dump 分析模式之 INCORRECT STACK TRACE - djm2005dy的專欄 - 博客頻道 - CSDN.NET

dump 分析模式之 INCORRECT STACK TRACE 翻譯自 MDA-Anthology Page288  

初學者常犯的錯誤是認爲 WinDbg 的 !analyze 和 kv 給出的信息是準確的.  

WinDbg 只是一個工具, 有時候會缺乏一些必要的信息來獲得正確的棧信息, 所以咱們須要本身明辨正確的與錯誤的棧信息. 我稱之爲 Incorrect Stack Trace, 它一般有如下特徵:  
  • WinDbg給出警告: "Following frames may be wrong"
  • 棧底函數不是 kernel32!BaseThreadStart (用戶模式)
  • 無心義的函數調用
  • 反彙編後的函數的代碼很奇怪, 或不像編譯器生成的代碼
  • ChildEBP 和 RetAddr 的地址沒有意義
考慮如下棧信息:  

0:011> k  
ChildEBP RetAddr  
WARNING: Frame IP not in any known module. Following frames may be wrong.  
0184e434 7c830b10 0×184e5bf  
0184e51c 7c81f832 ntdll!RtlGetFullPathName_Ustr+0×15b  
0184e5f8 7c83b1dd ntdll!RtlpLowFragHeapAlloc+0xc6a  
00099d30 00000000  ntdll!RtlpLowFragHeapFree+0xa7

以上棧信息基本具有了錯誤棧信息的全部性質. 初看像是堆破壞, 由於運行時的堆分配與釋放函數出如今了棧中. 但若是咱們再想一想就會發現 HeapFree 函數不該調用 HeapAlloc 函數, 而接下來更不該該調用 GetFullPathName. 因此這個棧信息是無心義的.  

那咱們能怎樣呢? 檢視 raw 棧信息並構造出真正的棧. 咱們能夠輕鬆地從 BaseThreadStart+0×34 開始遍歷全部幀直到沒有任何函數調用了或都已到棧頂. 當一個函數被調用的時候 EBP 會像下圖那樣連起來 (若是沒有被優化掉, 對於大多數編譯成立).  

http://1.bp.blogspot.com/-CajdqBJzLZ8/UIKoYcwFHsI/AAAAAAAAAfo/ZHYjJB2Ml4M/s640/stackebp.png

0:011> !teb  
TEB at 7ffd8000  
ExceptionList: 0184ebdc  
StackBase: 01850000  
StackLimit: 01841000  
...  
0:011> dds 01841000 01850000  
01841000 00000000  
 
 
 
0184eef0 0184ef0c0184eef4 7615dff2 localspl!SplDriverEvent+0×21  
0184eef8 00bc3e08  
...  
0184ef0c 0184ef300184ef10 7615f9d0  
localspl!PrinterDriverEvent+0×46  
0184ef14 00bc3e08  
0184ef18 00000003  
...  
0184ef2c 00bafcc0  
0184ef30 0184f3f80184ef34 7614a9b4 localspl!SplAddPrinter+0×5f3  
0184ef38 00c3ec58  
...  
0184ff30 0184ff840184ff34 77c75286 RPCRT4!LRPC_ADDRESS::ReceiveLotsaCalls+0×3a  
0184ff38 0184ff4c  
0184ff3c 77c75296 RPCRT4!LRPC_ADDRESS::ReceiveLotsaCalls+0×4a  
0184ff40 7c82f2fc ntdll!RtlLeaveCriticalSection  
...  
0184ff84 0184ff8c0184ff88 77c5778f RPCRT4!RecvLotsaCallsWrapper+0xd  
0184ff8c 0184ffac0184ff90 77c5f7dd RPCRT4!BaseCachedThreadRoutine+0×9d  
...  
0184ffac 0184ffb80184ffb0 77c5de88 RPCRT4!ThreadStartRoutine+0×1b  
0184ffb4 00088258  
0184ffb8  0184ffec  
0184ffbc 77e6608b kernel32!BaseThreadStart+0×34
接下來咱們須要用指定了基址的 k 命令來顯示棧信息. 在本例中最後的有效 EBP 地址是 0184eef0.  

