好吧,函数范围的静态instance
变量不会出现在由.map
生成的文件中cl.exe /Fm
,并且在我在 WinDbg 中使用时也不会出现x programname!*MyClass*
,因此损坏的名称似乎根本不包含MyClass
。
选项 1:拆卸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
。