在WinDbg中显示和搜索std::vector内容

时间:2023-12-28 09:54:32

WinDbg从来都不擅长可视化。尽管Visual Studio一直都有autoexp.dat,而且最近还出现了本机调试器可视化工具,但WinDbg用户不得不满足于转储内存区域和搜索内存来识别模式。
另一方面,如果希望简化调试过程,Visual Studio目前没有提供任何自动化机会。从Visual Studio 2012开始,不能再编写宏。WinDbg继续提供脚本支持,因此可以自动执行遇到的任何日常调试任务。如果通过了初始学习曲线并掌握了WinDbg脚本,几乎可以保证比在Visual Studio中手动遍历对象的同事获得更好更快的结果。
有一些不错的在线教程可以指导了解WinDbg脚本的基本知识,而且内置文档(debugger.chm)也有一些不错的场景。在这篇文章中,我想写一个简单的脚本,它搜索std::vector实例中匹配特定条件的对象,然后显示它们。
下面是如何使用这个脚本。假设有一个点类型的复杂对象向量。反过来,点类型有一个字段数据,该字段有一个类型为int的名为z的字段。正在查找其data.z字段等于0的点。如下:

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

struct point * 0x0129e4d0
   +0x000 x                : 0n0
   +0x004 y                : 0n0
   +0x008 data             : extra_data

脚本将$t0伪寄存器传递给向量的每个元素的命令块。在上面的命令块中,if语句将提供的表达式作为C++表达式求值(@ @运算符强制C++表达式求值器),如果它是真的,则使用“??”运算符来显示当前元素。这个??运算符只显示一个C++表达式。

以下是脚本和一些注释:

$$ 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
}

最初的挑战是如何处理所有的向量元素。这依赖于向量有Myfirst和Mylast成员这一事实。完成后,可以对向量内容运行任意命令、打印元素、筛选元素、将它们存储在文件中,等等。