使用Windows事件查看器調試崩潰


本文討論如何使用Windows事件查看器獲取實際崩潰的模塊以及代碼中崩潰的位置。示例代碼是用C++編寫的,以生成不同類型的崩潰,例如訪問沖突和堆棧溢出。

簡介

我經常聽同事和QA那里聽說,一個特定的崩潰很容易在客戶機上重現,而不是在他們的機器上重現。這是一個棘手的問題,因為開發人員無法在客戶機上調試崩潰。最終的結果是支持團隊和客戶之間無休止的溝通,甚至是現場會議。很少有聰明的程序員自己開發一個崩潰日志系統來確定導致崩潰的代碼。很少有人會在代碼中全面地實現try-catch塊,以縮小問題的范圍。

背景

近年來,我開始使用事件查看器檢查在特定計算機上注冊的各種警告和錯誤的日志。我注意到應用程序或程序崩潰記錄在應用程序事件日志中,並且在大多數情況下都有足夠的信息來獲取崩潰或問題位置。事件查看器通常位於C:\ Windows\system32\eventvwr.exe中,一旦啟動,就可以輕松查看應用程序事件日志。

當應用程序或程序在特定機器上崩潰時,類似的信息也會顯示給用戶。

如何調試崩潰?

為了更好地理解事件記錄器/查看器,我決定創建一個簡單的程序,當某個特定的命令行參數傳遞給它時,該程序將崩潰。

 

HowToFindCrashInExeCode.exe以1到4之間的數字作為參數,然后通過生成適當的異常來相應地崩潰。1號和3號生成訪問沖突異常,而2號和4號分別在從屬DLL和主EXE中生成StackOverflow異常。下面的兩個圖像顯示了當程序在命令行上崩潰時,使用1作為輸入參數的崩潰報告和應用程序事件日志。

 

 

 

應用程序事件日志提供給我們的重要細節是錯誤應用程序路徑、錯誤模塊名稱和路徑、異常代碼以及最重要的錯誤偏移量。錯誤應用程序路徑、錯誤模塊名稱和路徑的目的非常明顯。異常代碼揭示了崩潰發生的細節和/或情況。故障偏移量是加載的故障模塊內的內存位置,即它為我們提供了日志中提到的故障模塊中的准確故障位置。從客戶處獲取應用程序事件日志后,請檢查故障模塊名稱、路徑和故障偏移量,然后在計算機上啟動應用程序並將其附加到調試器。找到加載的故障模塊的起始內存地址,並將故障偏移量添加到此地址。然后使用反匯編跳轉到內存地址。反匯編將准確地告訴您崩潰的位置。這不是一個很酷很快就能解決問題的方法嗎。上面的事件管理器日志告訴我們,錯誤模塊是HowToFindCrashInDLLCode.dll,異常代碼是0xc000005,這是訪問沖突異常,錯誤偏移量是0x00001032。下圖描述了howtoFindCrashHindllcode.dll的反匯編以及模塊加載地址。

 

模塊加載地址為0x73D60000,現在添加錯誤偏移量0x00001032。產生的內存地址是0x73D61032。跳轉到此內存位置后,可以看到崩潰來自函數crashForAccessViolation,生成此崩潰的代碼是pVal[0]=10;因為pVal是未實例化的整數指針。

比較有趣的點

在開發人員的機器上調試相同版本/配置/平台的程序以獲得准確的錯誤位置是很重要的。另外,如果為程序生成了pdb,那么一旦跳轉到錯誤偏移量,就可以看到反匯編和源代碼。不需要在禁用優化的情況下構建程序,因為該程序的錯誤偏移量是通用的,開發人員需要自己做一些基本的數學計算。有時,崩潰模塊是系統DLL之一,例如kernel.DLL、nt.DLL或msvcr100.DLL,然后按上述方法檢查故障偏移量,並檢查異常代碼。這兩件事將幫助您猜測代碼中的問題,例如STL或CRT庫拋出一些異常,如邏輯錯誤,有時會生成未處理的異常,這些異常會被系統DLL捕獲。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM