Windbg 脚本 - STL 映射,在命令输出中显示有限的输出
Windbg script - STL map, displaying limited output in command output
我已经使用 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
之类的东西来解决这个问题,但是我可以对 contents?[=28 做同样的事情吗? =]
这可能是我缺乏经验,但如果我尝试显示 _Myval.first._Bx._Buf
中的内容,那么我只会得到一个地址并返回第一个字符,例如'C'
... 所以,我的问题就是这样 - 据我所知 我想要的 thing 被举行了,我知道long 有多长(如果我需要知道这一点)-那么我怎么才能显示那个...而不是当前返回 [=25] 的整个 _Bx
=]、_Ptr
和 _Alias
?
下面是在windbg中玩转STL模板显示的几个例子
尝试新的 dx 表达式求值器,它深入到最后一个成员并漂亮地打印它
如果您使用的是最新的 windbg 版本而不是 windbgs 本机脚本,也可以使用 javascript
假设一个正在调试的代码有一个私有 pdb
if done dv 在函数初始化地图之后
如果迭代器可用,可以直接使用它
0:000> ?? iter._Ptr->_Myval.second
char * 0x000341a0
"Alpha"
如果想用粗体打印
.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
要转储的示例 Javascript std::map map 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)
我已经使用 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
之类的东西来解决这个问题,但是我可以对 contents?[=28 做同样的事情吗? =]
这可能是我缺乏经验,但如果我尝试显示 _Myval.first._Bx._Buf
中的内容,那么我只会得到一个地址并返回第一个字符,例如'C'
... 所以,我的问题就是这样 - 据我所知 我想要的 thing 被举行了,我知道long 有多长(如果我需要知道这一点)-那么我怎么才能显示那个...而不是当前返回 [=25] 的整个 _Bx
=]、_Ptr
和 _Alias
?
下面是在windbg中玩转STL模板显示的几个例子
尝试新的 dx 表达式求值器,它深入到最后一个成员并漂亮地打印它
如果您使用的是最新的 windbg 版本而不是 windbgs 本机脚本,也可以使用 javascript
假设一个正在调试的代码有一个私有 pdb
if done dv 在函数初始化地图之后 如果迭代器可用,可以直接使用它
0:000> ?? iter._Ptr->_Myval.second
char * 0x000341a0
"Alpha"
如果想用粗体打印
.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
要转储的示例 Javascript std::map map
"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)