Windbg是微軟提供的Windows平台上強大且高效的用戶态和内核态調試工具,其調試功能甚至比微軟的Visual Studio集成開發環境還要強大。Windbg是我們日常工作中頻繁使用的分析工具,我們使用了多年,這一點我們是深有體會的。
Windbg可以分析和定位多種軟件異常問題,比如軟件崩潰、死循環、内存洩露、多線程死鎖等,其分析與定位問題的效率遠比直接分析代碼要高的多!下面就幾個關于windbg使用上的一些細節,簡單的說明一下。
1、Visual Studio調試時看不到有效的函數調用堆棧,windbg很多時候都能捕獲到有時候我們在使用Visaul Studio(後面簡稱VS)調試程序時,程序發生了崩潰,但是VS中看不到崩潰時的完整的函數調用堆棧,當然這個情況下往往是崩潰在底層的dll模塊的,不是我們負責的代碼模塊。
這種情況我們遇到過很多次,比如:
從VS給出的信息中,我們隻是知道崩潰在系統運行時庫ucrtbase.dll中,肯定是調用此庫的上層代碼引起的,這個ucrtbase.dll本身肯定是沒問題的。但是看不到完整的函數調用堆棧,沒法确定是哪個dll模塊觸發的,更搞不清楚是哪個函數調用引起的!
好在這個問題我們比較有經驗,我們可以直接啟動Debug版本的exe程序,然後啟動windbg,将windbg附加到這個exe進程上,然後按照崩潰複現的操作步驟,複現後windbg即能抓到有效的崩潰信息,就能查看到詳細的函數調用堆棧,就能知道問題出在哪個函數中了。
具體的操作是這樣子的,windbg捕獲到異常就會中斷下來,在windbg中輸入kn、kv或kp命令就能查看到崩潰時的函數堆棧調用信息了,如下所示:
調用堆棧從下往上看,可以得知是崩潰在mtrtcmpdll.dll庫中了。上圖中我們已經加載了pdb符号庫文件(包含完整的函數和變量的符号信息),所以能看到崩潰在哪個函數中,并且能看出崩潰在函數的哪一行代碼上。
一般我們查看到函數調用堆棧以後,确定崩潰在哪個模塊,然後使用“lm vm 模塊名*”命令,查看這個模塊文件的時間戳:
确定目标模塊是哪一天編譯的,是幾點幾分幾秒編譯出來的,然後到版本編譯服務器上找到對應的目錄,取出對應的pdb文件,然後将pdb文件的路徑添加到windbg中:(在windbg菜單欄中,File --> Symbol File Path)
注意在上面的界面中勾選reload選項,勾選後windbg會自動去加載pdb文件。
有時候可能加載不成功,此時就需要使用“.realod /f 帶文件後綴的完整的文件名”命令來強制加載pdb文件了。這個地方要注意一下,加載pdb文件是有嚴格的時間戳限制的,pdb文件和對應的庫文件必須是一個時間點生成的,否則會加載失敗!即便是一模一樣的代碼(沒有改動的),兩個時間點編譯的,pdb都不能混用的!
2、沒有pdb符号文件時,看到的函數調用堆棧可能是無效的,沒法分析的這個問題我們也遇到過,比如下面的場景:
上面打印出來的函數調用堆棧全部是彙編指令的地址,完全看不到模塊名,根本沒法直接分析的。當然精通彙編代碼的人,照樣是有辦法進行深入分析的,但比較費時費力!
根據崩潰的最後一條彙編指令所在的模塊路徑,得知是崩潰在哪個模塊中,然後找到pdb文件添加到windbg中來,然後使用kn命令再來查看函數調用堆棧,就能看到詳細的信息了:
這樣就能看到崩潰在哪個函數中了,崩潰在函數的哪一行代碼上了。
3、導出的是64位的dump文件,查看調用堆棧之前需要轉換成32位的查看一般情況下,我們的軟件都是32位程序,可能運行在64位Windows系統上,可能導出的dump文件是64位的,比如從Windows資源管理器中導出的dump文件:
取來dump文件用windbg打開,打開後看到的函數調用堆棧如下:
這樣的堆棧信息完全不知所雲,和我們的軟件無法對應起來,很是奇怪!其實很簡單,隻要在windbg中輸入“.effmach X86”命令,在windbg自帶的幫助文檔中可以看到該命令的詳細說明:
該命令可以将64位的函數調用堆棧上下文,轉換成32位的,這樣就能看到有效的函數調用堆棧了,如下:
4、pdb文件非常重要,如何正确地将pdb文件加載到windbg中
上面我說到過,pdb文件和目标文件的時間戳要嚴格一緻的,否則windbg會加載失敗的。pdb加載成功與否,可以使用“lm vm 模塊名*”命令查看的,如果加載成功,會顯示出來的,如下所示:
有一次我們在幫兄弟部門排查軟件崩潰時,已經找到對應時間點的pdb文件,但是就是加載不起來,使用.reload命令強制加載也加載不起來!
後來在windbg的錯誤提示信息中看到:
可以使用“!sym noisy”命令打開pdb加載詳情開關,看看能不能找到加載失敗的原因,于是就輸入了該命令,然後用.reload命令再去加載目标庫的pdb文件,看到了提示信息:
我們的程序崩潰在kdcodec.dll庫上,但是從上面的信息看出,是去加載帶“_hp”後綴的kdcodec_hp.pdb文件,但是我們找到的是kdcodec.pdb文件,難道是kdcodec庫的源代碼工程是以帶“_hp”後綴來命名的,經過個同事确認,确實是這樣的!
這樣就能确定原因了,pdb文件還有一個規則,就是pdb文件的名稱必須要和源代碼工程的名稱完全一緻,否則會加載失敗!估計是拷貝文件的腳本,在拷貝pdb文件到版本服務器上時,将pdb文件重命名了,将“_hp”後綴去掉了,所以出現了上述加載失敗的問題了。隻要手動去加上“_hp”後綴就好了。
5、寫在最後上面是我多年來在使用windbg上的一些細節問題,在這裡簡單的給大家分享一下,希望能對大家有一定的幫助!
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!