Windbg脚本 - STL映射,在命令输出中显示有限的输出

时间:2018-04-12 13:27:03

标签: dictionary scripting stl windbg

我已经使用Windbg几个月了,最后决定写一个脚本。我的目的是绕过STL地图的节点并显示键/值对。我已经到了输出我发现的东西的地步,但我的简单问题是我是否可以解析输出以使其更清晰,因为当我转储_Myval.first._Bx时,它被许多无关的信息所包围_Myval.second._Bx通过?? - 我喜欢就是让我感兴趣的东西,如果可能的话。

例如,当我这样做时,不要看到这个:

.printf "\nTREE MAP NODE: %p\n", @$t0 .printf " KEY = " ?? @$t0->_Myval.first._Bx

TREE MAP NODE: 00000010bc1f2cb0 KEY = union std::_String_val<char,std::allocator<char> >::_Bxty +0x000 _Buf : [16] "Connections" +0x000 _Ptr : 0x00004c5353657355 "--- memory read error at address 0x00004c5353657355 ---" +0x000 _Alias : [16] "Connections"

我想看到这个:

TREE MAP NODE: 00000010bc1f2cb0 KEY = "Connections"

所以我最终可能会这样显示:

TREE MAP NODE: 00000010bc1f2cb0 KEY = "Connections" VALUE = "10" TREE MAP NODE: 00000010bc1f2cc0 KEY = "StartupTask" VALUE = "TestTask" TREE MAP NODE: 00000010bc1f2cd0 KEY = "Location" VALUE = "UK"

我知道我可以使用??来查看某个节点_Myval.first,其中显示了其中包含的内容的大小,例如0xb我甚至可以通过_Myval.first._Mysize返回unsigned int64 0xb来解决这个问题,但是我可以对内容做同样的事情吗?

这可能是我缺乏经验,但如果我尝试在_Myval.first._Bx._Buf中显示什么,那么我只是得到一个地址并返回第一个字符,例如'C' ...所以,我的问题就是这个 - 因为我知道 我想要的东西,我知道 long < / em>它是(如果我需要知道这一点) - 那么我怎样才能显示那个......而不是当前带有_Bx_Buf_Ptr的整个_Alias Application.CutCopyRange

1 个答案:

答案 0 :(得分:1)

如下所示是在windbg中播放STL模板显示的几个例子

尝试新的dx表达式求值程序,它向下钻取到最后一个成员并且相当打印

如果您使用最新的windbg版本而不是windbgs本机脚本,也可以使用javascript

假设一个私有pdb代码正在调试

如果在函数上初始化地图后完成 dv 如果迭代器可用,可以直接使用

0:000> ?? iter._Ptr->_Myval.second
char * 0x000341a0
 "Alpha"

如果想要以粗体显示printf

.printf /D "contents of iter_.second is <b>%ma</b>\n" , @@c++(iter._Ptr->_Myval.second)
contents of iter_.second is Alpha

如果想要枚举地图中的每一对,则必须枚举父左右分支

0:000> ?? mymap._Mypair._Myval2._Myval2._Myhead->_Parent->_Myval
struct std::pair<char const ,char const *>
   +0x000 first            : -120 '' (eax)
   +0x004 second           : 0x000341a8  "Beta"
0:000> ?? mymap._Mypair._Myval2._Myval2._Myhead->_Left->_Myval
struct std::pair<char const ,char const *>
   +0x000 first            : -120 '' (eax)
   +0x004 second           : 0x000341a0  "Alpha"
0:000> ?? mymap._Mypair._Myval2._Myval2._Myhead->_Right->_Myval
struct std::pair<char const ,char const *>
   +0x000 first            : -120 '' (eax)
   +0x004 second           : 0x000341c0  "Epsilon"

如果需要打印右分支(地图中的最后一个成员)

.printf "the last memeber in map is %ma\n" , @@c++(mymap._Mypair._Myval2._Myval2._Myhead->_Right->_Myval.second)
the last memeber in map is Epsilon

使用最新的dx表达式评估器来打印几乎所有内容

0:000> dx mymap
mymap                 : { size=0x5 } [Type: std::map<char,char const *,std::less<char>,std::allocator<std::pair<char const ,char const *> > >]
    [<Raw View>]     [Type: std::map<char,char const *,std::less<char>,std::allocator<std::pair<char const ,char const *> > >]
    [comparator]     : less [Type: std::_Compressed_pair<std::less<char>,std::_Compressed_pair<std::allocator<std::_Tree_node<std::pair<char const ,char const *>,void *> >,std::_Tree_val<std::_Tree_simple_types<std::pair<char const ,char const *> > >,1>,1>]
    [allocator]      : allocator [Type: std::_Compressed_pair<std::allocator<std::_Tree_node<std::pair<char const ,char const *>,void *> >,std::_Tree_val<std::_Tree_simple_types<std::pair<char const ,char const *> > >,1>]
    [0x0]            : 65 'A', "Alpha" [Type: std::pair<char const ,char const *>]
    [0x1]            : 66 'B', "Beta" [Type: std::pair<char const ,char const *>]
    [0x2]            : 67 'C', "Gamma" [Type: std::pair<char const ,char const *>]
    [0x3]            : 68 'D', "Delta" [Type: std::pair<char const ,char const *>]
    [0x4]            : 69 'E', "Epsilon" [Type: std::pair<char const ,char const *>]

