好吧,函数作用域的静态变量instance 不会出现在.map 由cl.exe /Fm 生成的文件中,而且当我在WinDbg 中使用x programname!*MyClass* 时它也不会出现,所以损坏的name 似乎根本不包含 MyClass。
方案一:反汇编MyClass::getInstance
这种方法似乎更容易:
0:000> uf 程序名!MyClass::getInstance
程序名!MyClass::getInstance [程序名.cpp @ 14]:
14 00401050 55 推 ebp
14 00401051 8bec 移动 ebp,esp
15 00401053 a160b34200 mov eax,dword ptr [程序名!$S1 (0042b360)]
15 00401058 83e001 和 eax,1
15 0040105b 7526 jne funcstat!MyClass::getInstance+0x33 (00401083)
程序名!MyClass::getInstance+0xd [程序名.cpp @ 15]:
15 0040105d 8b0d60b34200 mov ecx,dword ptr [程序名!$S1 (0042b360)]
15 00401063 83c901 或 ecx,1
15 00401066 890d60b34200 mov dword ptr [程序名!$S1 (0042b360)],ecx
15 0040106c b9b0be4200 mov ecx,偏移程序名!实例(0042beb0)
15 00401071 e88fffffff 调用程序名!ILT+0(??0MyClassQAEXZ) (00401005)
15 00401076 68e03e4200 推送偏移程序名!`MyClass::getInstance'::`2'::`'instance' (00423ee0) 的动态 atexit 析构函数
15 0040107b e8f3010000 调用程序名!atexit (00401273)
15 00401080 83c404 添加 esp,4
程序名!MyClass::getInstance+0x33 [程序名.cpp @ 16]:
16 00401083 b8b0be4200 mov eax,偏移程序名!实例(0042beb0)
17 00401088 5d 弹出 ebp
17 00401089 C3 RET
由此我们可以看出编译器调用了对象$S1。当然,这个名字将取决于你的程序有多少函数范围的静态变量。
选项 2:在内存中搜索对象
进一步扩展@gbjbaanb 的建议,如果MyClass 具有虚函数,您可能很难找到它的位置:
- 对进程进行完整的内存转储。
- 将完整的内存转储加载到 WinDbg。
- 使用
x命令查找MyClass的vtable地址:
0:000> x 程序名!MyClass::`vftable'
00425c64 程序名!MyClass::`vftable' =
- 使用
s 命令在进程的虚拟地址空间(本例中为 0-2GB)中搜索指向 MyClass 的 vtable 的指针:
0:000> s -d 0 L?7fffffff 00425c64
004010dc 00425c64 c35de58b cccccccc cccccccc d\B...].........
0040113c 00425c64 8bfc458b ccc35de5 cccccccc d\B..E...]......
0042b360 00425c64 00000000 00000000 00000000 分贝......
- 使用
dt 命令查找类的vtable 偏移量,然后从搜索返回的地址中减去该偏移量。这些是对象的可能地址。
0:000> dt 程序名!MyClass
+0x000 __VFN_table : Ptr32
+0x008 x : Int4B
+0x010 y : 浮动
- 使用
dt programname!MyClass 0042b360 检查对象的成员变量,检验对象位于0042b360(或其他地址)的假设。正如我在上面所做的那样,您可能会得到一些误报,但是通过检查成员变量,您可能能够找出哪个是您的单例。
这是一种查找 C++ 对象的通用技术,当您可以反汇编 MyClass::getInstance 时,这有点过头了。