如何从转储和符号文件中获取变量名?
How to get variable names out of a dump and a symbol file?
我正在调试转储文件,同时我可以访问符号文件。
我正在使用一个脚本,它结合了以下 windbg
命令的结果:
x /2 *!* // which types are present in the symbol files?
!heap -h 0 // which memory address ranges are used in the dump?
(至少我是这么理解的,如有不妥欢迎指正)
脚本(称为 heap_stat.py
,在 this list of Windbg extensions 下找到)的结果是一个内存地址列表,后面是它们的类型。通过对这些进行统计,我可以得出是否存在内存泄漏。
最重要的是,使用提到的内存地址的 WinDbg 命令 dt CStringArray m_nSize
(当然,在 CStringArray
的特定情况下),我可以看到条目的总数使用过的 CStringArray
个对象,并查看是否有 CStringArray
个包含大量条目的对象。
但是这个系统有一个缺点:
当我发现这样一个包含很多条目的 CStringArray
对象时,我被困在那里,因为在我的应用程序中的所有 CStringArray
对象中,我不知道我正在处理哪个。
可能有帮助的一件事是内存地址所在的局部变量的名称,但有一个问题:我不知道是否存在此信息,如果存在,我能否在符号中找到它文件或转储中,并且(显然)我需要 运行 哪个命令才能获取此信息(我没有找到使 dt <flag> <memory address>
return 成为局部变量的标志名称,被 <memory address>
)?
占用
有人可以帮我吗?
为了清楚起见,这是我的脚本当前的结果:
0x0065a4d0 mfc110u!CStringArray Size:[1]
0x0065a4e4 mfc110u!CStringArray Size:[0]
0x0065a4f8 mfc110u!CStringArray Size:[295926]
0x0065a520 mfc110u!CStringArray Size:[0]
如你所见,我可以看到我的变量存储的内存地址,我可以看到类型(从符号文件中检索),我可以看到条目的数量(从 dt
Windbg
命令),但我想要如下输出:
0x0065a4d0 mfc110u!CStringArray Size:[1] var1
0x0065a4e4 mfc110u!CStringArray Size:[0] var2
0x0065a4f8 mfc110u!CStringArray Size:[295926] var3
0x0065a520 mfc110u!CStringArray Size:[0] var3
或:
0x0065a4d0 mfc110u!CStringArray Size:[1] obj1.prop1
0x0065a4e4 mfc110u!CStringArray Size:[0] obj2.prop1
0x0065a4f8 mfc110u!CStringArray Size:[295926] obj1.prop2
0x0065a520 mfc110u!CStringArray Size:[0] obj1.prop2
这样的输出表明我需要验证源代码中的 var3
或 obj1.prop2
发生了什么。
我写了下面的MFC应用程序(部分源码):
CStringArray stringarray;
void* anotherarray = new CStringArray();
void CLocalVariableNameApp::AnotherMethod(void* a)
{
CStringArray* temp = static_cast<CStringArray*>(a);
temp->Add(L"Something else");
}
CLocalVariableNameApp::CLocalVariableNameApp()
{
stringarray.Add(L"Something");
AnotherMethod(anotherarray);
CStringArray* holycow = static_cast<CStringArray*>(anotherarray);
holycow->Add(L"Yet something else");
DebugBreak();
}
如您所见,第二个 CStringArray 有多个名称:anotherarray
、a
、temp
和 holycow
.
观察 1:1:1 内存地址和变量名的映射并不容易。
局部变量名称可从 PDB 文件中获得:
0:000> k
# ChildEBP RetAddr
00 0022fa40 00fa2a30 KERNELBASE!DebugBreak+0x2
01 0022fb3c 00f97958 LocalVariableName!CLocalVariableNameApp::CLocalVariableNameApp+0x90 [c:\...\localvariablename.cpp @ 38]
02 0022fc10 014b628a LocalVariableName!`dynamic initializer for 'theApp''+0x28 [c:\...\localvariablename.cpp @ 43]
03 0022fc18 014b5e8c LocalVariableName!_initterm+0x1a [f:\...\crt0dat.c @ 955]
04 0022fc2c 014a9263 LocalVariableName!_cinit+0x6c [f:\...\crt0dat.c @ 308]
05 0022fc78 014a947d LocalVariableName!__tmainCRTStartup+0xf3 [f:\...\crt0.c @ 237]
06 0022fc80 7558336a LocalVariableName!wWinMainCRTStartup+0xd [f:\...\crt0.c @ 165]
07 0022fc8c 771198f2 kernel32!BaseThreadInitThunk+0xe
08 0022fccc 771198c5 ntdll!__RtlUserThreadStart+0x70
09 0022fce4 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> .frame 1
01 0022fb3c 00f97958 LocalVariableName!CLocalVariableNameApp::CLocalVariableNameApp+0x90 [c:\...\localvariablename.cpp @ 38]
0:000> dv
this = 0x01637118
holycow = 0x00445820
请注意,名称 a
和 temp
不可见。
观察2:变量名将被限制在它们的范围内。如果你想记住所有的变量名,你需要跟踪所有的函数。
以上是调试版本。发布版本不同:
0:000> k
# ChildEBP RetAddr
00 005efe04 002a1c18 KERNELBASE!DebugBreak+0x2
01 005efe20 002a1095 LocalVariableName!CLocalVariableNameApp::CLocalVariableNameApp+0x88 [c:\...\localvariablename.cpp @ 39]
02 005efe24 003c0289 LocalVariableName!`dynamic initializer for 'theApp''+0x5 [c:\...\localvariablename.cpp @ 43]
03 005efe38 003c01ea LocalVariableName!_initterm+0x29 [f:\...\crt0dat.c @ 954]
04 005efe48 003bd280 LocalVariableName!_cinit+0x5a [f:\...\crt0dat.c @ 321]
05 005efe88 7558336a LocalVariableName!__tmainCRTStartup+0xde [f:\...\crt0.c @ 237]
06 005efe94 771198f2 kernel32!BaseThreadInitThunk+0xe
07 005efed4 771198c5 ntdll!__RtlUserThreadStart+0x70
08 005efeec 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> .frame 1
01 005efe20 002a1095 LocalVariableName!CLocalVariableNameApp::CLocalVariableNameApp+0x88 [c:\...\localvariablename.cpp @ 39]
0:000> dv
this = 0x0043f420
请注意缺少 holycow
。
观察 3:在发布版本中,可能不需要(优化)变量,因此不存在。
总体结论:无法将内存地址映射到变量名。
我正在调试转储文件,同时我可以访问符号文件。
我正在使用一个脚本,它结合了以下 windbg
命令的结果:
x /2 *!* // which types are present in the symbol files?
!heap -h 0 // which memory address ranges are used in the dump?
(至少我是这么理解的,如有不妥欢迎指正)
脚本(称为 heap_stat.py
,在 this list of Windbg extensions 下找到)的结果是一个内存地址列表,后面是它们的类型。通过对这些进行统计,我可以得出是否存在内存泄漏。
最重要的是,使用提到的内存地址的 WinDbg 命令 dt CStringArray m_nSize
(当然,在 CStringArray
的特定情况下),我可以看到条目的总数使用过的 CStringArray
个对象,并查看是否有 CStringArray
个包含大量条目的对象。
但是这个系统有一个缺点:
当我发现这样一个包含很多条目的 CStringArray
对象时,我被困在那里,因为在我的应用程序中的所有 CStringArray
对象中,我不知道我正在处理哪个。
可能有帮助的一件事是内存地址所在的局部变量的名称,但有一个问题:我不知道是否存在此信息,如果存在,我能否在符号中找到它文件或转储中,并且(显然)我需要 运行 哪个命令才能获取此信息(我没有找到使 dt <flag> <memory address>
return 成为局部变量的标志名称,被 <memory address>
)?
有人可以帮我吗?
为了清楚起见,这是我的脚本当前的结果:
0x0065a4d0 mfc110u!CStringArray Size:[1]
0x0065a4e4 mfc110u!CStringArray Size:[0]
0x0065a4f8 mfc110u!CStringArray Size:[295926]
0x0065a520 mfc110u!CStringArray Size:[0]
如你所见,我可以看到我的变量存储的内存地址,我可以看到类型(从符号文件中检索),我可以看到条目的数量(从 dt
Windbg
命令),但我想要如下输出:
0x0065a4d0 mfc110u!CStringArray Size:[1] var1
0x0065a4e4 mfc110u!CStringArray Size:[0] var2
0x0065a4f8 mfc110u!CStringArray Size:[295926] var3
0x0065a520 mfc110u!CStringArray Size:[0] var3
或:
0x0065a4d0 mfc110u!CStringArray Size:[1] obj1.prop1
0x0065a4e4 mfc110u!CStringArray Size:[0] obj2.prop1
0x0065a4f8 mfc110u!CStringArray Size:[295926] obj1.prop2
0x0065a520 mfc110u!CStringArray Size:[0] obj1.prop2
这样的输出表明我需要验证源代码中的 var3
或 obj1.prop2
发生了什么。
我写了下面的MFC应用程序(部分源码):
CStringArray stringarray;
void* anotherarray = new CStringArray();
void CLocalVariableNameApp::AnotherMethod(void* a)
{
CStringArray* temp = static_cast<CStringArray*>(a);
temp->Add(L"Something else");
}
CLocalVariableNameApp::CLocalVariableNameApp()
{
stringarray.Add(L"Something");
AnotherMethod(anotherarray);
CStringArray* holycow = static_cast<CStringArray*>(anotherarray);
holycow->Add(L"Yet something else");
DebugBreak();
}
如您所见,第二个 CStringArray 有多个名称:anotherarray
、a
、temp
和 holycow
.
观察 1:1:1 内存地址和变量名的映射并不容易。
局部变量名称可从 PDB 文件中获得:
0:000> k
# ChildEBP RetAddr
00 0022fa40 00fa2a30 KERNELBASE!DebugBreak+0x2
01 0022fb3c 00f97958 LocalVariableName!CLocalVariableNameApp::CLocalVariableNameApp+0x90 [c:\...\localvariablename.cpp @ 38]
02 0022fc10 014b628a LocalVariableName!`dynamic initializer for 'theApp''+0x28 [c:\...\localvariablename.cpp @ 43]
03 0022fc18 014b5e8c LocalVariableName!_initterm+0x1a [f:\...\crt0dat.c @ 955]
04 0022fc2c 014a9263 LocalVariableName!_cinit+0x6c [f:\...\crt0dat.c @ 308]
05 0022fc78 014a947d LocalVariableName!__tmainCRTStartup+0xf3 [f:\...\crt0.c @ 237]
06 0022fc80 7558336a LocalVariableName!wWinMainCRTStartup+0xd [f:\...\crt0.c @ 165]
07 0022fc8c 771198f2 kernel32!BaseThreadInitThunk+0xe
08 0022fccc 771198c5 ntdll!__RtlUserThreadStart+0x70
09 0022fce4 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> .frame 1
01 0022fb3c 00f97958 LocalVariableName!CLocalVariableNameApp::CLocalVariableNameApp+0x90 [c:\...\localvariablename.cpp @ 38]
0:000> dv
this = 0x01637118
holycow = 0x00445820
请注意,名称 a
和 temp
不可见。
观察2:变量名将被限制在它们的范围内。如果你想记住所有的变量名,你需要跟踪所有的函数。
以上是调试版本。发布版本不同:
0:000> k
# ChildEBP RetAddr
00 005efe04 002a1c18 KERNELBASE!DebugBreak+0x2
01 005efe20 002a1095 LocalVariableName!CLocalVariableNameApp::CLocalVariableNameApp+0x88 [c:\...\localvariablename.cpp @ 39]
02 005efe24 003c0289 LocalVariableName!`dynamic initializer for 'theApp''+0x5 [c:\...\localvariablename.cpp @ 43]
03 005efe38 003c01ea LocalVariableName!_initterm+0x29 [f:\...\crt0dat.c @ 954]
04 005efe48 003bd280 LocalVariableName!_cinit+0x5a [f:\...\crt0dat.c @ 321]
05 005efe88 7558336a LocalVariableName!__tmainCRTStartup+0xde [f:\...\crt0.c @ 237]
06 005efe94 771198f2 kernel32!BaseThreadInitThunk+0xe
07 005efed4 771198c5 ntdll!__RtlUserThreadStart+0x70
08 005efeec 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> .frame 1
01 005efe20 002a1095 LocalVariableName!CLocalVariableNameApp::CLocalVariableNameApp+0x88 [c:\...\localvariablename.cpp @ 39]
0:000> dv
this = 0x0043f420
请注意缺少 holycow
。
观察 3:在发布版本中,可能不需要(优化)变量,因此不存在。
总体结论:无法将内存地址映射到变量名。