callstack的恢复

22次阅读

共计 2549 个字符,预计需要花费 7 分钟才能阅读完成。

一. 问题的现象

程序崩溃的时候有时候会产生 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


当然,使用上面的方法存在一定的运气成分,希望上面的方法对你有用。

正文完
 0