0:011> k L=0184eef0  
ChildEBP RetAddr WARNING: Frame IP not in any known module. Following frames may be wrong.  
0184eef0 7615dff2 0×184e5bf 0184ef0c 7615f9d0 localspl!SplDriverEvent+0×21  
0184ef30 7614a9b4 localspl!PrinterDriverEvent+0×46  
0184f3f8 761482de localspl!SplAddPrinter+0×5f3  
0184f424 74067c8f localspl!LocalAddPrinterEx+0×2e  
0184f874 74067b76 SPOOLSS!AddPrinterExW+0×151  
0184f890 01007e29 SPOOLSS!AddPrinterW+0×17  
0184f8ac 01006ec3 spoolsv!YAddPrinter+0×75  
0184f8d0 77c70f3b spoolsv!RpcAddPrinter+0×37  
0184f8f8 77ce23f7 RPCRT4!Invoke+0×30  
0184fcf8 77ce26ed RPCRT4!NdrStubCall2+0×299  
0184fd14 77c709be RPCRT4!NdrServerCall2+0×19  
0184fd48 77c7093f RPCRT4!DispatchToStubInCNoAvrf+0×38  
0184fd9c 77c70865 RPCRT4!RPC_INTERFACE::DispatchToStubWorker+0×117  
0184fdc0 77c734b1 RPCRT4!RPC_INTERFACE::DispatchToStub+0xa3  
0184fdfc 77c71bb3 RPCRT4!LRPC_SCALL::DealWithRequestMessage+0×42c  
0184fe20 77c75458 RPCRT4!LRPC_ADDRESS::DealWithLRPCRequest+0×127  
0184ff84 77c5778f RPCRT4!LRPC_ADDRESS::ReceiveLotsaCalls+0×430  
0184ff8c 77c5f7dd RPCRT4!RecvLotsaCallsWrapper+0xd
棧信息如今看起來有意義多了, 但咱們仍然沒有看到 BaseThreadStart+0×34. 默認狀況下 WinDbg 只顯示必定數量的棧幀. 因此咱們須要指定棧幀的數量, 好比 100:  

0:011> k L=0184eef0 100  
ChildEBP RetAddr WARNING: Frame IP not in any known module. Following frames may be wrong.  
0184eef0 7615dff2 0×184e5bf  
0184ef0c 7615f9d0 localspl!SplDriverEvent+0×21  
0184ef30 7614a9b4 localspl!PrinterDriverEvent+0×46  
...  
0184ffac 77c5de88 RPCRT4!BaseCachedThreadRoutine+0×9d  
0184ffb8 77e6608b RPCRT4!ThreadStartRoutine+0×1b  
0184ffec 00000000 kernel32!BaseThreadStart+0×34
如今咱們的棧信息看起來更好了. 還有一個完整的示例在   Manual Stack Track  Reconstruction, 本書第 157 頁.  

此外, incorrect stack trace 也會發生在沒有符號信息的時候. 這種狀況下, 一般棧幀之間會有找不到符號的警告:  

STACK_TEXT:  
WARNING: Stack unwind information not available. Following frames may be wrong.  
00b2f42c 091607aa mydll!foo+0×8338  
00b2f4cc 7c83ab9e mydll!foo+0×8fe3  
00b2f4ec 7c832d06 ntdll!RtlFindNextActivationContextSection+0×46  
00b2f538 001a5574 ntdll!RtlFindActivationContextSectionString+0xe1  
00b2f554 7c8302b3 0×1a5574  
00b2f560 7c82f9c1 ntdll!RtlpFreeToHeapLookaside+0×22  
00b2f640 7c832b7f ntdll!RtlFreeHeap+0×20e  
001dd000 00080040 ntdll!LdrUnlockLoaderLock+0xad  
001dd00c 0052005c 0×80040  
001dd010 00470045 0×52005c  
0052005c 00000000 0×470045
翻譯自 MDA-Anthology1 page167, WINDBG TIPS AND TRICKS.  

WinDbg中有一些很好的命令像dpu (檢視unicode字符串)和dpa (檢視ASCII字符串)以及其它 d 開頭的命令如dpp. 咱們可使用這些命令來看看棧上是否有指針指向了字符串.  

例如:  

0:143> !teb
TEB at 7ff2b000 
... 
StackBase: 05e90000 
StackLimit: 05e89000 
... 
... 
...
0:143> dpu 05e89000 05e90000
05e8f58c 00120010 ""
...
...
...
05e8f590 77e7723c "Debugger"
05e8f594 00000000
05e8f598 08dc0154
05e8f59c 01000040
05e8f5a0 05e8f5dc "G:\WINDOWS\system32\faultrep.dll"
05e8f5a4 0633adf0 ""
05e8f5a8 00000000
05e8f5ac 00000001
05e8f5b0 00000012
...
05e8f5d4 0633adfc "drwtsn32 -p %ld -e %ld -g"
...
...
...

固然這些命令不只能對棧地址空間起做用, 也能用在普通的內存段上.


相關文章
相關標籤/搜索