在之前的文章中,我们已经介绍了如何生成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问题。