Displaying and Searching std::vector Contents in WinDbg

July 18, 2013

tags: , ,
one comment

WinDbg has never been very good at visualization. While Visual Studio has always had autoexp.dat, and as of late also native debugger visualizers, WinDbg users had to settle for dumping memory areas and searching memory to identify patterns.

On the other hand, Visual Studio does not offer any automation opportunities today if you’re looking to simplify your debugging process. You can’t write macros anymore as of Visual Studio 2012. WinDbg continues to offer scripting support so you can automate any mundane debugging tasks you encounter. If you make it past the initial learning curve and master WinDbg scripts, you can almost guarantee better and faster results than your colleagues who traverse objects by hand in Visual Studio.

There are some decent tutorials online that can guide you through the basics of WinDbg scripting, and the built-in documentation (debugger.chm) has some nice scenarios as well. In this post, I’d like to show you a simple script that searches std::vector instances for objects that match a specific criterion, and then displays them.

Here’s how you could use this script. Suppose you have a vector of complex objects of type point. The point type, in turn, has a field data, which has a field called z of type int. You’re looking for points whose data.z field is equal to 0. Here you go:

0:000> $$>a< traverse_vector.script my_points ".block { .if (@@(@$t0->data.z) == 0) { ?? @$t0 } }"

struct point * 0x0129e4d0
   +0×000 x                : 0n0
   +0×004 y                : 0n0
   +0×008 data             : extra_data

The script passes the $t0 pseudo-register to the command block for each element of the vector. In the above command block, the .if statement evaluates the provided expression as a C++ expression (the @@ operator forces the C++ expression evaluator), and, if it is true, displays the current element by using the ?? operator. The ?? operator simply displays a C++ expression.

Here’s the script with some comments:

$$ save pointer to first element (current element)
r? $t0=${$arg1}._Myfirst

$$ save pointer to last element
r? $t1=${$arg1}._Mylast

$$ save first forever
r? $t2=@$t0

.while (@$t0 != @$t1)
{
    .if (${/d:$arg2} == 0) {
        $$ display element, no command provided
        .printf "index %d, address %p\n", @@(@$t0 – @$t2), @$t2
        ?? @$t0
    } .else {
        ${$arg2}
    }

    $$ advance current element
    r? $t0=@$t0 + 1
}

The initial challenge is just getting through all the vector elements. This relies on the fact that vectors have _Myfirst and _Mylast members. Once that’s done, you can run arbitrary commands on the vector contents, print the elements, filter them, store them in a file, and so on.


I am posting short links and updates on Twitter as well as on this blog. You can follow me: @goldshtn

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

one comment

  1. Marc ShermanJuly 19, 2013 ב 10:50 AM

    Is my_points a global std::vector?

    thanks

    Reply