windbg入门教程之异常报告深入解读

软件异常

异常,顾名思义是指不符合预期的时间发生,由应用程序和操作系统抛出的异常叫做软件异常

当然我们均不希望发生这些软件异常,但在实际中却常常会遇到因为不良编码导致的异常,比如访问了空指针、访问非法地址、解析json字符串异常等等。

异常处理

为了应对异常,window系统提供了一些API用于获取异常、处理或者控制异常,
为了理解后续的异常信息,我们先了解三个关于异常的API函数:

  1. GetExceptionCode
  2. GetExceptionInformation
  3. UnhandledExceptionFilter

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栈文本

该字段是栈文本信息,它反映了错误堆栈的调用情况,从中可以知道以下两个信息:

  1. 函数执行顺序为从RtlInitializeExceptionChain函数到GetStudentInfo函数,执行GetStudentInfo函数时发生异常。
  2. 每一行中的每列地址分别为 ChildEBP地址、函数返回地址、函数前三个参数,共计五个。

例如:

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

你可能感兴趣的:(调试技术)