一. 问题的现象
程序崩溃的时候有时候会产生 dump,或者弹出错误框“×××已停止工作”,这时候用 windbg 打开 dump 文件或者 attach 到进程,查看异常的线程,有时候线程的调用栈已经看不到,如何最大限度的手动恢复栈呢?我也曾经为了解决这个问题查了不少资料,现在也没找到完美的方法,限于自己的知识,只能尽力去恢复。
环境和工具主备
操作系统是 windows server 2012(64)64,异常的程序是 64 位,使用的调试工具 windbg 也是 64 位。
三. 问题追踪
首先,调用 k 命令,输出如下:
0:013> k
Child-SP RetAddr Call Site
00000000`3c98db18 00007ffc`749213ed ntdll!ZwWaitForMultipleObjects+0xa
00000000`3c98db20 00007ffc`772c8241 KERNELBASE!WaitForMultipleObjectsEx+0xe1
00000000`3c98de00 00000000`00000000 KERNEL32!WerpReportFaultInternal+0x581
通过这个 callstack,我们很难知道异常在哪。
接着,执行!teb 指令,查看线程栈的起始位置,输出如下:
0:013> !teb
TEB 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 000000003c990000
00000000`3c98d000 00000000`00000000
00000000`3c98d008 00000000`00000000
00000000`3c98d010 00000000`00000000
00000000`3c98d018 00007ffc`776bd702 ntdll!EtwEventWriteNoRegistration+0x92
.
.
.
00000000`3c98d0b8 00007ffc`7770be5a ntdll!WaitForWerSvc+0x8a
00000000`3c98d0c0 00000000`00000001
00000000`3c98d0c8 00007ffc`7770bf20 ntdll!WerpAllocateAndInitializeSid+0xac
00000000`3c98d0d0 00000000`00000000
00000000`3c98d0d8 00000000`00000000
00000000`3c98d0e0 00000000`00480046
00000000`3c98d0e8 00007ffc`776d8380 ntdll! ?? ::FNODOBFM::`string'
00000000`3c98d0f0 00000000`00001000
00000000`3c98d0f8 00007ffc`7770bfa9 ntdll!WerpFreeSid+0x41
.
.
.
00000000`3c98ec38 00007ffc`776d262a ntdll!KiUserExceptionDispatcher+0x3a
.
.
.
上面的内容输出很长,内容也很丰富,只列了一部分,执行下面的命令:
你看,这个问题是不是快解决了。至于具体的代码行数,可以根据图中最上面的栈帧,去 dps 的输出中去查找。
四. 其他
在此崩溃的进程中,还有另外的线程也出现了异常,使用同样的方法,可恢复
0:008> !teb
TEB 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: 0
0:008> dps 00000000399ba000 00000000399c0000
00000000399ba000 0000000000000000
.
.
.
00000000399bdc88 00007ffc776948d7 ntdll!RtlDispatchException+0x197
.
.
.
0:008> k L=00000000399bdc88
当然,使用上面的方法存在一定的运气成分,希望上面的方法对你有用。