软件异常
异常,顾名思义是指不符合预期的时间发生,由应用程序和操作系统抛出的异常叫做软件异常。
当然我们均不希望发生这些软件异常,但在实际中却常常会遇到因为不良编码导致的异常,比如访问了空指针、访问非法地址、解析json字符串异常等等。
异常处理
为了应对异常,window系统提供了一些API用于获取异常、处理或者控制异常,
为了理解后续的异常信息,我们先了解三个关于异常的API函数:
GetExceptionCode
该API原型如下:
DWORD GetExceptionCode(void);
该函数用于获取异常发生时的类型,比如 EXCEPTION_ACCESS_VIOLATION
异常和内存相关,它试图访问非法内存地址,数值为5,是最常见的一种异常。
GetExceptionInformation
该API原型如下:
LPEXCEPTION_POINTERS GetExceptionInformation(void);
这个函数返回指向EXCEPTION_POINTERS结构的指针,其结构体信息如下:
//异常信息描述
typedef struct _EXCEPTION_POINTERS {
//异常记录,和机器无关
PEXCEPTION_RECORD ExceptionRecord;
//异常时的上下文,和处理器有关系
PCONTEXT ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
//异常记录
typedef struct _EXCEPTION_RECORD {
DWORD ExceptionCode; /*异常原因*/
DWORD ExceptionFlags;/*异常标志*/
struct _EXCEPTION_RECORD *ExceptionRecord;/*异常记录信息*/
PVOID ExceptionAddress;/*发生异常的地址*/
DWORD NumberParameters;/*与异常关联的参数数量*/
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
} EXCEPTION_RECORD;
UnhandledExceptionFilter
该API原型如下:
LONG UnhandledExceptionFilter(
_EXCEPTION_POINTERS *ExceptionInfo
);
参数:
ExceptionInfo指向EXCEPTION_POINTERS
结构的指针,该结构指定异常的描述和异常时的处理器上下文。此指针是对GetExceptionInformation函数的调用的返回值 。
我们的windows系统会在内部使用 UnhandledExceptionFilter来处理在进程和线程创建期间发生的异常行为。如果我们的程序是在调试模式,异常则会传递给调试器,如果我们程序没有附加调试器,并且该异常未被处理,则windows会将异常通知用户。
获取异常信息
在windbg之初步分析转储文件这篇文章中,已经介绍了如何简单分析dump文件以及!analyze -v命令使用。
下面给出!analyze -v命令的分析结果,用于了解异常和分析异常信息。
FAULTING_IP:
+5b032faf06c4d81c
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:
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
异常信息解读
下面分别介绍比较重要的关键字段:
一、各个参数的详解
FAULTING_IP :
即出错的指令地址,指出发生错误时所执行的指令,这的IP值EIP
EXCEPTION_RECORD:
异常记录的地址,即该地址是PEXCEPTION_RECORD类型,并且这里给出了分析异常的命令(.exr 0x2afaec
)这个很重要
ExceptionAdddress:
发生异常的地址
ExceptionCode:
异常所代码的错误码,这是因为非法访问导致的
ExceptionFlag:
异常标志(1,表示不可继续的异常 0,表示可继续的异常)
NumberParameters:
异常相关联的参数,第一个参数是空指针,第二参数是结构体成员地址
FAULTING_THREAD:
发生错误的线程ID
CONTEXT:
是发生异常时的上下文地址,这里给出的地址是0x002afb08 ,这个很重要。
FAULTING_SOURCE_CODE:
给出了执行异常时所对应的源代码,>
符号表明了异常语句。
STACK_COMMAND:
是堆栈相关的命令,获取程序执行错误时堆栈调用情况,这给出了.cxr 0x2afb08 和 kb
两个命令, 这个也很重要。
二、STACK_TEXT栈文本
该字段是栈文本信息,它反映了错误堆栈的调用情况,从中可以知道以下两个信息:
RtlInitializeExceptionChain
函数到GetStudentInfo
函数,执行GetStudentInfo函数时发生异常。例如:
00d92104参数1 00000000参数2 00000005 参数3 若参数少于三个,按照实际顺序对号入座即可。
总结
在这篇文章总主要介绍了软件异常,以及介绍windows处理异常时的API,着重解读了windows异常报告中重要字段含义,在下一篇文章中,我们会根据该异常报告进行crash根因分析。
参考文章:
https://blog.csdn.net/Ma_Hong_Kai/article/details/83658522
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/using-the–analyze-extension
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/bug-check-0x1e–kmode-exception-not-handled