Windbg dump分析 学习总结
生活随笔
收集整理的這篇文章主要介紹了
Windbg dump分析 学习总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Windbg核心調試之dump分析
http://www.pediy.com/kssd/pediy08/pediy8-428.htm標 題: Windbg核心調試之dump分析
作 者:Lvg
時 間:2006-11-17 12:56?
鏈 接:http://bbs.pediy.com/showthread.php?threadid=35044
調試環境:winxp sp2+windbg ver:6.6.0007.5+vmware 5.5.2
附件:點擊下載
一.Dump文件的產生,意義和類型
? ? 當系統發生錯誤是,最常見的就是藍屏(Blue screen),這時就會在系統目錄下產生一個Dump文件,如MEMORY.DMP 。這個文件的主要意義在于分析系統錯誤發生的原因,以作出解決的方法。
? ?它可分為三種類型:
? ?1.完全內存轉儲。這個文件比較大,和物理內存相當,包含了程序崩潰前系統及用戶模式下的所有信
息。
? ?2.核心內存轉儲。這個文件大小約物理內存的三分之一,主要包含崩潰前系統內核的運行情況。一般
為了分析內核錯誤,就選用這種文件。
? ?3.小內存轉儲。這個文件小,只有64k,剛好一個頁面文件大小。它包含了相對比較少的信息,主要
可用于微軟的在線分析。
? ?以上三種形式的文件可以在我的電腦——〉鼠標右鍵——〉屬性——〉高級——〉故障及恢復中設置
。如下圖:
二 Dump文件的強迫產生
? ?由于我們也不知道何時會產生一個系統錯誤,從而得到dump文件,所以當練習分析時,可認為強迫產生一個。一般有以下兩個辦法。
? ?1.雙機聯調。這里的雙機可以是物理上的兩臺電腦,也可以是用虛擬機模擬。我想這里的大多數人應
該選擇后者,為啥?還不是money的問題~_^。當用windbg把被調試機聯上以后,就可以用.crash命令產
生一個藍屏,當然之前要在被調試機里把dump產生的路徑和類型設定好。還有另外一張辦法,是通過修
改注冊表后,用鍵盤產生dump,但這種方法哪有第一種來的快,所以就不說了,感興趣的可以查查
windbg幫助文檔看看。
? ?2.單機驅動產生。這種方法,不必用雙機聯調,在本機上就可以辦到。由于驅動深入到了內核,它的
要求非常苛刻,一個簡單的除零操作就可引發藍屏。但是驅動的編寫與普通win32 api是有很大不同的,
為了減輕負擔,我直接運用一個現成的程序,是《Microsoft Windows Internals》作者寫的Notmyfault
(見附件)。它由Notmyfault.exe和Myfault.sys兩部分組成。正如名字一樣,引發藍屏的不是
Notmyfault.exe而是由他加載到內核中的Myfault.sys。如圖:
?
? ?我在這里兩種方法都同時用了,先在虛擬機里執行Notmyfault,接著windbg立刻檢測到了系統崩潰,
并輸出相關信息。?
三 Dump文件的分析
? ? 當按上面的方法運行后,windbg輸出了以下內容:*** Fatal System Error: 0x000000d1
? ? ? ? ? ? ? ? ? ? ? ?(0xE1147008,0x0000001C,0x00000000,0xFBE93403)
? Break instruction exception - code 80000003 (first chance)
? A fatal system error has occurred.
? Debugger entered on first try; Bugcheck callbacks have not been ? invoked.
? A fatal system error has occurred.
*******************************************************************************
* ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* ? ? ? ? ? ? ? ? ? ? ? ?Bugcheck Analysis ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*
* ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
*******************************************************************************
Use !analyze -v to get detailed debugging information.
2.BugCheck D1, {e1147008, 1c, 0, fbe93403}
*** ERROR: Module load completed but symbols could not be loaded for myfault.sys
3.Probably caused by : myfault.sys ( myfault+403 )
Followup: MachineOwner
---------
nt!RtlpBreakWithStatusInstruction:
80527da8 cc ? ? ? ? ? ? ?int ? ? 3
Kd:> ?
上面這一段,有用的信息,如1和2兩段,說明的是一個問題,都指明了BugCheck是D1,并給了四個參數
,這里的D1可以在windbg文檔的Bug Check Code Reference中查出其具體含義,也可用!analyze –show?
D1命令查出。3說明引起的原因是myfault.sys模塊。
接著在kd后輸入!analyze –v命令,這個命令是詳細列出dump文件的信息。
windbg輸出如下:
kd> !analyze -v
*******************************************************************************
* ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* ? ? ? ? ? ? ? ? ? ? ? ?Bugcheck Analysis ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*
* ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
*******************************************************************************
DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1) ?//指明Bugcheck D1,我們已看見過了
An attempt was made to access a pageable (or completely invalid) address at an
interrupt request level (IRQL) that is too high. ?This is usually
caused by drivers using improper addresses. ? ? ?//解釋了錯誤的原因
If kernel debugger is available get stack backtrace.
Arguments:
Arg1: e1147008, memory referenced
Arg2: 0000001c, IRQL
Arg3: 00000000, value 0 = read operation, 1 = write operation
Arg4: fbe93403, address which referenced memory
? ? ? ? ? ? ? ? ?//給出了相應的四個參數,第二列是代號,第三列是解釋
Debugging Details:
------------------
READ_ADDRESS: ?e1147008 Paged pool ? ? ? //上面的Arg1.
CURRENT_IRQL: ?1c ? ? ? //上面的Arg2
FAULTING_IP: ? ? //指出發生錯誤時所執行的指令
myfault+403
fbe93403 8b06 ? ? ? ? ? ?mov ? ? eax,dword ptr [esi]
DEFAULT_BUCKET_ID: ?DRIVER_FAULT ? //指出錯誤類型,是驅動錯誤
BUGCHECK_STR: ?0xD1 ? //bugcheck索引,可查windbg文檔,也可!analyze –show D1
PROCESS_NAME: ?NotMyfault.exe ?//錯誤所屬進程
TRAP_FRAME: ?f9357b80 --(trap fffffffff9357b80)//錯誤時各寄存器的內容
ErrCode = 00000000
eax=00000000 ebx=8111f330 ecx=000000d1 edx=0000001c esi=e1147008 edi=00000000
eip=fbe93403 esp=f9357bf4 ebp=f9357c58 iopl=0 ? ? ? ? nv up ei pl zr na pe nc
cs=0008 ?ss=0010 ?ds=0023 ?es=0023 ?fs=0030 ?gs=0000 ? ? ? ? ? ? efl=00010246
myfault+0x403:
fbe93403 8b06 ? ? ? ? ? ?mov ? ? eax,dword ptr [esi] ?ds:0023:e1147008=????????
Resetting default scope
LAST_CONTROL_TRANSFER: ?from 804f880d to 80527da8
STACK_TEXT: //反映了錯誤前堆棧中函數調用情況,最下面的0x7c801671處函數調用ntdll中的
ZwDeviceIoControlFile,接著調用了ntdll中的KiFastSystemCallRet,再接著調用了nt(這里的nt指
Ntoskrnl)中的KiFastCallEntry,一直到myfault+0x403,發生異常。
f9357734 804f880d 00000003 f9357a90 00000000 nt!RtlpBreakWithStatusInstruction
f9357780 804f93fa 00000003 e1147008 fbe93403 nt!KiBugCheckDebugBreak+0x19
f9357b60 80540853 0000000a e1147008 0000001c nt!KeBugCheck2+0x574
f9357b60 fbe93403 0000000a e1147008 0000001c nt!KiTrap0E+0x233
WARNING: Stack unwind information not available. Following frames may be wrong.
f9357c58 805759d1 ffb5c3b0 8111f318 811d9130 myfault+0x403
f9357d00 8056e33c 00000090 00000000 00000000 nt!IopXxxControlFile+0x5e7
f9357d34 8053d808 00000090 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
f9357d34 7c92eb94 00000090 00000000 00000000 nt!KiFastCallEntry+0xf8
0012f9f0 7c92d8ef 7c801671 00000090 00000000 ntdll!KiFastSystemCallRet
0012f9f4 7c801671 00000090 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xc
0012fa54 004018c2 00000090 83360018 00000000 0x7c801671
STACK_COMMAND: ?kb
FOLLOWUP_IP: //反匯編了發生錯誤指令的代碼
myfault+403
fbe93403 8b06 ? ? ? ? ? ?mov ? ? eax,dword ptr [esi]
SYMBOL_STACK_INDEX: ?4
FOLLOWUP_NAME: ?MachineOwner
MODULE_NAME: myfault
IMAGE_NAME: ?myfault.sys
DEBUG_FLR_IMAGE_TIMESTAMP: ?43774e1d
SYMBOL_NAME: ?myfault+403
FAILURE_BUCKET_ID: ?0xD1_myfault+403
BUCKET_ID: ?0xD1_myfault+403
Followup: MachineOwner
//以上幾段看名字就知道了,是以上信息的重復沒有多大價值。
四 總結
? ? 通過以上的分析,知道了藍屏的原因是Bugcheck D1引起的,是由于驅動程序讀操作了過高的IRQL引起的。也知道了這個引發藍屏的驅動程序是myfault.sys,屬于notmyfaulf.exe的進程。還知道了藍屏前
bug程序myfault.sys的調用情況等多個有用信息,接著就可以在myfault.sys源程序中進行bug修改了。
========
利用windbg分析dump文件 ?
http://blog.163.com/crazywolf_/blog/static/195231413201061794619624/這里主要記錄利用windbg來分析windows藍屏
時所產生的內存轉儲文件*.dmp。
1,下載:
http://www.microsoft.com/whdc/devtools/debugging/default.mspx
2,配置symbol path:
windows程序在編譯生成后,會產生一些.exe,dll文件。同時也會用到一些symbol文件,這些文件包含全
局變量,局部變量等信息。在調試不同的系統的時候,用到的symbol是不同的,而且這些文件會很大,
如果下載安裝會占用很大的硬盤空間。如果下載,在上面提供的地址也可以下載。微軟還提供了一個網
絡上的symbol服務器。其網絡地址是:http://msdl.microsoft.com/download/symbols,設置symbol時
可以在打開windbg后,file->symbol file path 設置如下:其d:\temp 是本地緩存的目錄:
SRV*d:/temp/*http://msdl.microsoft.com/download/symbols。也可以用命令如下設置:
set _NT_SYMBOL_PATH=srv*DownstreamStore*http://msdl.microsoft.com/download/symbols
利用windbg分析dump文件(二)基本調試
1,打開dump文件,在正確設置了symbol路徑后,會有如下的顯示:
Microsoft (R) Windows Debugger Version 6.5.0003.7
Copyright (c) Microsoft Corporation. All rights reserved.
Loading Dump File [D:\important\document\win系統\debug\Mini121605-01.dmp]
Mini Kernel Dump File: Only registers and stack trace are available
Symbol search path is: SRV*d:/temp/*http://msdl.microsoft.com/download/symbols
Executable search path is:
Windows 2000 Kernel Version 2195 (Service Pack 4) UP Free x86 compatible
Kernel base = 0x80400000 PsLoadedModuleList = 0x8046e8f0
Debug session time: Fri Dec 16 13:30:21.203 2005 (GMT+8)
System Uptime: not available
Loading Kernel Symbols
...........................................................................................
.........................
Loading unloaded module list
...................
Loading User Symbols
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************
Use !analyze -v to get detailed debugging information.
BugCheck 7F, {8, 0, 0, 0}
c0000005 Exception in ext.Analyze debugger extension.
?PC: 77c16fa3 VA: 01fe8000 R/W: 0 Parameter: 0001003f
2,關于調試窗口:view菜單下面有詳細的列表:可以調出對應的窗口,默認的打開窗口是command窗口
3,基本調試命令:
r 可以顯示系統崩潰時的寄存器,和最后的命令狀態。
dd 顯示當前內存地址,dd 參數:顯示參數處的內存。
u 可以顯示反匯編的指令
!analyze -v 顯示分析的詳細信息。
kb 顯示call stack 內容
kv.bugcheck 可以顯示出錯的代碼
========
?WinDBG 技巧:如何生成Dump 文件(.dump 命令)
http://wingeek.blog.51cto.com/1226974/273964程序崩潰(crash)的時候, 為了以后能夠調試分析問題, 可以使用WinDBG要把當時程序內存空間數據
都保存下來,生成的文件稱為dump 文件。 步驟:
1) 打開WinDBG并將之Attach 到crash的程序進程
2) 輸入產生dump 文件的命令
WinDBG產生dump 文件的命令是 .dump ,可以選擇不同的參數來生成不同類型的dump文件。
選項(1): /m
命令行示例:.dump /m C:\dumps\myapp.dmp
注解: 缺省選項,生成標準的minidump, 轉儲文件通常較小,便于在網絡上通過郵件或其他方式傳輸
。 這種文件的信息量較少,只包含系統信息、加載的模塊(DLL)信息、 進程信息和線程信息。
選項(2): /ma
命令行示例:.dump /ma C:\dumps\myapp.dmp
注解: 帶有盡量多選項的minidump(包括完整的內存內容、句柄、未加載的模塊,等等),文件很大,
但如果條件允許(本機調試,局域網環境), 推薦使用這中dump。
選項(3):/mFhutwd
命令行示例:.dump /mFhutwd C:\dumps\myapp.dmp
注解:帶有數據段、非共享的讀/寫內存頁和其他有用的信息的minidump。包含了通過minidump能夠得到
的最多的信息。是一種折中方案。
========
?WINDBG調試DUMP文件
http://blog.csdn.net/vah101/article/details/5916384? ? 對于windows程序員來說,程序運行時藍屏是最郁悶的事情,如何找到藍屏的原因則是首要解決的事
情,好在微軟提供了一系列的方法,為我們調試藍屏提供了便利。
? ? 首先要用的工具是windbg,可以到微軟的官方網站下載
? ? http://msdl.microsoft.com/download/symbols/debuggers/dbg_x86_6.11.1.402.msi
? ? 再需要下載并安裝一個符號鏈接庫,微軟官方網站也有提供,這個要根據你所調試系統的版本來選
擇
? ? http://www.microsoft.com/whdc/devtools/debugging/symbolpkg.mspx#d
? ? 也可以不下載這個符號庫,直接讓windbg自己去網上下符號鏈接信息。
? ? 工具軟件準備好了,就可以開始設置了,首先進入 “我的電腦”->“屬性”->“高級”,選擇“啟
動和故障恢復”選項卡,在“寫入調試信息”一欄選擇dump文件的轉儲方式,在“轉儲文件”中填入
dump文件的保存路徑。當出現藍屏時,系統就會保存現場,將dump時的運行信息保存起來,以便我們用
windbg來分析。有一條要注意,如果選擇了完全內存轉儲,系統將會把內存中的所有信息都存進文件中
,這會相當緩慢,所以你能看到藍色屏幕上有一個跳動的數字,那就是保存的進度,必須耐心等待它保
存到100%。
? ? ? 當藍屏再次發生的時候,我們手上就有了dump文件了,通常在windows目錄下的MEMORY.DMP,或者
在windows下的miniDump文件夾中,以*.dmp的形式保存。把.dmp文件拷貝出來,就可以用windbg來調試
。
? ? ? 首先,需要設置一下windbg的符號庫,進入windbg的"File"->"Symbol File Path",在對話框的
“symbol path”里面輸入剛才下載的符號庫的安裝目錄,最省心的方法是在這里填入
SRV*c:/temp*http://msdl.microsoft.com/download/symbols就可以讓windbg自動去下載所需要的符號
信息。
? ? ? 將這里設置完,就可以開始調試.dmp文件了,打開“File”->“Open Crase Dump”,選擇一
個.dmp文件,windbg就開始下載符號庫并進行初步的分析,當出現
*******************************************************************************
* ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* ? ? ? ? ? ? ? ? ? ? ? ?Bugcheck Analysis ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*
* ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
*******************************************************************************
Use !analyze -v to get detailed debugging information.
BugCheck 1000007F, {8, f772ffe0, 0, 0}
Probably caused by : bxnd52x.sys ( bxnd52x+365f )
Followup: MachineOwner
---------
就可以在下面的輸入框中敲入
!analyze -v;r;kv;lmtn;.logclose;
回車后就可以看到結果,比如我這里看到
BUGCHECK_STR: ?0x7f_8
CUSTOMER_CRASH_COUNT: ?3
DEFAULT_BUCKET_ID: ?DRIVER_FAULT_SERVER_MINIDUMP
CURRENT_IRQL: ?2
LAST_CONTROL_TRANSFER: ?from 00000000 to f759a65f
STACK_TEXT: ?
f78dc000 00000000 00000000 00000000 00000000 bxnd52x+0x365f
STACK_COMMAND: ?kb
FOLLOWUP_IP:?
bxnd52x+365f
f759a65f 53 ? ? ? ? ? ? ?push ? ?ebx
SYMBOL_STACK_INDEX: ?0
SYMBOL_NAME: ?bxnd52x+365f
FOLLOWUP_NAME: ?MachineOwner
MODULE_NAME: bxnd52x
IMAGE_NAME: ?bxnd52x.sys
DEBUG_FLR_IMAGE_TIMESTAMP: ?44a55446
FAILURE_BUCKET_ID: ?0x7f_8_bxnd52x+365f
BUCKET_ID: ?0x7f_8_bxnd52x+365f
Followup: MachineOwner
---------
? 說明藍屏可能是由于bxnd52x.sys驅動的問題造成的,上網百度了一下,這個 bxnd52x.sys是網卡驅動
,下載了一個更高版本的驅動重新安裝,藍屏的問題就解決了。 ?
========
使用Windbg解析dump文件
http://blog.csdn.net/xuleilx/article/details/17622627第一章 常用的Windbg指令
①!analyze -v?②kP ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 可以看函數的入參
③!for_each_frame dv /t ? ? ? ? ? ? ? ? ? ? ? ? ? ?可以看函數中的局部變量
④dc , db ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?產看某一內存中的值 ? ?可以直接接變量名?
不過可能需要回溯棧
⑤!threads ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 顯示所有線程
⑥~0s , ~1s ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 進入某個線程
⑦!frame ProcessA!FunctionA ? ? ? ? ? ? ? ? ? ? ? ?查看某一變量有時需要。 回溯棧 ?
⑧!uniqstack ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 擴展命令顯示當前進程中所有線程的調用堆棧
,除開重復的那些。 ??
⑨!teb ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 擴展以的格式化后的形式顯示線程環境塊
(TEB)的信息。?
⑩s-sa 和 s-su ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 命令搜索未指定的 ASCII 和 Unicode 字符串
。這在檢查某段內存是否包含可打印字符時有用。
?dds、dps 和 dqs 命令顯示給定范圍內存的內容。 ? ? 該內存被假定為符號表中的一連串地址。相應
的符號也會被顯示出來。命令顯示給定范圍內存的內容,它們是把內存區域轉儲出來,并把內存中每個元
素都視為一個符號對其進行解析,dds是四字節視為一個符號,dqs是每8字節視為一個符號,dps是根據
當前處理器架構來選擇最合適的長度
?.kframes ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?命令設置堆?;厮蒿@示的默認長度。默認20
?k, kb, kd, kp, kP, kv (Display Stack Backtrace) k*命令顯示給定線程的調用堆棧,以及其他相
關信息。通常要結合12)使用否則顯示出來的東西很少
?.reload /i xxx.dll ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?忽略.pdb 文件版本不匹配的情況。
第二章 Symbol的設置方法
2.1 將遠程的系統函數的PDB文件拷貝到本地「D:\mysymbol」目錄下? ? SRV*D:\mysymbol*http://msdl.microsoft.com/download/symbols
2.2 加載設置的符號文件
? ? .reload
? ? 可以使用菜單中的 Debug -> Modules 查看有沒有加載進來
第三章 實例
實例1 如何調查堆被破壞問題。
? ? 錯誤代碼:0xc0000374
? ? 錯誤含義:ACTIONABLE_HEAP_CORRUPTION_heap_failure_buffer_overrun
第一步、先用「!analyze -v」分析出錯誤的地方以及由于什么原因導致程序Dump掉的。
? ? ? ?無非是內存溢出,訪問非法地址等幾種。
0:009> !analyze -v
*******************************************************************************
* ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* ? ? ? ? ? ? ? ? ? ? ? ?Exception Analysis ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
*******************************************************************************
GetPageUrlData failed, server returned HTTP status 404
URL requested:?
http://watson.microsoft.com/StageOne/ProcessA_exe/1_0_0_1/5134aefd/ntdll_dll/6_1_7601_18229
/51fb164a/c0000374/000c4102.htm?Retriage=1
FAULTING_IP:?
ntdll!RtlReportCriticalFailure+62
00000000`777b4102 eb00 ? ? ? ? ? ?jmp ? ? ntdll!RtlReportCriticalFailure+0x64?
(00000000`777b4104)
EXCEPTION_RECORD: ?ffffffffffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 00000000777b4102 (ntdll!RtlReportCriticalFailure+0x0000000000000062)
? ?ExceptionCode: c0000374
? ExceptionFlags: 00000001
NumberParameters: 1
? ?Parameter[0]: 000000007782b4b0
PROCESS_NAME: ?ProcessA.exe
ERROR_CODE: (NTSTATUS) 0xc0000374 - <Unable to get error code text>
EXCEPTION_CODE: (NTSTATUS) 0xc0000374 - <Unable to get error code text>
EXCEPTION_PARAMETER1: ?000000007782b4b0
MOD_LIST: <ANALYSIS/>
NTGLOBALFLAG: ?0
APPLICATION_VERIFIER_FLAGS: ?0
FAULTING_THREAD: ?0000000000002f8c
DEFAULT_BUCKET_ID: ?ACTIONABLE_HEAP_CORRUPTION_heap_failure_buffer_overrun
PRIMARY_PROBLEM_CLASS: ?ACTIONABLE_HEAP_CORRUPTION_heap_failure_buffer_overrun
BUGCHECK_STR: ?APPLICATION_FAULT_ACTIONABLE_HEAP_CORRUPTION_heap_failure_buffer_overrun
LAST_CONTROL_TRANSFER: ?from 00000000777b4746 to 00000000777b4102
STACK_TEXT: ?
00000000`0548e170 00000000`777b4746 : 00000000`00000002 00000000`00000023 00000000`00000000?
00000000`00000003 : ntdll!RtlReportCriticalFailure+0x62
00000000`0548e240 00000000`777b5952 : 00000000`00000000 00000000`00000000 00000000`00000000?
00000000`1c01001d : ntdll!RtlpReportHeapFailure+0x26
00000000`0548e270 00000000`777b7604 : 00000000`00c50000 00000000`00c50000 00000000`0000000a?
00000000`00000000 : ntdll!RtlpHeapHandleError+0x12
00000000`0548e2a0 00000000`777b79e8 : 00000000`00c50000 00000000`00000000 00000000`00100000?
00000000`00000000 : ntdll!RtlpLogHeapFailure+0xa4
00000000`0548e2d0 00000000`7774fad6 : 00000000`00c50000 00000000`00c59e50 00000000`00c50000?
00000000`00000000 : ntdll!RtlpAnalyzeHeapFailure+0x3a8
00000000`0548e330 00000000`777434d8 : 00000000`00c50000 00000000`00000003 00000000`000006cc?
00000000`000006e0 : ntdll!RtlpAllocateHeap+0x1d2a
00000000`0548e8d0 00000000`777247ea : 00000000`00000003 00000000`00c5ee80 00000000`00c50278?
00000000`000006cc : ntdll!RtlAllocateHeap+0x16c
00000000`0548e9e0 00000000`77723ff2 : 00000000`00c50000 00000000`00000003 00000000`00c5ee90?
00000000`000006cc : ntdll!RtlpReAllocateHeap+0x648
00000000`0548eca0 00000000`750c712f : 00000000`0548fbe8 00000000`00c5ee90 00000000`00000000?
00000000`000005ac : ntdll!RtlReAllocateHeap+0xa2
00000000`0548edb0 00000001`40010f6f : 00000000`00000000 00000000`0548fbe8 00000000`00000000?
00000000`00000661 : msvcr80!realloc+0x6f [f:\dd\vctools\crt_bld\self_64_amd64\crt\src
\realloc.c @ 332]
00000000`0548ede0 00000001`4000f63c : ffffffff`ffffffff 00000000`0548ff10 00000000`00c97fd0?
00000000`0548fe48 : ProcessA!FunctionA_AnalyzeEventData+0xfcf [e:\ProcessA
\FunctionA_sockserv.cpp @ 1666]
00000000`0548f8a0 00000000`774e652d : 00000000`000002a0 00000000`00000000 00000000`00000000?
00000000`00000000 : ProcessA!FunctionA_SockWork+0xe1c [e:\ProcessA\FunctionA_sockserv.cpp @?
1102]
00000000`0548ff60 00000000`7771c541 : 00000000`00000000 00000000`00000000 00000000`00000000?
00000000`00000000 : kernel32!BaseThreadInitThunk+0xd
00000000`0548ff90 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000?
00000000`00000000 : ntdll!RtlUserThreadStart+0x1d
STACK_COMMAND: ?!heap ; ~9s; .ecxr ; kb
FOLLOWUP_IP:?
msvcr80!realloc+6f [f:\dd\vctools\crt_bld\self_64_amd64\crt\src\realloc.c @ 332]
00000000`750c712f 4885c0 ? ? ? ? ?test ? ?rax,rax
SYMBOL_STACK_INDEX: ?9
SYMBOL_NAME: ?msvcr80!realloc+6f
FOLLOWUP_NAME: ?MachineOwner
MODULE_NAME: msvcr80
IMAGE_NAME: ?msvcr80.dll
DEBUG_FLR_IMAGE_TIMESTAMP: ?4ec3407e
FAILURE_BUCKET_ID: ?
ACTIONABLE_HEAP_CORRUPTION_heap_failure_buffer_overrun_c0000374_msvcr80.dll!realloc
BUCKET_ID: ?
X64_APPLICATION_FAULT_ACTIONABLE_HEAP_CORRUPTION_heap_failure_buffer_overrun_msvcr80!
realloc+6f
WATSON_STAGEONE_URL: ?
http://watson.microsoft.com/StageOne/ProcessA_exe/1_0_0_1/5134aefd/ntdll_dll/6_1_7601_18229
/51fb164a/c0000374/000c4102.htm?Retriage=1
Followup: MachineOwner
---------
第二步、使用「!heap」找出出錯的堆。分析出錯的原因。
? ? ? ?0000000000c59c80
? ? ? ?0000000000c59e50 ?←出錯的堆地址。
? ? ? ?0000000000c59fd0
大家應該有這樣的常識,在使用malloc()或者realloc()分配出來的空間的前面都有
相應的管理情報,用來記錄這塊分配的內存的大小以及返回的時候用的情報。
從這里很自然的猜想到,在寫往0000000000c59c80里面寫數據的時候寫過了,
寫到0000000000c59e50上去了,導致它的管理情報被覆蓋了。從而程序dump掉了。
0:009> !heap
**************************************************************
* ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*
* ? ? ? ? ? ? ? ? ?HEAP ERROR DETECTED ? ? ? ? ? ? ? ? ? ? ? *
* ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*
**************************************************************
Details:
Heap handle: 0000000000c50000
Error type heap_failure_buffer_overrun (6)
Parameter 1: 000000000000000a
Last known valid blocks: before - 0000000000c59c80, after -0000000000c59fd0
Stack trace:
? ? ? ? ? ? ? ? 00000000777b79e8: ntdll!RtlpAnalyzeHeapFailure+0x00000000000003a8
? ? ? ? ? ? ? ? 000000007774fad6: ntdll!RtlpAllocateHeap+0x0000000000001d2a
? ? ? ? ? ? ? ? 00000000777434d8: ntdll!RtlAllocateHeap+0x000000000000016c
? ? ? ? ? ? ? ? 00000000777247ea: ntdll!RtlpReAllocateHeap+0x0000000000000648
? ? ? ? ? ? ? ? 0000000077723ff2: ntdll!RtlReAllocateHeap+0x00000000000000a2
? ? ? ? ? ? ? ? 00000000750c712f: msvcr80!realloc+0x000000000000006f
? ? ? ? ? ? ? ? 0000000140010f6f: ProcessA!FunctionA_AnalyzeEventData+0x0000000000000fcf
? ? ? ? ? ? ? ? 000000014000f63c: ProcessA!FunctionA_SockWork+0x0000000000000e1c
? ? ? ? ? ? ? ? 00000000774e652d: kernel32!BaseThreadInitThunk+0x000000000000000d
? ? ? ? ? ? ? ? 000000007771c541: ntdll!RtlUserThreadStart+0x000000000000001d
Index ? Address ?Name ? ? ?Debugging options enabled
? 1: ? 001f0000 ? ? ? ? ? ? ? ?
? 2: ? 00010000 ? ? ? ? ? ? ? ?
? 3: ? 00020000 ? ? ? ? ? ? ? ?
? 4: ? 00670000 ? ? ? ? ? ? ? ?
? 5: ? 00950000 ? ? ? ? ? ? ? ?
? 6: ? 00c50000 ? ? ? ? ? ? ? ?
? 7: ? 00910000 ? ? ? ? ? ? ? ?
? 8: ? 00bc0000 ? ? ? ? ? ? ? ?
? 9: ? 010e0000 ? ? ? ? ? ? ? ?
?10: ? 01220000 ? ? ? ? ? ? ? ?
?11: ? 01420000 ? ? ? ? ? ? ? ?
?12: ? 00c30000 ? ? ? ? ? ? ? ?
?13: ? 03660000 ? ? ? ? ? ? ? ?
?14: ? 00ba0000 ? ? ? ? ? ? ? ?
?15: ? 037b0000 ? ? ? ? ? ? ? ?
?16: ? 01340000 ? ? ? ? ? ? ? ?
?17: ? 039a0000 ? ? ? ? ? ? ? ?
第三步、使用「!for_each_frame dv /t」打印出錯函數的局部變量,找出元兇。
? ? ? ?從下面的變量里面找到距離0000000000c59c80地址最近的變量,對了就是它:
? ? ? ?char * pData_n = 0x00000000`00c59c90 "SE:Security: ???"
? ? ? ?※注意如果變量值指針的指針需要先用dc看一下該指針指向的地址。
? ? ? ?之后看代碼知道,程序在讀取pData_n的數據的時候如果遇到是0a(Windos換行符)就自動在后面
加上
? ? ? ?0d變成0a0d。導致pData_n內存越界了。
0:009> !for_each_frame dv /t
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
12 00000000`0548edb0 00000001`40010f6f msvcr80!realloc+0x6f [f:\dd\vctools\crt_bld
\self_64_amd64\crt\src\realloc.c @ 332]
void * pBlock = 0x00000000`00000000
unsigned int64 newsize = 0x548fbe8
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
13 00000000`0548ede0 00000001`4000f63c ProcessA!FunctionA_AnalyzeEventData+0xfcf [e:
\ProcessA\FunctionA_sockserv.cpp @ 1666]
void * cd = 0xffffffff`ffffffff
struct _MpEvsHead * Head = 0x00000000`0548ff10
char * pEventData = 0x00000000`00c97fd0 "???"
char ** pNewData = 0x00000000`0548fe48
char * SiteName = 0x00000000`0548fe18 ""
int oval_check = 0n0
char * pszHostIp = 0x00000000`0548fbf0 "192.168.1.1"
int j = 0n469
int NodeName_check = 0n0
char [2068] eventtext = char [2068] "SE:Security: ???"
unsigned long err = 0
int NL_henkan = 0n1
int Evttxt_check = 0n1
char [129] nameWork = char [129] "`_???"
int ret = 0n0
struct NameObject_t * pNameObj_n = 0x00000000`00c5eee8
char * pData_n = 0x00000000`00c59c90 "SE:Security: ???"
long lWork = 0n9
char [257] szTrcBuff = char [257] "safely divided text.([453]bytes --> [469]bytes)"
long nNameNum = 0n44
long nNewLen = 0n1740
struct NameObject_t * pNameObj_o = 0x00000000`00c98028
char * pData_o = 0x00000000`00c984c6 "SE:Security: ???"
char * pt = 0x00000000`00c59e55 "[???"
long i = 0n20
int IpAddr_check = 0n0
int res = 0n1
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
14 00000000`0548f8a0 00000000`774e652d ProcessA!FunctionA_SockWork+0xe1c [e:\ProcessA
\FunctionA_sockserv.cpp @ 1102]
void * ns = 0x00000000`000002a0
char * pRead_str = 0x00000000`00c562f0 ","
int bTableRegisterd = 0n0
unsigned long err = 0
char [3] traceflg = char [3] ""
int ret = 0n0
short sWork = 0n2
int oval_check = 0n0
char * pNewData = 0x00000000`00c5ee90 "???"
char * wk = 0x00000000`0548f930 "192.168.1.1"
char [33] SiteName = char [33] ""
long lWork = 0n2032
char [257] szTrcBuff = char [257] "recv event OK"
int iLastSerchedIndex = 0n0
char [256] HostIp = char [256] "192.168.1.1"
int ret2 = 0n0
struct _MpEvsHead Head = struct _MpEvsHead
long nDataLen = 0n3
char [257] szTrcBuff2 = char [257] ""
char [20] szSendData = char [20] "OK"
struct addrinfo hinst = struct addrinfo
int conv_disc_set = 0n1
long lRc = 0n0
void * conv_disc = 0xffffffff`ffffffff
int res = 0n1
char * pData = 0x00000000`00c97fd0 "???"
long nRead = 0n3726
char [16] evttype = char [16] "Alarm.sys"
char * lpszEventid = 0x00000000`00c5f180 ""
long nSend = 0n12
char [256] ipTmp = char [256] "192.168.1.1"
char [20] szToCode = char [20] "sjis"
char [20] szFromCode = char [20] "sjis"
int bWriteEvent = 0n1
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
實例2 ?無效參數(STATUS_INVALID_PARAMETER)。
? ? 錯誤代碼:0xc000000d
? ? 錯誤含義:STATUS_INVALID_PARAMETER
第一步、先用「!analyze -v」分析出錯誤的地方以及由于什么原因導致程序Dump掉的。
?
0:000> !analyze -v
*******************************************************************************
* ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* ? ? ? ? ? ? ? ? ? ? ? ?Exception Analysis ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
* ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *
*******************************************************************************
*** ERROR: Symbol file could not be found. ?Defaulted to export symbols for user32.dll -?
Unable to load image C:\Windows\Odsv.dll, Win32 error 0n2
*** WARNING: Unable to verify timestamp for Odsv.dll
*** ERROR: Module load completed but symbols could not be loaded for Odsv.dll
GetPageUrlData failed, server returned HTTP status 404
URL requested:?
http://watson.microsoft.com/StageOne/ProcessB_exe/1_0_0_1/4e362265/msvcr80_dll/8_0_50727_61
95/4dcdd833/c000000d/0001d5fa.htm?Retriage=1
FAULTING_IP:?
msvcr80!strncpy_s+10a [f:\dd\vctools\crt_bld\self_64_amd64\crt\src\tcsncpy_s.inl @ 62]
00000000`74e6d5fa b822000000 ? ? ?mov ? ? eax,22h
EXCEPTION_RECORD: ?ffffffffffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 0000000074e6d5fa (msvcr80!strncpy_s+0x000000000000010a)
? ?ExceptionCode: c000000d
? ExceptionFlags: 00000000
NumberParameters: 0
PROCESS_NAME: ?ProcessB.exe
ERROR_CODE: (NTSTATUS) 0xc000000d - <Unable to get error code text>
EXCEPTION_CODE: (NTSTATUS) 0xc000000d - <Unable to get error code text>
MOD_LIST: <ANALYSIS/>
NTGLOBALFLAG: ?0
LAST_CONTROL_TRANSFER: ?from 0000000000124250 to 0000000074e5b0ec
FAULTING_THREAD: ?ffffffffffffffff
DEFAULT_BUCKET_ID: ?STATUS_INVALID_PARAMETER
PRIMARY_PROBLEM_CLASS: ?STATUS_INVALID_PARAMETER
BUGCHECK_STR: ?APPLICATION_FAULT_STATUS_INVALID_PARAMETER
IP_ON_STACK:?
+2e32faf01dedf58
00000000`00124250 60 ? ? ? ? ? ? ????
FRAME_ONE_INVALID: 1
STACK_TEXT: ?
00000000`00124220 00000000`00124250 : 00000000`00000006 00000000`00000000 00000000`00000001?
00000000`00000000 : msvcr80!_invalid_parameter+0x6c [f:\dd\vctools\crt_bld
\self_64_amd64\crt\src\invarg.c @ 88]
00000000`00124228 00000000`00000006 : 00000000`00000000 00000000`00000001 00000000`00000000?
00000000`00000000 : 0x124250
00000000`00124230 00000000`00000000 : 00000000`00000001 00000000`00000000 00000000`00000000?
00000000`00124260 : 0x6
STACK_COMMAND: ?~0s; .ecxr ; kb
FOLLOWUP_IP:?
msvcr80!strncpy_s+10a [f:\dd\vctools\crt_bld\self_64_amd64\crt\src\tcsncpy_s.inl @ 62]00000000`74e6d5fa b822000000 ? ? ?mov ? ? eax,22h
FAULTING_SOURCE_CODE: ?
No source found for 'f:\dd\vctools\crt_bld\self_64_amd64\crt\src\tcsncpy_s.inl'
SYMBOL_STACK_INDEX: ?0
SYMBOL_NAME: ?msvcr80!strncpy_s+10a
FOLLOWUP_NAME: ?MachineOwner
MODULE_NAME: msvcr80
IMAGE_NAME: ?msvcr80.dll
DEBUG_FLR_IMAGE_TIMESTAMP: ?4dcdd833
FAILURE_BUCKET_ID: ?STATUS_INVALID_PARAMETER_c000000d_msvcr80.dll!strncpy_s
BUCKET_ID: ?X64_APPLICATION_FAULT_STATUS_INVALID_PARAMETER_msvcr80!strncpy_s+10a
WATSON_STAGEONE_URL: ?
http://watson.microsoft.com/StageOne/ProcessB_exe/1_0_0_1/4e362265/msvcr80_dll/8_0_50727_61
95/4dcdd833/c000000d/0001d5fa.htm?Retriage=1
Followup: MachineOwner
---------
這次運氣很不好,從「!analyze -v」打出來的結果來看看不出啥東西來,只知道
在調用strncpy_s的時候dmp掉了,無法定位具體是哪個函數出錯的原因很多,有可能
客戶采集的不是全dmp文件或者dmp文件中的棧被破壞了。 ??
這的確很傷腦筋,就針對這個我可是花了3個星期一行行的解析棧里面的內容 才解決的。
第二步、先用「!teb」看一下這個程序的棧是從哪里到哪里的。
0:000>!teb
TEB at 000007ffffeee000
? ? ExceptionList: ? ? ? ?0000000000000000
? ? StackBase: ? ? ? ? ? ?0000000008d50000
? ? StackLimit: ? ? ? ? ? 0000000008d4d000
? ? SubSystemTib: ? ? ? ? 0000000000000000
? ? FiberData: ? ? ? ? ? ?0000000000001e00
? ? ArbitraryUserPointer: 0000000000000000
? ? Self: ? ? ? ? ? ? ? ? 000007ffffeee000
? ? EnvironmentPointer: ? 0000000000000000
? ? ClientId: ? ? ? ? ? ? 0000000000001bdc . 0000000000001868
? ? RpcHandle: ? ? ? ? ? ?0000000000000000
? ? Tls Storage: ? ? ? ? ?000007ffffeee058
? ? PEB Address: ? ? ? ? ?000007fffffd6000
? ? LastErrorValue: ? ? ? 87
? ? LastStatusValue: ? ? ?c000000d
? ? Count Owned Locks: ? ?0
? ? HardErrorMode: ? ? ? ?0
第三步、先用「dps」看一下這個程序的棧中的內存的內容。 下面截取其中比較重要的一段。
-------------------------------------------------------------------------------------------
------------------------------------
00000000`001247d8 ?00000000`74e6d5fa msvcr80!strncpy_s+0x10a [f:\dd\vctools\crt_bld
\self_64_amd64\crt\src\tcsncpy_s.inl @ 62]
00000000`001247e0 ?00000000`009c01e0
00000000`001247e8 ?00000000`030f5810
00000000`001247f0 ?00000000`0057e310 ProcessB2!work
★「ProcessB2!work」的內容本應該是像這樣的數據「DNxxxxxxxx_150_109」
但是現在「ProcessB2!work」中的內容卻是「VIP_rtcrx00184-004a/b-y3b-d」這個。
00000000`001247f8 ?00000000`005782c0 ProcessB2!trcData
▲「ProcessB2!trcData」的內容是「Function:testB call」。
?函數List::testB の trace("testB", __FILE__, __LINE__, TRCLV_3);
00000000`00124800 ?00000000`00000000
00000000`00124808 ?00000000`00000000
00000000`00124810 ?00000000`004a3150 ProcessB2!`string'
▲「 ProcessB2!`string'」的內容是「e:\ProcessB\FunctionB.cpp __FILE__」。
00000000`00124818 ?00000000`00455b65 ProcessB2!List::testB+0x55 [e:\ProcessB\Listset.cpp @?
719]
00000000`00124820 ?00000000`009c01e0
00000000`00124828 ?00000000`030f5810
00000000`00124830 ?00000000`0057e310 ProcessB2!work
00000000`00124838 ?00000000`001249e0
00000000`00124840 ?32322e35`322e3000
00000000`00124848 ?30614031`33312e34
00000000`00124850 ?7097fb8e`bc923730
00000000`00124858 ?5049565f`5753334c
00000000`00124860 ?00000000`0000125f
00000000`00124868 ?000082bd`b1200d5e
00000000`00124870 ?00000000`009c01e0
00000000`00124878 ?00000000`00467bda ProcessB2!FunctionB+0x73a [e:\ProcessB\FunctionB.cpp @?
181] ??
-------------------------------------------------------------------------------------------
------------------------------------
這里終于定位到是哪個函數出問題。搞清楚這些函數的功能,然后打印出所有可能打印的內容,發現
函數傳遞了一個不合法的數據。在這里要說一下為啥傳的數據不合法就會Dmp掉。
首先strncpy 這個函數在使用的時候只要有個宏定義(默認是有的)在編譯的時候就會使用strncpy_s這個
安全函數。
詳情可以參考下面微軟的說明文檔。
http://msdn.microsoft.com/zh-cn/LIBRARY/ms175759(v=vs.80)
其次說明一下為什么會dmp掉。strncpy在使用的時候如果轉化成strncpy_s的時候是這樣一種形式。
char dst[5];
strncpy(dst, "a long string", 5); ? ?----> ?strncpy_s(dst, 5, "a long string", 5);
而這樣就會到時報STATUS_INVALID_PARAMETER這個錯誤這是strncpy_s的特性。具體使用方法可以參考下
面的文檔。
http://msdn.microsoft.com/zh-cn/library/5dae5d43(v=vs.90).aspx
節選:
char dst[5];
strncpy_s(dst, 5, "a long string", 5);
means that we are asking strncpy_s to copy five characters into a buffer five bytes long;?
this would leave no space for the null terminator, hence strncpy_s zeroes out the string?
and calls the invalid parameter handler.
If truncation behavior is needed, use _TRUNCATE or (size – 1):
strncpy_s(dst, 5, "a long string", _TRUNCATE);
strncpy_s(dst, 5, "a long string", 4);
詳細的ACTIONABLE_HEAP_CORRUPTION_heap_failure_buffer_overrun方法還可以參考以下的例子:
http://blogs.msdn.com/b/jiangyue/archive/2010/03/16/windows-heap-overrun-monitoring.aspx
========
?windbg分析dump文件
http://blog.csdn.net/xiaoshahai/article/details/7284867/前言:WinDbg是微軟開發的免費源代碼級的調試工具。WinDbg可以用于Kernel模式調試和用戶模式調試
,還可以調試Dump文件。本文的討論是在安裝了Debugging Tools for Windows 的前提下進行的,下載
地址可以參考我之前的文章。WinDbg對于dump文件的調試可以通過菜單設置Symbol File Path、Source?
File Path ,并可設置多個路徑。
1、 ?打開Dump格式文件
打開WinDbg,通過菜單[File] à [Open Crash dump] 選擇dump文件打開,也可通過CMD打開Dos命令窗口
,切換到WinDbg所在目錄,利用命令:
WinDbg –z “D:/Lines2009-7-25-22-20-33-900.dmp”
-z表示路徑
clip_image001
圖1.1 利用WinDbg打開dump文件
本文編寫了一個簡單能產生除數為0異常的程序,讓其運行,產生崩潰,通過drwtsn產生dmp文件,然后
通過windbg分析dmp文件,定位程序bug。
目的:學習windbg基本功能使用。
程序源代碼:
void Crash(void) {int i = 1;int j = 0;i /= j; }void main(void) {Crash(); }
編譯環境:vc++6.0
編譯器設置:
?這一步設置,要求對release版本不使用優化,如果使用優化,上面源代碼中Crash(void)函數將不被匯
編。
這一步設置,產生release版本的調試符號表,為后續定位錯誤準備。
步驟:
1、 安裝drwtsn32
用戶可以通過drwtsn32命令,查看dmp文件會被保存在何處。
2、 安裝windbg,Windbg下載地址:
http://www.microsoft.com/whdc/devtools/debugging/default.mspx
3、 設置windbg
A、符號表路徑設置
其中;srv*d:/symbolslocal*http://msdl.microsoft.com/download/symbols設置的目的是下載該程序用
到的操作系統相關的庫函數的符號表到本地。
B、源代碼路徑設置
C、dmp文件導入
載入dump文件顯示如圖:
clip_image002
圖1.2 WinDbg界面
2、 ?分析dump文件
若生成的dump文件在本機,dump文件中將包含調試需要的PDB文件及源代碼路徑,若不在本機,可以通過
WinDbg菜單[File] à [Symbol File path] 及 [Source File Path] 分別設置PDB文件路徑和源代碼路徑
。如果程序涉及到DLL,需要將EXE、DLL所有涉及的PDB、源代碼路徑都包括。使用命令:
!analyze –v
將分析dump文件,并顯示程序崩潰處于的代碼行:
clip_image003
圖1.3 分析dump 文件
========
?調試技巧 —— 如何利用windbg + dump + map分析程序異常
http://blog.csdn.net/xiaoshahai/article/details/7285103之前碰到論壇里有幾個好友,說程序不時的崩潰,什么xxoo不能read的! 如果光要是這個內存地址,估
計你會瘋掉~~
所以分享一下基本的調試技巧,需要準備的工具有WinDbg + VC6.0,
下面是自己整理的一份自動生成DUMP文件的源代碼,只需要添加到工程即可,源代碼如下:
MiniDump.h
[cpp] view plaincopy?
#include <windows.h> ?
#include <tlhelp32.h> ?
??
//#include "dbghelp.h" ?
//#define DEBUG_DPRINTF ? ? 1 ? //allow d() ?
//#include "wfun.h" ?
??
#pragma optimize("y", off) ? ? ?//generate stack frame pointers for all functions - same as?
/Oy- in the project ?
#pragma warning(disable: 4200) ?//nonstandard extension used : zero-sized array in?
struct/union ?
#pragma warning(disable: 4100) ?//unreferenced formal parameter ?
??
/*BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, PCHAR Module_Name, PBYTE &?
Module_Addr);?
int ?WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, PCHAR Str);?
int ?WINAPI Get_Version_Str(PCHAR Str);?
PCHAR WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException);?
void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag);*/ ?
??
// In case you don't have dbghelp.h. ?
#ifndef _DBGHELP_ ?
??
typedef struct _MINIDUMP_EXCEPTION_INFORMATION { ?
? ? DWORD ? ThreadId; ?
? ? PEXCEPTION_POINTERS ExceptionPointers; ?
? ? BOOL ? ?ClientPointers; ?
} MINIDUMP_EXCEPTION_INFORMATION, *PMINIDUMP_EXCEPTION_INFORMATION; ?
??
typedef enum _MINIDUMP_TYPE { ?
? ? MiniDumpNormal = ? ? ? ? ? ?0x00000000, ?
? ? ? ? MiniDumpWithDataSegs = ? ? ?0x00000001, ?
} MINIDUMP_TYPE; ?
??
typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)( ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IN HANDLE ? ? ? ? ? hProcess, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IN DWORD ? ? ? ? ? ?ProcessId, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IN HANDLE ? ? ? ? ? hFile, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IN MINIDUMP_TYPE ? ?DumpType, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IN CONST PMINIDUMP_EXCEPTION_INFORMATION ? ?
ExceptionParam, OPTIONAL ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IN PVOID ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
UserStreamParam, OPTIONAL ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IN PVOID ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
CallbackParam OPTIONAL ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ); ?
??
#else ?
??
typedef BOOL (WINAPI * MINIDUMP_WRITE_DUMP)( ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IN HANDLE ? ? ? ? ? hProcess, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IN DWORD ? ? ? ? ? ?ProcessId, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IN HANDLE ? ? ? ? ? hFile, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IN MINIDUMP_TYPE ? ?DumpType, ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IN CONST PMINIDUMP_EXCEPTION_INFORMATION ? ?
ExceptionParam, OPTIONAL ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IN PMINIDUMP_USER_STREAM_INFORMATION ? ? ? ?
UserStreamParam, OPTIONAL ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? IN PMINIDUMP_CALLBACK_INFORMATION ? ? ? ? ??
CallbackParam OPTIONAL ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ); ?
#endif //#ifndef _DBGHELP_ ?
??
// Tool Help functions. ?
typedef HANDLE (WINAPI * CREATE_TOOL_HELP32_SNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID); ?
typedef BOOL (WINAPI * MODULE32_FIRST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); ?
typedef BOOL (WINAPI * MODULE32_NEST)(HANDLE hSnapshot, LPMODULEENTRY32 lpme); ?
??
??extern void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL?
Show_Flag); ?
??
extern HMODULE ?hDbgHelp; ?
extern MINIDUMP_WRITE_DUMP ?MiniDumpWriteDump_; ?
??
extern CREATE_TOOL_HELP32_SNAPSHOT ?CreateToolhelp32Snapshot_; ?
extern MODULE32_FIRST ? Module32First_; ?
extern MODULE32_NEST ? ?Module32Next_; ?
MiniDump.cpp
/*?
? ? Author: Vladimir Sedach.?
?
? ? Purpose: demo of Call Stack creation by our own means,?
? ? and with MiniDumpWriteDump() function of DbgHelp.dll.?
*/ ?
??
#include "StdAfx.h" ?
#include "MiniDump.h" ?
#include <Shlwapi.h> ?
??
#pragma comment(lib,"shlwapi.lib") ?
??
HMODULE hDbgHelp; ?
MINIDUMP_WRITE_DUMP MiniDumpWriteDump_; ?
??
CREATE_TOOL_HELP32_SNAPSHOT CreateToolhelp32Snapshot_; ?
MODULE32_FIRST ?Module32First_; ?
MODULE32_NEST ? Module32Next_; ?
??
#define DUMP_SIZE_MAX ? 8000 ? ?//max size of our dump ?
#define CALL_TRACE_MAX ?((DUMP_SIZE_MAX - 2000) / (MAX_PATH + 40)) ?//max number of traced?
calls ?
#define NL ? ? ? ? ? ? ?"\r\n" ?//new line ?
??
extern CString GetExePath(); ?
??
//**************************************************************************************** ?
BOOL WINAPI Get_Module_By_Ret_Addr(PBYTE Ret_Addr, PCHAR Module_Name, PBYTE & Module_Addr) ?
//**************************************************************************************** ?
// Find module by Ret_Addr (address in the module). ?
// Return Module_Name (full path) and Module_Addr (start address). ?
// Return TRUE if found. ?
{ ?
? ? MODULEENTRY32 ? M = {sizeof(M)}; ?
? ? HANDLE ?hSnapshot; ?
??
? ? Module_Name[0] = 0; ?
? ? ??
? ? if (CreateToolhelp32Snapshot_) ?
? ? { ?
? ? ? ? hSnapshot = CreateToolhelp32Snapshot_(TH32CS_SNAPMODULE, 0); ?
? ? ? ? ??
? ? ? ? if ((hSnapshot != INVALID_HANDLE_VALUE) && ?
? ? ? ? ? ? Module32First_(hSnapshot, &M)) ?
? ? ? ? { ?
? ? ? ? ? ? do ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? if (DWORD(Ret_Addr - M.modBaseAddr) < M.modBaseSize) ?
? ? ? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? ? ? lstrcpyn(Module_Name, M.szExePath, MAX_PATH); ?
? ? ? ? ? ? ? ? ? ? Module_Addr = M.modBaseAddr; ?
? ? ? ? ? ? ? ? ? ? break; ?
? ? ? ? ? ? ? ? } ?
? ? ? ? ? ? } while (Module32Next_(hSnapshot, &M)); ?
? ? ? ? } ?
??
? ? ? ? CloseHandle(hSnapshot); ?
? ? } ?
??
? ? return !!Module_Name[0]; ?
} //Get_Module_By_Ret_Addr ?
??
//****************************************************************** ?
int WINAPI Get_Call_Stack(PEXCEPTION_POINTERS pException, PCHAR Str) ?
//****************************************************************** ?
// Fill Str with call stack info. ?
// pException can be either GetExceptionInformation() or NULL. ?
// If pException = NULL - get current call stack. ?
{ ?
? ? CHAR ? ?Module_Name[MAX_PATH]; ?
? ? PBYTE ? Module_Addr = 0; ?
? ? PBYTE ? Module_Addr_1; ?
? ? int ? ? Str_Len; ?
? ? ??
? ? typedef struct STACK ?
? ? { ?
? ? ? ? STACK * Ebp; ?
? ? ? ? PBYTE ? Ret_Addr; ?
? ? ? ? DWORD ? Param[0]; ?
? ? } STACK, * PSTACK; ?
??
? ? STACK ? Stack = {0, 0}; ?
? ? PSTACK ?Ebp; ?
??
? ? if (pException) ? ? //fake frame for exception address ?
? ? { ?
? ? ? ? Stack.Ebp = (PSTACK)pException->ContextRecord->Ebp; ?
? ? ? ? Stack.Ret_Addr = (PBYTE)pException->ExceptionRecord->ExceptionAddress; ?
? ? ? ? Ebp = &Stack; ?
? ? } ?
? ? else ?
? ? { ?
? ? ? ? Ebp = (PSTACK)&pException - 1; ?//frame addr of Get_Call_Stack() ?
??
? ? ? ? // Skip frame of Get_Call_Stack(). ?
? ? ? ? if (!IsBadReadPtr(Ebp, sizeof(PSTACK))) ?
? ? ? ? ? ? Ebp = Ebp->Ebp; ? ? ?//caller ebp ?
? ? } ?
??
? ? Str[0] = 0; ?
? ? Str_Len = 0; ?
??
? ? // Trace CALL_TRACE_MAX calls maximum - not to exceed DUMP_SIZE_MAX. ?
? ? // Break trace on wrong stack frame. ?
? ? for (int Ret_Addr_I = 0; ?
? ? ? ? (Ret_Addr_I < CALL_TRACE_MAX) && !IsBadReadPtr(Ebp, sizeof(PSTACK)) && !
IsBadCodePtr(FARPROC(Ebp->Ret_Addr)); ?
? ? ? ? Ret_Addr_I++, Ebp = Ebp->Ebp) ?
? ? { ?
? ? ? ? // If module with Ebp->Ret_Addr found. ?
? ? ? ? if (Get_Module_By_Ret_Addr(Ebp->Ret_Addr, Module_Name, Module_Addr_1)) ?
? ? ? ? { ?
? ? ? ? ? ? if (Module_Addr_1 != Module_Addr) ? //new module ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? // Save module's address and full path. ?
? ? ? ? ? ? ? ? Module_Addr = Module_Addr_1; ?
? ? ? ? ? ? ? ? Str_Len += wsprintf(Str + Str_Len, NL "%08X ?%s", Module_Addr,?
Module_Name); ?
? ? ? ? ? ? } ?
??
? ? ? ? ? ? // Save call offset. ?
? ? ? ? ? ? Str_Len += wsprintf(Str + Str_Len, ?
? ? ? ? ? ? ? ? NL " ?+%08X", Ebp->Ret_Addr - Module_Addr); ?
??
? ? ? ? ? ? // Save 5 params of the call. We don't know the real number of params. ?
? ? ? ? ? ? if (pException && !Ret_Addr_I) ?//fake frame for exception address ?
? ? ? ? ? ? ? ? Str_Len += wsprintf(Str + Str_Len, " ?Exception Offset"); ?
? ? ? ? ? ? else if (!IsBadReadPtr(Ebp, sizeof(PSTACK) + 5 * sizeof(DWORD))) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? Str_Len += wsprintf(Str + Str_Len, " ?(%X, %X, %X, %X, %X)", ?
? ? ? ? ? ? ? ? ? ? Ebp->Param[0], Ebp->Param[1], Ebp->Param[2], Ebp->Param[3], Ebp->Param
[4]); ?
? ? ? ? ? ? } ?
? ? ? ? } ?
? ? ? ? else ?
? ? ? ? ? ? Str_Len += wsprintf(Str + Str_Len, NL "%08X", Ebp->Ret_Addr); ?
? ? } ?
??
? ? return Str_Len; ?
} //Get_Call_Stack ?
??
//*********************************** ?
int WINAPI Get_Version_Str(PCHAR Str) ?
//*********************************** ?
// Fill Str with Windows version. ?
{ ?
? ? OSVERSIONINFOEX V = {sizeof(OSVERSIONINFOEX)}; ?//EX for NT 5.0 and later ?
??
? ? if (!GetVersionEx((POSVERSIONINFO)&V)) ?
? ? { ?
? ? ? ? ZeroMemory(&V, sizeof(V)); ?
? ? ? ? V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); ?
? ? ? ? GetVersionEx((POSVERSIONINFO)&V); ?
? ? } ?
??
? ? if (V.dwPlatformId != VER_PLATFORM_WIN32_NT) ?
? ? ? ? V.dwBuildNumber = LOWORD(V.dwBuildNumber); ?//for 9x HIWORD(dwBuildNumber) = 0x04xx?
??
? ? return wsprintf(Str, ?
? ? ? ? NL "Windows: ?%d.%d.%d, SP %d.%d, Product Type %d", //SP - service pack, Product?
Type - VER_NT_WORKSTATION,... ?
? ? ? ? V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber, V.wServicePackMajor,?
V.wServicePackMinor/*, V.wProductType*/); ?
} //Get_Version_Str ?
??
//************************************************************* ?
PCHAR WINAPI Get_Exception_Info(PEXCEPTION_POINTERS pException) ?
//************************************************************* ?
// Allocate Str[DUMP_SIZE_MAX] and return Str with dump, if !pException - just return call?
stack in Str. ?
{ ?
? ? PCHAR ? ? ? Str; ?
? ? int ? ? ? ? Str_Len; ?
? ? int ? ? ? ? i; ?
? ? CHAR ? ? ? ?Module_Name[MAX_PATH]; ?
? ? PBYTE ? ? ? Module_Addr; ?
? ? HANDLE ? ? ?hFile; ?
? ? FILETIME ? ?Last_Write_Time; ?
? ? FILETIME ? ?Local_File_Time; ?
? ? SYSTEMTIME ?T; ?
? ? ??
? ? Str = new CHAR[DUMP_SIZE_MAX]; ?
??
? ? if (!Str) ?
? ? ? ? return NULL; ?
??
? ? Str_Len = 0; ?
? ? Str_Len += Get_Version_Str(Str + Str_Len); ?
??
? ? Str_Len += wsprintf(Str + Str_Len, NL "Process: ?"); ?
? ? GetModuleFileName(NULL, Str + Str_Len, MAX_PATH); ?
? ? Str_Len = lstrlen(Str); ?
??
? ? // If exception occurred. ?
? ? if (pException) ?
? ? { ?
? ? ? ? EXCEPTION_RECORD & ?E = *pException->ExceptionRecord; ?
? ? ? ? CONTEXT & ? ? ? ? ? C = *pException->ContextRecord; ?
??
? ? ? ? // If module with E.ExceptionAddress found - save its path and date. ?
? ? ? ? if (Get_Module_By_Ret_Addr((PBYTE)E.ExceptionAddress, Module_Name, Module_Addr)) ?
? ? ? ? { ?
? ? ? ? ? ? Str_Len += wsprintf(Str + Str_Len, ?
? ? ? ? ? ? ? ? NL "Module: ?%s", Module_Name); ?
??
? ? ? ? ? ? if ((hFile = CreateFile(Module_Name, GENERIC_READ, FILE_SHARE_READ, NULL,?
OPEN_EXISTING, ?
? ? ? ? ? ? ? ? FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE) ?
? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? if (GetFileTime(hFile, NULL, NULL, &Last_Write_Time)) ?
? ? ? ? ? ? ? ? { ?
? ? ? ? ? ? ? ? ? ? FileTimeToLocalFileTime(&Last_Write_Time, &Local_File_Time); ?
? ? ? ? ? ? ? ? ? ? FileTimeToSystemTime(&Local_File_Time, &T); ?
??
? ? ? ? ? ? ? ? ? ? Str_Len += wsprintf(Str + Str_Len, ?
? ? ? ? ? ? ? ? ? ? ? ? NL "Date Modified: ?%02d/%02d/%d", ?
? ? ? ? ? ? ? ? ? ? ? ? T.wMonth, T.wDay, T.wYear); ?
? ? ? ? ? ? ? ? } ?
? ? ? ? ? ? ? ? CloseHandle(hFile); ?
? ? ? ? ? ? } ?
? ? ? ? } ?
? ? ? ? else ?
? ? ? ? { ?
? ? ? ? ? ? Str_Len += wsprintf(Str + Str_Len, ?
? ? ? ? ? ? ? ? NL "Exception Addr: ?%08X", E.ExceptionAddress); ?
? ? ? ? } ?
? ? ? ? ??
? ? ? ? Str_Len += wsprintf(Str + Str_Len, ?
? ? ? ? ? ? NL "Exception Code: ?%08X", E.ExceptionCode); ?
? ? ? ? ??
? ? ? ? if (E.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) ?
? ? ? ? { ?
? ? ? ? ? ? // Access violation type - Write/Read. ?
? ? ? ? ? ? Str_Len += wsprintf(Str + Str_Len, ?
? ? ? ? ? ? ? ? NL "%s Address: ?%08X", ?
? ? ? ? ? ? ? ? (E.ExceptionInformation[0]) ? "Write" : "Read", E.ExceptionInformation[1]);??
? ? ? ? } ?
??
? ? ? ? // Save instruction that caused exception. ?
? ? ? ? Str_Len += wsprintf(Str + Str_Len, NL "Instruction: "); ?
? ? ? ? for (i = 0; i < 16; i++) ?
? ? ? ? ? ? Str_Len += wsprintf(Str + Str_Len, " %02X", PBYTE(E.ExceptionAddress)[i]); ?
??
? ? ? ? // Save registers at exception. ?
? ? ? ? Str_Len += wsprintf(Str + Str_Len, NL "Registers:"); ?
? ? ? ? Str_Len += wsprintf(Str + Str_Len, NL "EAX: %08X ?EBX: %08X ?ECX: %08X ?EDX: %08X",?
C.Eax, C.Ebx, C.Ecx, C.Edx); ?
? ? ? ? Str_Len += wsprintf(Str + Str_Len, NL "ESI: %08X ?EDI: %08X ?ESP: %08X ?EBP: %08X",?
C.Esi, C.Edi, C.Esp, C.Ebp); ?
? ? ? ? Str_Len += wsprintf(Str + Str_Len, NL "EIP: %08X ?EFlags: %08X", C.Eip, C.EFlags); ?
? ? } //if (pException) ?
? ? ??
? ? // Save call stack info. ?
? ? Str_Len += wsprintf(Str + Str_Len, NL "Call Stack:"); ?
? ? Get_Call_Stack(pException, Str + Str_Len); ?
??
? ? if (Str[0] == NL[0]) ?
? ? ? ? lstrcpy(Str, Str + sizeof(NL) - 1); ?
??
? ? return Str; ?
} //Get_Exception_Info ?
??
//************************************************************************************* ?
void WINAPI Create_Dump(PEXCEPTION_POINTERS pException, BOOL File_Flag, BOOL Show_Flag) ?
//************************************************************************************* ?
// Create dump. ??
// pException can be either GetExceptionInformation() or NULL. ?
// If File_Flag = TRUE - write dump files (.dmz and .dmp) with the name of the current?
process. ?
// If Show_Flag = TRUE - show message with Get_Exception_Info() dump. ?
{ ?
? ? HANDLE ?hDump_File; ?
? ? PCHAR ? Str; ?
? ? DWORD ? Bytes; ?
? ? DWORD ? nLen = 0; ?
??
? ? CString strDir,strTXTFile,strDMPFile; ?
? ? CString strDate,strTotal; ?
? ? CTime ? tm = CTime::GetCurrentTime(); ?
? ? ??
? ? strDir.Format(_T("%s\\Log"),GetExePath()); ?
? ? strTXTFile.Format(_T("%s\\Log\\%04d-%02d-%02d %02d%02d%02d.txt"),GetExePath
(),tm.GetYear(),tm.GetMonth(), ?
? ? ? ? tm.GetDay(),tm.GetHour(),tm.GetMinute(),tm.GetSecond()); ?
? ? strDMPFile.Format(_T("%s\\Log\\%04d-%02d-%02d %02d%02d%02d.dmp"),GetExePath
(),tm.GetYear(),tm.GetMonth(), ?
? ? ? ? tm.GetDay(),tm.GetHour(),tm.GetMinute(),tm.GetSecond()); ?
??
? ? if(!PathFileExists(strDir)) ?
? ? ? ? CreateDirectory(strDir,NULL); ?
??
? ? Str = Get_Exception_Info(pException); ?
??
? ? //if (Show_Flag && Str) ?
? ? // ?MessageBox(NULL, Str, "MiniDump", MB_ICONHAND | MB_OK); ?
??
? ? if (File_Flag) ?
? ? { ?
? ? ? ? if (Str) ?
? ? ? ? { ?
? ? ? ? ? ? hDump_File = CreateFile(strTXTFile, ?
? ? ? ? ? ? ? ? GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); ?
? ? ? ? ? ? ??
? ? ? ? ? ? nLen = lstrlen(Str); ?
? ? ? ? ? ? Str[nLen] = '\0'; ?
??
? ? ? ? ? ? WriteFile(hDump_File, Str, lstrlen(Str) + 1, &Bytes, NULL); ?
??
? ? ? ? ? ? CloseHandle(hDump_File); ?
? ? ? ? } ?
??
? ? ? ? // If MiniDumpWriteDump() of DbgHelp.dll available. ?
? ? ? ? if (MiniDumpWriteDump_) ?
? ? ? ? { ?
? ? ? ? ? ? MINIDUMP_EXCEPTION_INFORMATION ?M; ?
??
? ? ? ? ? ? M.ThreadId = GetCurrentThreadId(); ?
? ? ? ? ? ? M.ExceptionPointers = pException; ?
? ? ? ? ? ? M.ClientPointers = 0; ?
??
? ? ? ? ? ? hDump_File = CreateFile(strDMPFile, ?
? ? ? ? ? ? ? ? GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); ?
??
? ? ? ? ? ? MiniDumpWriteDump_(GetCurrentProcess(), GetCurrentProcessId(), hDump_File, ?
? ? ? ? ? ? ? ? MiniDumpNormal, (pException) ? &M : NULL, NULL, NULL); ?
??
? ? ? ? ? ? CloseHandle(hDump_File); ?
? ? ? ? } ?
? ? } //if (File_Flag) ?
??
? ? delete Str; ?
} //Create_Dump ?
具體參考方法如下:
1、在CXXDlg::OnInitDialog()中添加這樣一段:
SetUnhandledExceptionFilter(CrashReportEx); ?
HMODULE hKernel32; ?
??
// Try to get MiniDumpWriteDump() address. ?
hDbgHelp = LoadLibrary("DBGHELP.DLL"); ?
MiniDumpWriteDump_ = (MINIDUMP_WRITE_DUMP)GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); ?
// ?d("hDbgHelp=%X, MiniDumpWriteDump_=%X", hDbgHelp, MiniDumpWriteDump_); ?
??
// Try to get Tool Help library functions. ?
hKernel32 = GetModuleHandle("KERNEL32"); ?
CreateToolhelp32Snapshot_ = (CREATE_TOOL_HELP32_SNAPSHOT)GetProcAddress(hKernel32,?
"CreateToolhelp32Snapshot"); ?
Module32First_ = (MODULE32_FIRST)GetProcAddress(hKernel32, "Module32First"); ?
Module32Next_ = (MODULE32_NEST)GetProcAddress(hKernel32, "Module32Next"); ?
測試代碼如下:
class CTestDlg : public CDialog ?
{ ?
// Construction ?
public: ?
? ? CTestDlg(CWnd* pParent = NULL); // standard constructor ?
??
? ? void Fun1(char *pszBuffer); ?
? ? void Fun2(char *pszBuffer); ?
? ? void Fun3(char *pszBuffer); ?
}; ?
void CTestDlg::Fun1(char *pszBuffer) ?
{ ?
? ? Fun2(pszBuffer); ?
} ?
??
void CTestDlg::Fun2(char *pszBuffer) ?
{ ?
? ? Fun3(pszBuffer); ?
} ?
??
void CTestDlg::Fun3(char *pszBuffer) ?
{ ?
? ? pszBuffer[1] = 0x00; ?
} ?
我們在雙擊確定按鈕時的響應代碼如下:
void CTestDlg::OnOK() ??
{ ?
? ? // TODO: Add extra validation here ?
? ? Fun1(NULL); ?
} ?
2、設置VC編譯選項,勾選生成MAP和Debug Info:
3、將編譯生成的Release目錄中的pdb、map文件保存起來,以后調試會用到:
4、運行程序,單擊確定按鈕出現異常后自動重啟,并創建一個Log文件夾,里面生成dump文件:
5、我們打開WinDbg,設置一下pdb路徑(File \ Symbol File Path):
6、用WiinDbg打開dump文件(File \ Open Crash Dump)
7、輸入命令!analyze -v,等待幾秒后會打印出錯誤信息,函數調用棧如下圖:
OK ,這樣我們就能在發布版本的程序中,準確的定位到哪個函數出了問題,所以發布程序時,一定要記
得生成pdb、map文件,不然客戶運行出錯的話,你不死也殘!
測試工程下載地址:
http://download.csdn.NET/source/3575167
========
總結
以上是生活随笔為你收集整理的Windbg dump分析 学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WinDBG调试dNet程序总结
- 下一篇: Java web 三大框架异常学习总结