九天雁翎的博客
如果你想在软件业获得成功,就使用你知道的最强大的语言,用它解决你知道的最难的问题,并且等待竞争对手的经理做出自甘平庸的选择。 -- Paul Graham

Breakpad 使用方法理解文档

Breakpad 使用方法理解文档.

只需要在任何异常前正常创建一个ExceptionHandler类的成员函数,就可以完成异常的捕捉及dump.

在创建ExceptionHandler时,第一参数为宽字符表示的dump存储路径,第二参数为dump前客户需要运行的程序,程序原型应该为

bool (*FilterCallback)(void* context, 
                       EXCEPTION_POINTERS* exinfo,
                       MDRawAssertionInfo* assertion);

程序返回false将不产生dump,返回true才正常dump.

第三参数为客户Dump后需要运行的程序,程序原型为:

bool (*MinidumpCallback)(const wchar_t* dump_path,
                         const wchar_t* minidump_id,
                         void* context,
                         EXCEPTION_POINTERS* exinfo,
                         MDRawAssertionInfo* assertion,
                         bool succeeded);

程序返回true表示异常全部被控制,程序正常运行,返回false,程序仍然保留异常,以方便交给其他程序处理,比如各平台的原生异常处理系统.

HandlerType:确定需要控制的异常类型,HANDLER_ALL时,控制所有类型的异常.

ExceptionHandler有两个版本的构造函数:

ExceptionHandler(const wstring& dump_path, FilterCallback filter, MinidumpCallback callback, void* callback_context, int handler_types);

ExceptionHandler(const wstring& dump_path, FilterCallback filter, MinidumpCallback callback, void* callback_context, int handler_types, MINIDUMP_TYPE dump_type, const wchar_t* pipe_name, const CustomClientInfo* custom_info);

dump_path()用来返回dump的路径.

Set_dump_path(const wstring &dump_path)用来设置路径.

WriteMinidump()

WriteMinidump(const wstring &dump_path, MinidumpCallback callback, void* callback_context);立即写dump文件.

WriteMinidumpForException(EXCEPTION_POINTERS* exinfo)用用户提供的异常信息立即写dump文件.

get_requesting_thread_id()得到出现异常或者调用WriteMinidump()函数的线程ID.

bool ExceptionHandler::WriteMinidumpWithException( DWORD requesting_thread_id, EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion)

为最主要的函数,具体的写下Dump文件.

这个结构很明显是用来保存异常信息的

typedef struct _EXCEPTION_RECORD {
    DWORD    ExceptionCode;
    DWORD ExceptionFlags;
    struct _EXCEPTION_RECORD *ExceptionRecord;
    PVOID ExceptionAddress;
    DWORD NumberParameters;
    ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
    } EXCEPTION_RECORD;

typedef EXCEPTION_RECORD *PEXCEPTION_RECORD;
typedef struct _CONTEXT {

    //
    // The flags values within this flag control the contents of
    // a CONTEXT record.
    //
    // If the context record is used as an input parameter, then
    // for each portion of the context record controlled by a flag
    // whose value is set, it is assumed that that portion of the
    // context record contains valid context. If the context record
    // is being used to modify a threads context, then only that
    // portion of the threads context will be modified.
    //
    // If the context record is used as an IN OUT parameter to capture
    // the context of a thread, then only those portions of the thread's
    // context corresponding to set flags will be returned.
    //
    // The context record is never used as an OUT only parameter.
    //

    DWORD ContextFlags;

    //
    // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
    // set in ContextFlags.  Note that CONTEXT_DEBUG_REGISTERS is NOT
    // included in CONTEXT_FULL.
    //

    DWORD   Dr0;
    DWORD   Dr1;
    DWORD   Dr2;
    DWORD   Dr3;
    DWORD   Dr6;
    DWORD   Dr7;

    //
    // This section is specified/returned if the
    // ContextFlags word contians the flag CONTEXT_FLOATING_POINT.
    //

    FLOATING_SAVE_AREA FloatSave;

    //
    // This section is specified/returned if the
    // ContextFlags word contians the flag CONTEXT_SEGMENTS.
    //

    DWORD   SegGs;
    DWORD   SegFs;
    DWORD   SegEs;
    DWORD   SegDs;

    //
    // This section is specified/returned if the
    // ContextFlags word contians the flag CONTEXT_INTEGER.
    //

    DWORD   Edi;
    DWORD   Esi;
    DWORD   Ebx;
    DWORD   Edx;
    DWORD   Ecx;
    DWORD   Eax;

    //
    // This section is specified/returned if the
    // ContextFlags word contians the flag CONTEXT_CONTROL.
    //

    DWORD   Ebp;
    DWORD   Eip;
    DWORD   SegCs;              // MUST BE SANITIZED
    DWORD   EFlags;             // MUST BE SANITIZED
    DWORD   Esp;
    DWORD   SegSs;

    //
    // This section is specified/returned if the ContextFlags word
    // contains the flag CONTEXT_EXTENDED_REGISTERS.
    // The format and contexts are processor specific
    //

    BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];

} CONTEXT;

