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


    我们希望在WinDbg中自动显示、搜索和过滤std::map对象。std::vectors的脚本相对简单,因为vectors中数据的平面结构;map是更复杂的野兽。
    具体地说,Visual C++ STL中的映射是作为红黑树实现的。每个树节点都有三个重要的指针:左指针、右指针和父指针。此外,每个节点都有一个Myval字段,其中包含std::对以及节点表示的键和值。
    迭代树结构需要递归,WinDbg脚本没有任何语法来定义函数。但是,我们可以递归地调用脚本——允许脚本包含$$>a<命令,该命令使用不同的参数集再次调用脚本。脚本的路径也可以在${$arg0}中找到。
    当递归调用脚本时,伪寄存器的值(如$t0)将被递归调用破坏。当我偶然发现.push和.pop命令时,我正处于动态分配内存或调用shell进程来存储和加载变量的边缘,这两个命令分别存储和加载寄存器上下文。这些是递归WinDbg脚本必须的。
    好,假设您想显示std::map<int,point>中键小于或等于2的值。

    0:000> $$>a< traverse_map.script my_map -c ".block { .if (@@(@$t9.first) <= 2) { .echo —-; ?? @$t9.second } }"

    size = 10
    —-
    struct point
       +0x000 x                : 0n1
       +0x004 y                : 0n2
       +0x008 data             : extra_data
    —-
    struct point
       +0x000 x                : 0n0
       +0x004 y                : 0n1
       +0x008 data             : extra_data
    —-
    struct point
       +0x000 x                : 0n2
       +0x004 y                : 0n3
       +0x008 data             : extra_data

    对于每个pair(存储在$t9伪寄存器中),块检查第一个组件是否小于或等于2,如果小于或等于2,则输出第二个组件。
    接下来是剧本。注意,它比我们对向量的处理要复杂得多,因为它本质上是用一组不同的参数调用自己,然后递归地重复。

    .if ($sicmp("${$arg1}", "-n") == 0) {
        .if (@@(@$t0->_Isnil) == 0) {
            .if (@$t2 == 1) {
                .printf /D "<exec cmd="db %p L10">%p</exec> ", @$t0, @$t0
                .printf "key = "
                ?? @$t0->_Myval.first
                .printf "value = "
                ?? @$t0->_Myval.second
            } .else {
                r? $t9 = @$t0->_Myval
                command
            }
        }

        $$ Recurse into _Left, _Right unless they point to the root of the tree
        .if (@@(@$t0->_Left) != @@(@$t1)) {
            .push /r /q
            r? $t0 = @$t0->_Left
            $$>a< ${$arg0} -n
            .pop /r /q
        }
        .if (@@(@$t0->_Right) != @@(@$t1)) {
            .push /r /q
            r? $t0 = @$t0->_Right
            $$>a< ${$arg0} -n
            .pop /r /q
        }
    } .else {
        r? $t0 = ${$arg1}

        .if (${/d:$arg2}) {
            .if ($sicmp("${$arg2}", "-c") == 0) {
                r $t2 = 0
                aS ${/v:command} "${$arg3}"
            }
        } .else {
            r $t2 = 1
            aS ${/v:command} " "
        }

        .printf "size = %d ", @@(@$t0._Mysize) 
        
        r? $t0 = @$t0._Myhead->_Parent
        r? $t1 = @$t0->_Parent

        $$>a< ${$arg0} -n

        ad command
    }

    特别值得注意的是,as命令配置了一个别名,然后递归调用使用该别名为映射的每个元素调用一个命令块;比较字符串的$sicmp函数;以及输出DML块的.printf/D函数。最后,当_Left或_Right等于树的根时,递归终止(在本例中就是这样实现树的)。

  • 相关阅读:
    EF6的DbContext动态连接字符串
    Swagger配置
    Xamarin学习资源收集
    xmarin开发问题收集
    javascript基础
    Vue3.0到底带来来哪些变化视频笔记1
    Git操作
    EFCore 通过数据库生成模型
    Web Deploy远程发布
    ASP.NET CORE系列【七】分析NetCore启动原理
  • 原文地址:https://www.cnblogs.com/yilang/p/12012232.html
Copyright © 2020-2023  润新知