在之前的文章中,我們已經介紹瞭如何生成dump文件以及異常報告分析,今天就基於生成的dump文件進行crash根因分析。
打開dump文件
當打開dump文件之後,windbg會顯示如下信息:
!analyze -v命令使用
爲了分析此次程序運行崩潰的原因,可以輸入!analyze -v
命令,來分析當前異常的詳細信息。
輸入!analyze -v命令後,windbg會進行大量的分析,以下是異常的詳細信息記錄:
FAULTING_IP:
+5b032faf072ddb48
00000000 ?? ???
EXCEPTION_RECORD: 002afaec -- (.exr 0x2afaec)
ExceptionAddress: 00d91006 (aLittleCode!GetStudentInfo+0x00000006)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 00000100
Attempt to read from address 00000100
FAULTING_THREAD: 00001f24
DEFAULT_BUCKET_ID: WRONG_SYMBOLS
PROCESS_NAME: aLittleCode.exe
ADDITIONAL_DEBUG_TEXT:
Use '!findthebuild' command to search for the target build information.
If the build information is available, run '!findthebuild -s ; .reload' to set symbol path and load symbols.
FAULTING_MODULE: 77730000 ntdll
DEBUG_FLR_IMAGE_TIMESTAMP: 5d6b8f1a
ERROR_CODE: (NTSTATUS) 0x80000003 - {
EXCEPTION_CODE: (NTSTATUS) 0x80000003 (2147483651) - {
MOD_LIST: <ANALYSIS/>
CONTEXT: 002afb08 -- (.cxr 0x2afb08)
eax=00000000 ebx=00000000 ecx=6742b6f0 edx=00000000 esi=00000001 edi=00d93374
eip=00d91006 esp=002afdec ebp=002afdec iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
aLittleCode!GetStudentInfo+0x6:
00d91006 8b8800010000 mov ecx,dword ptr [eax+100h] ds:0023:00000100=????????
Resetting default scope
PRIMARY_PROBLEM_CLASS: WRONG_SYMBOLS
BUGCHECK_STR: APPLICATION_FAULT_WRONG_SYMBOLS
LAST_CONTROL_TRANSFER: from 00d9103b to 00d91006
STACK_TEXT:
002afdec 00d9103b 00d92104 00000000 00000005 aLittleCode!GetStudentInfo+0x6 [e:\code\c++\myproject\vs2008\src\alittlecode\main.cpp @ 13]
002afe04 00d911ad 00000003 00422da8 00421f78 aLittleCode!main+0x1b [e:\code\c++\myproject\vs2008\src\alittlecode\main.cpp @ 22]
002afe48 7709efac 7ffd3000 002afe94 77793618 aLittleCode!__tmainCRTStartup+0x10f [f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c @ 582]
WARNING: Stack unwind information not available. Following frames may be wrong.
002afe54 77793618 7ffd3000 26dce074 00000000 kernel32!BaseThreadInitThunk+0x12
002afe94 777935eb 00d912f5 7ffd3000 00000000 ntdll!RtlInitializeExceptionChain+0xef
002afeac 00000000 00d912f5 7ffd3000 00000000 ntdll!RtlInitializeExceptionChain+0xc2
FOLLOWUP_IP:
aLittleCode!GetStudentInfo+6 [e:\code\c++\myproject\vs2008\src\alittlecode\main.cpp @ 13]
00d91006 8b8800010000 mov ecx,dword ptr [eax+100h]
FAULTING_SOURCE_CODE:
9:
10: //?¡äDDo¡¥¨ºy2?¨ºy
11: void GetStudentInfo(char* name, STRU_STUDENT_INFO *pStudent, int count)
12: {
> 13: printf("student age=%d",pStudent->usAge);
14: }
15:
16:
17: int main(int argc, char const *argv[])
18: {
SYMBOL_STACK_INDEX: 0
SYMBOL_NAME: alittlecode!GetStudentInfo+6
FOLLOWUP_NAME: MachineOwner
MODULE_NAME: aLittleCode
IMAGE_NAME: aLittleCode.exe
STACK_COMMAND: .cxr 0x2afb08 ; kb
BUCKET_ID: WRONG_SYMBOLS
FAILURE_BUCKET_ID: WRONG_SYMBOLS_80000003_aLittleCode.exe!GetStudentInfo
WATSON_STAGEONE_URL: http://watson.microsoft.com/StageOne/aLittleCode_exe/0_0_0_0/5d6b8f1a/unknown/0_0_0_0/bbbbbbb4/80000003/00000000.htm?Retriage=1
Followup: MachineOwner
---------
通過分析異常信息,我們很容易找的發生異常的源碼位置:
異常代碼位於13行,而pStudent是指針變量,可以猜出是因爲空指定導致的函數崩潰。
crash 分析步驟
在一般情況情況下,通過windbg給出的錯誤源代碼提示,我們就可以知道崩潰原因,然後完成代碼修復。下面先給出兩個重要命令:
- .exr (Display Exception Record)
- .cxr (Display Context Record)
如果想要嚴謹的分析crash根因,我們需要藉助dump文件(轉儲文件)得到下列信息:
- 異常發生的地方 (地址、源碼文件和代碼行)
- 異常發生時的調用堆棧,通過.cxr命令
- 調用堆棧上函數參數和本地變量的值,通過k命令以及d命令
想要得到這三個信息,最重要的一步就是得到函數執行異常時的上下文環境,通過.cxr命令可實現。
步驟一: 獲取異常原因
異常原因我們可以在報告中獲取,內容如下:
EXCEPTION_RECORD: 002afaec -- (.exr 0x2afaec)
ExceptionAddress: 00d91006 (aLittleCode!GetStudentInfo+0x00000006)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 00000100
Attempt to read from address 00000100
此次crash時異常記錄地址爲002afaec,可以通過執行.exr 0x002afaec
命令獲取crash問題原因描述。
這個地方相對沒有那麼重要,但是我們需要了解。
步驟二: 切換上下文
在windbg給出的異常詳細信息中,有一個STACK_COMMAND和CONTEXT字段,都給出了分析堆棧重要前提,如下圖所示:
.cxr 0x2afb08 用來顯示上下文記錄,0x2afb08 是上下文記錄地址,這個命令很重要,只有切換到出問題時的上下文記錄,才能分析堆棧信息。
我們在命令行窗口中輸入.cxr 0x2afb08切換異常的上下文環境,如下圖:
此時源碼窗口會被調用出來,並將異常源碼行高亮,如下圖:
步驟三: 顯示調用棧信息
與此同時,我們可輸入kb命令,顯示函數調用棧過程
爲了清楚看到函數入參,我們建議使用kP命令,功能和kb命令一樣,如下圖:
如果此時,GetStudentInfo函數中還有其他的本地變量或者全局變量需要分析,我們可使用d命令,比如dt命令或者dv命令
很明顯pStudent爲NULL導致程序崩潰。好了,分析轉儲文件基本過程就是這樣了,有了這篇文章,我相信再次遇到crash問題我們將有應對方法。
下一篇將介紹沒有異常記錄和上下文地址時,如何分析crash問題。