windbgwindbg-extension

Use WinDbg LINQ with C/C++ objects


I have an array of structs stores as pointer + length and would like to print a deep field of each.

I can do it using .for and temporary registers:

.for (r $t0 = 0; @$t0 < @@c++(length); r $t0 = @$t0 + 1) { dx pointer[@$t0].a.b.c }

Is there some nicer way to do it using dx expressions? I know they have some LINQ capabilities, because they are described at MSDN and I can for example run:

dx Debugger.Utility.FileSystem.CurrentDirectory.Files.Select(x => x.Extension)

I am looking for an equivalent code for C/C++ objects, something like:

dx array(pointer, length).Select(x => x.a.b.c)

Having to write a small JS extension which works genetically and can be invoked with arbitrary pointer, size and lambda would also be an acceptable answer.


Solution

  • The LINQ methods are projected onto anything which is iterable (either naturally like an array or via an attached data model (e.g.: NatVis, JS, etc...) which supports the iterable concept). The dx evaluator supports casting to array types. You can easily do something like:

    dx ((TYPE[SIZE])pointer).Select(...)

    For instance:

    0:000> dx ((int[5])@rip).Select(x => x < 0)
    ((int[5])@rip).Select(x => x < 0)                
        [0]              : false
        [1]              : true
        [2]              : true
        [3]              : false
        [4]              : false
    

    If you need to programmatically control the size (e.g.: it's not constant), you can write a short JavaScript function which does this. For example:

    "use strict";
    
    class __CollectionsExtension
    {
        PointerToArray(ptr, size)
        {
            if (ptr.targetType === undefined || ptr.targetType.typeKind != "pointer")
            {
                throw new Error("Invalid argument: must provide a pointer");
            }
    
            var baseType = ptr.targetType.baseType;
            return host.createTypedObject(ptr.address, baseType.createArrayOf([new host.typeSystem.arrayDimension(0, size, baseType.size)]));
        }
    }
    
    function initializeScript()
    {
        return [new host.apiVersionSupport(1, 9),
                new host.namedModelParent(__CollectionsExtension, "Debugger.Models.Utility.Collections")];
    }
    

    The above script will add a method called PointerToArray onto Debugger.Utility.Collections. You could then do something like:

    0:000> dx Debugger.Utility.Collections.PointerToArray((int *)@rip, @rax + 2)
    Debugger.Utility.Collections.PointerToArray((int *)@rip, @rax + 2)                 [Type: int [2]]
        [0]              : 1208019916 [Type: int]
        [1]              : -1019689853 [Type: int]
    

    Hope that helps...