使用dx表达式求值程序可以将任何地址转换为地图,如此

dx @$myvar = ((stdmap!std::map<char,char const *,std::less<char>,std::allocator<std::pair<char const ,char const *> > > * ) 0x17fb90)

演员表演后 一个人可以像这样使用它

0:000> .for (r $t0 = 0 ; @$t0 < 5 ; r $t0 = @$t0+1) { dx @$myvar[0][@$t0].second }
@$myvar[0][@$t0].second                  : 0x341a0 : "Alpha" [Type: char *]
@$myvar[0][@$t0].second                  : 0x341a8 : "Beta" [Type: char *]
@$myvar[0][@$t0].second                  : 0x341b0 : "Gamma" [Type: char *]
@$myvar[0][@$t0].second                  : 0x341b8 : "Delta" [Type: char *]
@$myvar[0][@$t0].second                  : 0x341c0 : "Epsilon" [Type: char *]

_Bx等属于std :: string而不是映射

打印std :: string

0:000> .printf "%ma\n" , @@c++(test._Mypair._Myval2._Bx._Ptr)

Hello I am Me Are You Thou

_Bx是工会使用适当的成员

0:000> ?? test._Mypair._Myval2._Bx._Buf
char [16] 0x0013f888
96 '`'
0:000> ?? test._Mypair._Myval2._Bx._Ptr
char * 0x001a9860
 ".Hello I am Me Are You Thou."
0:000> ?? test._Mypair._Myval2._Bx._Alias
char [16] 0x0013f888
96 '

或将其转换为适合打印的类型

0:000> ?? (char *)*(unsigned long *)test._Mypair._Myval2._Bx._Buf
char * 0x001a9860
 ".Hello I am Me Are You Thou."

或者这里是适用于_Buf的printf变体,其中包含_Ptr

0:000> .printf "%ma\n" , @@c++( *(char **)(test._Mypair._Myval2._Bx._Buf) )

Hello I am Me Are You Thou

如果有人想跟进 用于显示这些结果的代码如下

using namespace std;
#define ALLOCSIZ 5
const char *Greek_Alphabets[ALLOCSIZ] = { "Alpha","Beta","Gamma","Delta","Epsilon" };

__declspec(noinline) void  play_with_map() {
    cout << "playing with maps\n\n";
    map<char, const char*> mymap;
    for (int i = 0; i < ALLOCSIZ; i++) {
        mymap.insert(pair<char, const char*>('A' + i, Greek_Alphabets[i]));
    }
    map<char, const char*>::iterator iter = mymap.begin();
    for (iter; iter != mymap.end(); iter++)
        cout << iter->first << " = " << iter->second << "\n";
}
__declspec(noinline) void play_with_vector(){
    cout << "playing with vectors\n\n";
    vector< pair< char, const char* > > myvec;
    for (int i = 0; i < ALLOCSIZ; i++) {
        myvec.push_back(make_pair('A' + i, Greek_Alphabets[i]));
    }
    for (int i = 0; i < ALLOCSIZ; i++) {
        cout << myvec[i].first << " = "<< myvec[i].second <<"\n";
    }
}
int main() {
    play_with_map();
    play_with_vector();
    return 0;
}

std :: string函数如下

__declspec(noinline) void play_with_std_string() {
    string test("\nHello I am Me Are You Thou\n");
    cout << test.c_str();
}

JAVASCRIPT

转储std :: map map&lt; char,const char *&gt;的示例Javascript MyMap中

"use strict";

// make an alias so that it can be used like regular bang command !dumpmap address
function initializeScript() {
    return [new host.functionAlias(dump_std_map, "dumpmap")];
}

// a helper to log strings
function log(instr) {
    host.diagnostics.debugLog(instr + "\n")
}

//use dt /v /t std::map* to get a type description string and pass it 
// or use the default (applicable for this example only 
// std::map< int , int > will not pan for  std::map <bar , foo > 
function dump_std_map(input , typedesc) {
    var typeDescription;
    if(typedesc) {
        typeDescription = typedesc 
        }else {
            typeDescription = "(std::map<char,char const *,std::less<char>,std::allocator<std::pair<char const ,char const *> > > *)"
        }   
    var foo = host.evaluateExpression( typeDescription + input.toString() )
    var mapsize = foo._Mypair._Myval2._Myval2._Mysize
    for (var i=0; i<mapsize;i++) 
    {
        log (foo.dereference().Skip(i).First().toString())
    }
}

并像

一样使用它
0:000> ? mymap
Evaluate expression: 2357904 = 0023fa90
0:000> !dumpmap 0x23fa90
65 'A', "Alpha"
66 'B', "Beta"
67 'C', "Gamma"
68 'D', "Delta"
69 'E', "Epsilon"
@$dumpmap(0x23fa90)