文章的這一部分使用了一個例子,在 Windows 2000 系統下手工建立了 Notepad 的一個 minidump,然後在 Windows XP 系統下調試。
啟動 Visual Studio .NET,單擊[檔案] 功能表上的“開啟解決方案”,在“檔案類型”下拉式清單方塊中選擇“轉儲檔案(*.dmp; *.mdmp)”(555~~~為什麼我在 Visual Studio .NET 2003 中找不到這一項……不過還好,可以直接雙擊 .dmp 檔案開啟——譯者注),找到 minidump 檔案,然後點擊“開啟”建立一個預設工程。
按 F5 在調試器中啟動這個 dump,這一步將為你開始調試提供一些資訊。調試器將建立一個假的進程;在輸出視窗中顯示了很多模組載入的訊息。此時調試器僅僅是在重建崩潰時的進程狀態。在顯示了一條 EXE 不包含調試資訊的警告訊息之後,調試器停在了使用者崩潰的地方,諸如一個非法訪問什麼的。這時候如果你查看調用棧視窗,你會發現缺少符號和很多有用的資訊。
為了讀取一個 minidump,你通常需要相關的二進位拷貝。為了找到正確的二進位檔案,開啟模組視窗。
圖 2 展示了 Notepad 的例子,並且說明了兩個情況。首先,二進位所在的路徑名前標上了一個星號,這表示這些是在使用者機器上的模組路徑,但是在本地卻找不到對應的二進位檔案。其次,在“Information”一列中全都寫著“No matching binary found”。找到對應的二進位檔案的關鍵是注意“Version”欄位和檔案名稱。在這個例子中,大多數系統檔案的版本號碼都是 2195,也就是 Windows 2000。雖然無法從這些資訊上立即得知確切的 service pack (SP) 或者 quality fix engineering (QFE),但這些資訊可以從微軟的 DLL 協助資料庫中查詢到:http://support.microsoft.com/servicedesks/fileversion/dllinfo.asp。
現在,你需要找到一張 Windows 作業系統的 CD 或者已經安裝了正確版本的機器,然後將所需要的檔案複製到一個目錄。通常情況下沒有必要把進程中每個模組的二進位檔案都找出來,但是找出那些在每個調用棧上的關鍵模組是很重要的。這通常包括作業系統的二進位檔案(例如 Kernel32.dll)和你自己的二進位模組(在這個例子中就是 Notepad.exe)。
在你找到這些二進位檔案、並把它們拷貝到一個本地目錄之後,單擊“調試”菜單中的“停止調試”命令。然後在方案總管中,按右鍵工程表徵圖,在捷徑功能表上單擊“屬性”,你將看到“調試”屬性頁面。在“命令參數”中填入“MODPATH”,跟上一個等號,然後輸入二進位檔案所在的位置,如果有多個位置,可以用分號分隔。在這個例子中,它是:
MODPATH=m:/sysbits
在設定好了路徑之後,按 F5 重新裝入 minidump,MODPATH 的值將通過命令列參數傳遞給調試器;在 Visual Studio .NET 的後續版本中應該會有更方便的方法設定這個參數,或許可以作為一個選項出現在屬性對話方塊中。
儘管找到二進位檔案並不太可能改善調用棧視窗的情況,但是它卻能解決模組視窗中的問題, 3 所示:
它現在顯示的不再是“No matching binary found”,而是“Cannot find or open a required DBG file”(我怎麼覺得這個地方的英文文法應該用“nor”而不是“or”……呵呵,不管它了,反正微軟程式中無傷大雅的語法錯誤已經不是第一次被發現了——譯者注)和“No symbols loaded”。前一條訊息出現在那些使用 DBG 檔案儲存體調試資訊的系統 DLL 上,後一條訊息則出現在使用 PDB 檔案的 DLL 上。找到對應的二進位檔案並不能使你看到調用棧;你還需要找到它們對應的調試資訊。
方法 A:坎坷之路
為了完整地分析一個 minidump,你需要找到所有的調試資訊。但為了節省時間,你可以只找那些你需要的資訊。本例中的調用棧列表包含了 User32.dll 和 Kernel32.dll,所以需要它們的調試資訊。
對應的調試資訊 |
作業系統 |
所需的檔案 |
Windows NT 4 |
DBGs |
Windows 2000 |
DBGs, PDBs |
Windows XP |
PDBs |
一個找系統符號的好地方在 http://www.microsoft.com/ddk/debugging,你也可以在 Windows NT Server 和 Windows 2000 Server 作業系統的 Support CD 上找到系統符號。在本例中,它們被拷貝到了二進位代碼所在的位置。實際情況中你可能會遇到非微軟發布的二進位模組,這時候你就需要它們的 PDB 檔案了。同樣在本例中,Notepad 的 DBG 和 PDB 檔案也被拷貝了出來,因為它是我們使用的樣本應用程式。
在單擊“調試”菜單上的“停止調試”命令後再按 F5 就會看到調用棧列表, 4 所示。你也許發現了,由於添加了新的二進位檔案和調試資訊,調用棧發生了變化。這就是我們要的結果;只有在具有調試資訊的情況下才能準確地回溯一個調用棧,提供的資訊越詳細,你得到的堆棧就越精確,通常能夠把那些原來沒有顯示出來的棧幀資訊暴露出來。
在本例中並沒有崩潰。在實際情況中,這些資訊應該已經能夠協助你尋找出大概 70% 的崩潰原因。另外,本例中的調用棧列表是使用微軟隨系統組件提供的、經過刪減的符號檔案所產生的,所以沒有行號資訊。如果你使用自己產生的、完整的 PDB 檔案,你可以看到一個更詳盡的調用棧。
符號伺服器
如果你需要處理大量 minidumps,進行大範圍調試,那麼儲存和訪問所有的二進位檔案以及 PDB/DBG 檔案將變得很困難。Windows NT 中包含了一種叫做符號伺服器的技術,起初只是用來儲存符號檔案的,後來擴充到也支援二進位檔案的尋找。Windows NT 調試器是第一個支援它的工具,但實際上 Visual Studio .NET 也支援它,雖然沒有文檔提及(事實上,在 Visual Studio .NET 2003 的文檔中和 MSDN 的 Knowledge Base (KB) 中都有講到如何使用符號伺服器,KB 中的 Q319037 和 Q311503 分別講述了如何在 Visual Studio .NET 2002 和 Visual Studio 6.0 中使用符號伺服器,甚至還包括了一個詳細無比的、傻瓜式的教學視頻。在 MSDN 中搜尋索引鍵“symsrv.dll”可以找到這部分內容——譯者注)。關於符號伺服器,可以參考 http://www.microsoft.com/ddk/debugging/symbols.asp。
|
方法 B:康庄大道——使用符號伺服器
首先,去 http://www.microsoft.com/ddk/debugging 下載調試工具。你需要安裝 Symsrv.dll 檔案,你可以將它拷貝到 devenv.exe 所在的目錄下,或者放到你的 System32 目錄下,以便 Visual Studio .NET 可以訪問到它。在複製了 Symsrv.DLL 檔案之後,你就可以安全地卸載調試工具了。你還需要建立一個本地目錄,在本例中,建立了一個本地目錄 C:/localstore。
在工程屬性對話方塊中的“調試”屬性頁面上,填寫“符號路徑”:
SRV*c:/localstore*http://msdl.microsoft.com/download/symbols
這個字串會告訴調試器使用符號伺服器來擷取符號檔案,並在本地建立一個符號伺服器,用來存放符號檔案。現在,當你在 minidump 工程中按下 F5 後,符號檔案將從微軟的網站上拷貝到本機伺服器。在第一次下載後,之後的載入速度就會快很多,因為符號檔案將從本機伺服器中直接載入,不再需要通過 Web 下載了。
在調試微軟之外的程式時,你應該將方法 A 和方法 B 結合起來。用方法 A 獲得系統組件的符號檔案(反了吧?好像應該用方法 B 吧……不過原文確實是“Use A to get the system components”——譯者注),然後附上你自己的符號檔案路徑,用分號將它們隔開,例如:
c:/drop/build/myapp;SRV*c:/localstore*http://msdl.microsoft.com/download/symbols
由於符號伺服器是 Visual Studio .NET 中的一個沒有文檔說明的特性,所以沒有錯誤報表。如果運算式錯誤或者 Symsrv.dll 檔案的位置不正確,符號檔案就不能被載入,只能在模組視窗中顯示“No symbols loaded”的錯誤資訊。你也可以使用符號伺服器儲存和下載二進位檔案,但是 MODPATH 運算式需要使用“symsrv*symsrv.dll*”而不是“SRV*”(MSDN 中對於“srv”的解釋是:“This is shorthand for symsrv*symsrv.dll.”——譯者注)。
注意:微軟的符號伺服器不包含二進位檔案,但是你自己建立的符號伺服器卻可以。
符號伺服器不僅僅是用來調試 minidumps 的,它提供了一種“線上”調試的方法。在使用符號伺服器之前,別忘了正確地配置“調試”屬性頁面上的“符號路徑”選項。
|