引言
第一次用WinDbg來排查問題,花了很多時間踩坑,記錄一下希望對后面的同學有些幫助。
客戶現場軟件出現偶發性的界面卡死現象一直找不出原因,就想着讓客戶用任務管理器生成了一個dump文件發給我,我再用WinDbg看一下現線程堆棧。
找篇教程,按步驟一步一步來,應該挺簡單吧。我想。
WinDbg軟件版本選擇
官方版本不“綠色”,最開始從第三方下了一個《WinDbg中文版(32位/64位) 6.12 獨立版》v6.12.2.663
結果不管怎么嘗試,加載CLR DLL的時候都提示
0:000> .cordll -u -ve -l
CLR DLL status: No load attempts
由於沒經驗,一直懷疑是不是自己哪里沒有配置正確、操作有問題、敲鍵盤的姿勢不對?。做了很多嘗試,才意識到會不會下載的版本有問題,於是趕緊去官網下載(Debugging Tools for Windows (WinDbg, KD, CDB, NTSD))v6.3.9600.17298。果然!新的版本不會再出現這個提示! 有人說這是軟件BUG。。。一口老血。。。
32位 vs 64位 該用哪個版本的WinDbg
下載的WinDbg有32和64位兩個版本,該用哪個版本呢?我們可以參考這位園友的回答(一句話總結Windbg 32位版本和64位版本的選擇)
他說:只有在實時用戶態調試,並且調試器也在同一台64位機器上的情況下必須用64位的調試工具集。
那么我們調試dump,選擇WinDbg x86應該沒錯了。
按套路來
因為一直失敗,更換N種套路后,保留這一種:
-
設置符號地址
菜單|File|Symbol File Path|設置符號地址srv*c:\symbolspub*http://msdl.microsoft.com/download/symbols
(如果你還有本地符號,點擊Browse... 選擇路徑)
-
打開dump文件
菜單|File|Open Crash Dump...|選擇dump文件路徑打開dump文件 -
加載SOS
0:000> .cordll -ve -u -l
CLRDLL: C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscordacwks.dll:2.0.50727.8762 f:0
doesn't match desired version 2.0.50727.5485 f:0
CLRDLL: Unable to find mscordacwks_x86_x86_2.0.50727.5485.dll by mscorwks search
CLRDLL: Unable to find 'mscordacwks_x86_x86_2.0.50727.5485.dll' on the path
CLRDLL: Unable to get version info for 'c:\symbolspub\mscorwks.dll\53A121FA5ae000\mscordacwks_x86_x86_2.0.50727.5485.dll', Win32 error 0n87
Cannot Automatically load SOS
CLRDLL: ERROR: Unable to load DLL mscordacwks_x86_x86_2.0.50727.5485.dll, Win32 error 0n87
CLR DLL status: ERROR: Unable to load DLL mscordacwks_x86_x86_2.0.50727.5485.dll, Win32 error 0n87
誒,出錯了,從日志可以看出缺少 c:\symbolspub\mscorwks.dll\53A121FA5ae000\mscordacwks_x86_x86_2.0.50727.5485.dll
文件。
這個文件從哪來?
1)客戶計算機:NET2.0 x86 在 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727
路徑下的 mscordacwks.dll
,其他版本類似;
2)從網絡下載:這里有好心人已經打包了:Mscordacwks/SOS debugging archive;
把下載的文件重命名一下放到 c:\symbolspub\mscorwks.dll\53A121FA5ae000\mscordacwks_x86_x86_2.0.50727.5485.dll
路徑下,這個路徑就是前面設置的符號地址的存儲路徑。一定要確保版本完全一致,再加載一次就OK了。
加載成功后提示類似:
0:000> .cordll -u -ve -l
CLRDLL: C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscordacwks.dll:2.0.50727.8762 f:0
doesn't match desired version 2.0.50727.5485 f:0
CLRDLL: Unable to find mscordacwks_x86_x86_2.0.50727.5485.dll by mscorwks search
CLRDLL: Unable to find 'mscordacwks_x86_x86_2.0.50727.5485.dll' on the path
CLRDLL: Unable to get version info for 'c:\symbolspub\mscorwks.dll\53A121FA5ae000\SOS_x86_x86_2.0.50727.5485.dll', Win32 error 0n87
Cannot Automatically load SOS
CLRDLL: Loaded DLL c:\symbolspub\mscorwks.dll\53A121FA5ae000\mscordacwks_x86_x86_2.0.50727.5485.dll
CLR DLL status: Loaded DLL c:\symbolspub\mscorwks.dll\53A121FA5ae000\mscordacwks_x86_x86_2.0.50727.5485.dll
如果一切正常,這時候輸入 !threads 就可以看到托管線程了。
0:000:x86> !threads
ThreadCount: 22
UnstartedThread: 0
BackgroundThread: 20
PendingThread: 0
DeadThread: 1
Hosted Runtime: no
PreEmptive GC Alloc Lock
ID OSID ThreadOBJ State GC Context Domain Count APT Exception
0 1 7c0 000000000077d1d0 6020 Enabled 0000000000000000:0000000000000000 0000000000778c20 0 STA
2 2 260 000000000078bfe0 b220 Enabled 0000000000000000:0000000000000000 0000000000778c20 0 MTA (Finalizer)
5 4 fd0 00000000007ec5a8 80a220 Enabled 0000000000000000:0000000000000000 0000000000778c20 0 MTA (Threadpool Completion Port)
balabala...
好事多磨
沒有坑是不可能滴,我電腦上卻提示:
0:000> !threads
Failed to load data access DLL, 0x80004005
Verify that 1) you have a recent build of the debugger (6.2.14 or newer)
2) the file mscordacwks.dll that matches your version of mscorwks.dll is
in the version directory
3) or, if you are debugging a dump file, verify that the file
mscordacwks_<arch>_<arch>_<version>.dll is on your symbol path.
4) you are debugging on the same architecture as the dump file.
For example, an IA64 dump file must be debugged on an IA64
machine.
You can also run the debugger command .cordll to control the debugger's
load of mscordacwks.dll. .cordll -ve -u -l will do a verbose reload.
If that succeeds, the SOS command should work on retry.
If you are debugging a minidump, you need to make sure that your executable
path is pointing to mscorwks.dll as well.
再用.cordll和.chain檢查一下SOS的加載情況
0:000> .cordll
CLR DLL status: Loaded DLL c:\symbolspub\mscorwks.dll\53A121FA5ae000\mscordacwks_x86_x86_2.0.50727.5485.dll
0:000> .chain
Extension DLL search Path:
balabala。。。
Extension DLL chain:
C:\Windows\Microsoft.NET\Framework\v2.0.50727\sos: image 2.0.50727.8762, API 1.0.0, built Wed Apr 05 11:41:39 2017
[path: C:\Windows\Microsoft.NET\Framework\v2.0.50727\sos.dll]
balabala。。。
可以看到sos正常加載了啊,難道沒有?哪里還有問題?。。。這里我又卡了很久沒有頭緒。。。
Google半天才意識到,會不會是抓的dump有問題,再查,才發現有人建議用64位任務管理器抓64位進程的dump,32位任務管理器抓32位進程的dump。我去,又是一口老血。。。
64位系統怎么抓dump
我們以抓32位進程的dump為例,先打開32位任務管理器(C:\Windows\SysWOW64\taskmgr.exe
)
確保taskmgr.exe 后面有一個*32
,表示這是一個32位程序跑在64位系統上,叫做wow64模式。
然后右鍵你的目標進程,點擊“創建轉儲文件”,成功后會提示dmp文件存儲路徑。
也就是說,你的目標進程有 *32
,taskmgr也要有 *32
,如果沒有則都必須沒有。
另外:推薦抓dump工具:ProcDump 小巧又強大,里面也是區分一個32位版本和一個64位版本。
正確的dump抓下來,再按照前面的方法正常情況就可以開始分析了。
再接再勵
那是不是64位任務管理器抓32位進程的dump就沒用了呢?等現場抓下一個dump不知道要等到什么時候。繼續Google,終於找到關鍵字 Debugging WOW64
然后找到這篇文章 Debugging a 64-bit dump of a 32-bit managed process
簡單說,就是前面步驟做完后,通過下面兩條指令切換到32bit模式
0:000> .load wow64exts
0:000> !sw
Switched to 32bit mode
切換32bit模式后后 !clrstack
可以執行,卻看不到正確的堆棧信息
0:000:x86> !clrstack
OS Thread Id: 0x7c0 (0)
Failed to start stack walk: 80070057
Google無果。不過還好,可以用其他指令指令替代它,比如 !dumpstack -ee
0:000:x86> !dumpstack -ee
OS Thread Id: 0x7c0 (0)
TEB information is not available so a stack size of 0xFFFF is assumed
Current frame:
ChildEBP RetAddr Caller,Callee
002dca68 6a27d6b4 (MethodDesc 0x69e47600 +0x70 System.Data.OleDb.OleDbCommand.ExecuteCommandTextForSingleResult(System.Data.OleDb.tagDBPARAMS, System.Object ByRef))
002dca88 6a27d6b4 (MethodDesc 0x69e47600 +0x70 System.Data.OleDb.OleDbCommand.ExecuteCommandTextForSingleResult(System.Data.OleDb.tagDBPARAMS, System.Object ByRef))
002dcab4 6a27d519 (MethodDesc 0x69e475e4 +0xbd System.Data.OleDb.OleDbCommand.ExecuteCommandText(System.Object ByRef))
002dcaf0 6a27d437 (MethodDesc 0x69e475d8 +0x3b System.Data.OleDb.OleDbCommand.ExecuteCommand(System.Data.CommandBehavior, System.Object ByRef))
002dcb00 6a27d192 (MethodDesc 0x69e475cc +0xa2 System.Data.OleDb.OleDbCommand.ExecuteReaderInternal(System.Data.CommandBehavior, System.String))
..balabala...
至此,我想看的線程堆棧信息終於出來了~~~ 額,WTF,又是萬惡的ACCESS惹的禍! 再吐一口血,卒。。。
總結一下
- 最好從官方下載程序(即便它不是綠色版,即便它還和其他程序綁定 😦)
- 用64位任務管理器(或調試器)生成64位進程的dump,用32位任務管理器(或調試器)生成32位進程的dump!
- 加載SOS最容易出問題的一點就是:一定要保證加載的SOS模塊要與客戶現場的程序版本保持一致!
- 最后,最重要的一點:不要用ACCESS、CCESS、CESS、ESS、SS、S ~~~
客戶:ACCESS好用的,好伐,快給我起來干活。
我我:。。。讓我再死會兒~
參考鏈接
- 面向.Net程序員的dump分析
- Windbg 調試 SOS 版本問題
- “Failed to load data access DLL, 0x80004005” – OR – What is mscordacwks.dll?
- 使用Mdbg.exe 調試.Net 程序
- SOS Debugging Extension (SOS.dll)
- Debugging Managed Code Using the Windows Debugger
- Determine if process dump was generated on x64 or x86 machine
- How to use Windbg to debug a dump of a 32bit .NET app running on a x64 machine
- "Failed to start stack walk: 80004005", "Following frames may be wrong" and other errors you may see in windbg
- Debugging a 64-bit dump of a 32-bit managed process
- Debugging WOW64