typedef CONTEXT *PCONTEXT;
typedef struct _EXCEPTION_POINTERS {
    PEXCEPTION_RECORD ExceptionRecord;
    PCONTEXT ContextRecord;
} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS;
typedef struct {
 /* expression, function, and file are 0-terminated UTF-16 strings.  They
  * may be truncated if necessary, but should always be 0-terminated when
  * written to a file.
  * Fixed-length strings are used because MiniDumpWriteDump doesn't offer
  * a way for user streams to point to arbitrary RVAs for strings. */
 u_int16_t expression[128];  /* Assertion that failed... */
 u_int16_t function[128];    /* ...within this function... */
 u_int16_t file[128];        /* ...in this file... */
 u_int32_t line;             /* ...at this line. */
 u_int32_t type;
} MDRawAssertionInfo;

实现上:当FilterCallback(即ExceptionHandler构造函数的第二参数)不为空的时候,首先用WriteMinidumpWithException函数的原参数直接调用FilterCallback,(参数类型一致),完成用户在调用Dump先需要做的工作.

然后通过IsOutOfProcess()成员函数判断是否此时是Exception_handler自身来进行dump,详细内容,参看

当IsOutOfProcess()返回真的时候,应该表示此时处理是在进程外发生的,也就是利用crash_generation的client,server的机制完成,不影响原进程的运行.

此时调用CrashGenerationClient类型的成员变量的RequestDump函数完成dump.

当返回假的时候,此时先判断是否从dbghelp.dll中正确的import了MiniDumpWriteDump函数,然后创建了一个新的可写的文件.

当创建成功后,ExceptionHander加入异常信息到user_streams,然后调用minidump_write_dump_(实际就是dbghelp.dll中的MiniDumpWriteDump函数)完成dump.

主要的信息都在WriteMinidumpWithException函数的第二参数及第三参数里面.从注释上看,这些信息属于breakpad自己新增加的附加信息,但是增加这些信息对以前的dump文件正常使用没有影响,这些信息来自出现纯虚函数调用和无效参数调用时,breakpad自定义的用户函数中添加的信息.

_set_invalid_parameter_handler(ExceptionHandler::HandleInvalidParameter);
#endif  // _MSC_VER >= 1400

_set_purecall_handler(ExceptionHandler::HandlePureVirtualCall);

即, HandleInvalidParameter, HandlePureVirtualCall中添加的信息.

此信息类型为MDRawAssertionInfo,在HandlePureVirtualCall函数调用时,仅仅是设定异常类型为HandlePureVirtualCall,当出现无效参数调用时,增加的内容较多:

_snwprintf_s(reinterpret_cast<wchar_t*>(assertion.expression),
             sizeof(assertion.expression) /, sizeof(assertion.expression[0]),
             _TRUNCATE, L"%s", expression);

_snwprintf_s(reinterpret_cast<wchar_t*>(assertion.function),
             sizeof(assertion.function) / sizeof(assertion.function[0]),
             _TRUNCATE, L"%s", function);

_snwprintf_s(reinterpret_cast<wchar_t*>(assertion.file),
             sizeof(assertion.file) / sizeof(assertion.file[0]),
             _TRUNCATE, L"%s", file);

assertion.line = line;
assertion.type = MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER;

分别为调用无效参数的表达式,函数名,文件名,行号,最后设定异常类型为

MD_ASSERTION_INFO_TYPE_INVALID_PARAMETE.

最后关闭文件,再调用callback_函数,也就是ExceptionHandler构造函数的第三参数.

其他主要内容在 描述.

分类:  C++ 
标签:  Breakpad  C++ 

Posted By 九天雁翎 at 九天雁翎的博客 on 2008年06月01日

前一篇: 关于以前应用程序运行出现配置错误的问题的解决方案 后一篇: Breakpad在进程中完成dump的流程描述