有时,您会查看异常抛出后处理程序中的调用堆栈。如果附加到弹出watson对话框的未处理异常,这是非常常见的。
它可能看起来像:
kernel32!WaitForSingleObject+0xf
devenv!DwCreateProcess+0xbb
devenv!fExceptionHandling+0x1cb
devenv!DwExceptionFilter+0x8b
0x535ef48
那没什么用。您真正想要的是查看抛出异常时的调用堆栈。在x86上执行此操作有一个技巧。(这可以调整为在64位平台上工作。)
它可以在实时调试和小型转储中工作,甚至在没有任何符号的情况下也可以工作。我将首先给出如何做到这一点的快速步骤,然后我将解释它的工作原理。
我怎么找到它?
使用这些Windbg指令,但是任何带有内存搜索(‘s‘)和set context(‘.cxr‘)命令的本机调试器也可以执行此操作。
现在应该多检查一下你的调用堆栈。在我的示例中,它看起来像:
mscordbi!CordbHashTable::GetBase
mscordbi!CordbThread::RefreshStack+0x349
mscordbi!CordbProcess::DispatchRCEvent+0x1291
mscordbi!CordbRCEventThread::ThreadProc+0x9
eax=00000000 ebx=04700168 ecx=00000048 edx=0535f230 esi=00000000 edi=0535f254
eip=636ac786 esp=0535f214 ebp=0535f228 iopl=0 nv up ei pl zr na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00210246
mscordbi!CordbHashTable::GetBase:
636ac786 80791400 cmp byte ptr [ecx+0x14],0x0 ds:0023:0000005c=??
我的程序正在取消引用0x5c(=0x48+0x14)。难怪它坠毁了。
请注意,我们不需要为原始堆栈上的任何模块添加任何符号来找到它。即使我们根本没有任何符号,我们仍然可以对崩溃的代码进行反汇编。
为什么有用?
这里有一些关键数据。
1) 当操作系统抛出异常时,它将原始抛出站点的上下文推送到堆栈上。(这是异常指针的一部分)。
2) 在x86上,上下文结构中的第一个字段是一个标志字段,它总是设置为0x1003f。由于其他原因,此值不太可能随机出现在堆栈顶部。
3) 在x86上,堆栈增长。因此,当前堆栈指针(esp)表示0x1003f将出现的范围的高端。因此,如果我们要搜索接近堆栈顶部的内容(0x1000字节以内),我们可以在范围内(esp,esp-0x1000)进行搜索。
4) 搜索dw的内存。格式为“s–d<范围><值>”。<range>的格式可以是“<address>L<length>”,它将搜索范围(address,address length)中的“value”。因此,“s-d esp L1000 1003f”意味着“搜索范围内的dword 0x1003f(esp,esp-0x1000)”。0x1000是一个任意的数字,在这里似乎足够了。
5) 调试器可以从任何上下文执行stackwalk。大多数调试器只是自动使用线程的当前上下文(通过kernel32!GetThreadContext),但调试器没有理由不能使用任意上下文。Windbg提供了一个很好的命令,“.cxr”,它可以让您这样做。可以设置要检查的上下文。(VS也在添加此命令)。
对于kicks,检查我们提供给.cxr的上下文指针,您可以自己看到它与register命令的输出相匹配:
0:015> dt _CONTEXT 0535ef48
+0x000 ContextFlags : 0x1003f
+0x004 Dr0 : 0
+0x008 Dr1 : 0
+0x00c Dr2 : 0
+0x010 Dr3 : 0
+0x014 Dr6 : 0
+0x018 Dr7 : 0
+0x01c FloatSave : _FLOATING_SAVE_AREA
+0x08c SegGs : 0
+0x090 SegFs : 0x3b
+0x094 SegEs : 0x23
+0x098 SegDs : 0x23
+0x09c Edi : 0x535f254
+0x0a0 Esi : 0
+0x0a4 Ebx : 0x4700168
+0x0a8 Edx : 0x535f230
+0x0ac Ecx : 0x48
+0x0b0 Eax : 0
+0x0b4 Ebp : 0x535f228
+0x0b8 Eip : 0x636ac786
+0x0bc SegCs : 0x1b
+0x0c0 EFlags : 0x210246
+0x0c4 Esp : 0x535f214
+0x0c8 SegSs : 0x23
+0x0cc ExtendedRegisters : [512] "???"
0:015> r
Last set context:
eax=00000000 ebx=04700168 ecx=00000048 edx=0535f230 esi=00000000 edi=0535f254
eip=636ac786 esp=0535f214 ebp=0535f228 iopl=0 nv up ei pl zr na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00210246
这主要适用于本机异常;但也适用于托管异常+SOS。
从经验上讲,我已经使用这种技术很长时间了,而且每次都非常有效。我还没有找到一个值为0x1003f的杂散局部。
原文:https://www.cnblogs.com/yilang/p/13906051.html