一.问题的现象
程序崩溃的时候有时候会产生dump,或者弹出错误框“×××已停止工作”,这时候用windbg打开dump文件或者attach到进程,查看异常的线程,有时候线程的调用栈已经看不到,如何最大限度的手动恢复栈呢?我也曾经为了解决这个问题查了不少资料,现在也没找到完美的方法,限于自己的知识,只能尽力去恢复。
环境和工具主备
操作系统是windows server 2012(64)64,异常的程序是64位,使用的调试工具windbg也是64位。
三.问题追踪
首先,调用k命令,输出如下:
0:013> kChild-SP RetAddr Call Site00000000`3c98db18 00007ffc`749213ed ntdll!ZwWaitForMultipleObjects+0xa00000000`3c98db20 00007ffc`772c8241 KERNELBASE!WaitForMultipleObjectsEx+0xe100000000`3c98de00 00000000`00000000 KERNEL32!WerpReportFaultInternal+0x581
通过这个callstack,我们很难知道异常在哪。
接着,执行!teb指令,查看线程栈的起始位置,输出如下:
0:013> !tebTEB at 00007ff6df4ae000 ExceptionList: 0000000000000000 StackBase: 000000003c990000 StackLimit: 000000003c98d000 SubSystemTib: 0000000000000000 FiberData: 0000000000001e00 ArbitraryUserPointer: 0000000000000000 Self: 00007ff6df4ae000 EnvironmentPointer: 0000000000000000 ClientId: 000000000000148c . 0000000000001c08 RpcHandle: 0000000000000000 Tls Storage: 0000000000e9acd0 PEB Address: 00007ff6df5f6000 LastErrorValue: 0 LastStatusValue: c0000017 Count Owned Locks: 0 HardErrorMode: 0
找到线程栈的起始地址和结束地址后,执行命令:
dps 000000003c98d000 000000003c990000
输出的内容如下:
0:013> dps 000000003c98d000 000000003c99000000000000`3c98d000 00000000`0000000000000000`3c98d008 00000000`0000000000000000`3c98d010 00000000`0000000000000000`3c98d018 00007ffc`776bd702 ntdll!EtwEventWriteNoRegistration+0x92...00000000`3c98d0b8 00007ffc`7770be5a ntdll!WaitForWerSvc+0x8a00000000`3c98d0c0 00000000`0000000100000000`3c98d0c8 00007ffc`7770bf20 ntdll!WerpAllocateAndInitializeSid+0xac00000000`3c98d0d0 00000000`0000000000000000`3c98d0d8 00000000`0000000000000000`3c98d0e0 00000000`0048004600000000`3c98d0e8 00007ffc`776d8380 ntdll! ?? ::FNODOBFM::`string'00000000`3c98d0f0 00000000`0000100000000000`3c98d0f8 00007ffc`7770bfa9 ntdll!WerpFreeSid+0x41 ...00000000`3c98ec38 00007ffc`776d262a ntdll!KiUserExceptionDispatcher+0x3a ...
上面的内容输出很长,内容也很丰富,只列了一部分,执行下面的命令:
你看,这个问题是不是快解决了。至于具体的代码行数,可以根据图中最上面的栈帧,去dps的输出中去查找。
四.其他
在此崩溃的进程中,还有另外的线程也出现了异常,使用同样的方法,可恢复
0:008> !tebTEB at 00007ff6df4b8000 ExceptionList: 0000000000000000 StackBase: 00000000399c0000 StackLimit: 00000000399ba000 SubSystemTib: 0000000000000000 FiberData: 0000000000001e00 ArbitraryUserPointer: 0000000000000000 Self: 00007ff6df4b8000 EnvironmentPointer: 0000000000000000 ClientId: 000000000000148c . 0000000000001bf4 RpcHandle: 0000000000000000 Tls Storage: 0000000000e9a7f0 PEB Address: 00007ff6df5f6000 LastErrorValue: 8 LastStatusValue: c0000017 Count Owned Locks: 0 HardErrorMode: 00:008> dps 00000000399ba000 00000000399c000000000000399ba000 0000000000000000...00000000399bdc88 00007ffc776948d7 ntdll!RtlDispatchException+0x197...0:008> k L=00000000399bdc88
当然,使用上面的方法存在一定的运气成分,希望上面的方法对你有用。