• 编写的windows程序,崩溃时产生crash dump文件的办法


    一、引言

    dump文件是C++程序发生异常时,保存当时程序运行状态的文件,是调试异常程序重要的方法,所以程序崩溃时,除了日志文件,dump文件便成了我们查找错误的最后一根救命的稻草。windows程序产生dump文件和linux程序产生dump文件的方式不一样,linux默认是不让产生core dump文件,只要在用户自己的~/.bash_profile文件中增加

    ulimit -S -c unlimited > /dev/null 2>&1

    这样程序崩溃就可以产生可调试的core dump文件了。但是windows环境就得写代码才能实现了。

    二、原理

    windows程序当遇到异常,没有try-catch或者try-catch也无法捕获到的异常时,程序就会自动退出,如果这时候没有dump文件的话,我们是没有得到任何程序退出的信息。在windows程序异常退出之前,会预先调用一个在程序中注册的异常处理回调函数(默认是没有设置),只要我们在这个回调函数中调用MiniDumpWriteDump函数就可以产生我们想要的dump文件。

    三、实现

    1.调用SetUnhandledExceptionFilter注册一个自定义的异常处理回调函数

    SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

    异常处理回调函数的原型

    LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo);

    2.CreateFile创建dump文件,调用MiniDumpWriteDump函数往dump文件写异常信息

    [cpp] view plain copy
     
     print?
    1. inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)  
    2. {  
    3.     HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,  
    4.         FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  
    5.   
    6.     if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))  
    7.     {  
    8.         MINIDUMP_EXCEPTION_INFORMATION mdei;  
    9.         mdei.ThreadId           = GetCurrentThreadId();  
    10.         mdei.ExceptionPointers  = pep;  
    11.         mdei.ClientPointers     = NULL;  
    12.   
    13.         MINIDUMP_CALLBACK_INFORMATION mci;  
    14.         mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;  
    15.         mci.CallbackParam       = 0;  
    16.   
    17.         ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);  
    18.   
    19.         CloseHandle(hFile);  
    20.     }  
    21. }  


    CreateMiniDump函数是在异常处理回调函数MyUnhandledExceptionFilter中调用的

    [cpp] view plain copy
     
     print?
    1. LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)  
    2. {  
    3.     CreateMiniDump(pExceptionInfo, "core.dmp");  
    4.   
    5.     return EXCEPTION_EXECUTE_HANDLER;  
    6. }  


    3.将SetUnhandledExceptionFilter失效

    vs2005中,编译的过程中,编译器会自动给你的程序加上一句SetUnhandledExceptionFilter(NULL),这就会导致你之前自定义的

    SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

    无效,就有可能不会产生dump文件,因此我们必须在自定义的SetUnhandledExceptionFilter之后,让之后调用的SetUnhandledExceptionFilter无效。增加以下代码:

    [cpp] view plain copy
     
     print?
    1. // 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效  
    2. void DisableSetUnhandledExceptionFilter()  
    3. {  
    4.     void* addr = (void*)GetProcAddress(LoadLibrary("kernel32.dll"),  
    5.         "SetUnhandledExceptionFilter");  
    6.   
    7.     if (addr)  
    8.     {  
    9.         unsigned char code[16];  
    10.         int size = 0;  
    11.   
    12.         code[size++] = 0x33;  
    13.         code[size++] = 0xC0;  
    14.         code[size++] = 0xC2;  
    15.         code[size++] = 0x04;  
    16.         code[size++] = 0x00;  
    17.   
    18.         DWORD dwOldFlag, dwTempFlag;  
    19.         VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);  
    20.         WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);  
    21.         VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);  
    22.     }  
    23. }  


    最终代码整理:

    //minidump.h

    [cpp] view plain copy
     
     print?
    1. #pragma once  
    2. #include <windows.h>  
    3. #include <DbgHelp.h>  
    4. #include <stdlib.h>  
    5. #pragma comment(lib, "dbghelp.lib")  
    6.   
    7. #ifndef _M_IX86  
    8. #error "The following code only works for x86!"  
    9. #endif  
    10.   
    11. inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)  
    12. {  
    13.     if(pModuleName == 0)  
    14.     {  
    15.         return FALSE;  
    16.     }  
    17.   
    18.     WCHAR szFileName[_MAX_FNAME] = L"";  
    19.     _wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);  
    20.   
    21.     if(wcsicmp(szFileName, L"ntdll") == 0)  
    22.         return TRUE;  
    23.   
    24.     return FALSE;  
    25. }  
    26.   
    27. inline BOOL CALLBACK MiniDumpCallback(PVOID                            pParam,  
    28.                                       const PMINIDUMP_CALLBACK_INPUT   pInput,  
    29.                                       PMINIDUMP_CALLBACK_OUTPUT        pOutput)  
    30. {  
    31.     if(pInput == 0 || pOutput == 0)  
    32.         return FALSE;  
    33.   
    34.     switch(pInput->CallbackType)  
    35.     {  
    36.     case ModuleCallback:  
    37.         if(pOutput->ModuleWriteFlags & ModuleWriteDataSeg)  
    38.             if(!IsDataSectionNeeded(pInput->Module.FullPath))  
    39.                 pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);  
    40.     case IncludeModuleCallback:  
    41.     case IncludeThreadCallback:  
    42.     case ThreadCallback:  
    43.     case ThreadExCallback:  
    44.         return TRUE;  
    45.     default:;  
    46.     }  
    47.   
    48.     return FALSE;  
    49. }  
    50.   
    51. inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)  
    52. {  
    53.     HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,  
    54.         FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  
    55.   
    56.     if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))  
    57.     {  
    58.         MINIDUMP_EXCEPTION_INFORMATION mdei;  
    59.         mdei.ThreadId           = GetCurrentThreadId();  
    60.         mdei.ExceptionPointers  = pep;  
    61.         mdei.ClientPointers     = NULL;  
    62.   
    63.         MINIDUMP_CALLBACK_INFORMATION mci;  
    64.         mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;  
    65.         mci.CallbackParam       = 0;  
    66.   
    67.         ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);  
    68.   
    69.         CloseHandle(hFile);  
    70.     }  
    71. }  
    72.   
    73. LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)  
    74. {  
    75.     CreateMiniDump(pExceptionInfo, "core.dmp");  
    76.   
    77.     return EXCEPTION_EXECUTE_HANDLER;  
    78. }  
    79.   
    80. // 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效  
    81. void DisableSetUnhandledExceptionFilter()  
    82. {  
    83.     void* addr = (void*)GetProcAddress(LoadLibrary("kernel32.dll"),  
    84.         "SetUnhandledExceptionFilter");  
    85.   
    86.     if (addr)  
    87.     {  
    88.         unsigned char code[16];  
    89.         int size = 0;  
    90.   
    91.         code[size++] = 0x33;  
    92.         code[size++] = 0xC0;  
    93.         code[size++] = 0xC2;  
    94.         code[size++] = 0x04;  
    95.         code[size++] = 0x00;  
    96.   
    97.         DWORD dwOldFlag, dwTempFlag;  
    98.         VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);  
    99.         WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);  
    100.         VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);  
    101.     }  
    102. }  
    103.   
    104. void InitMinDump()  
    105. {  
    106.     //注册异常处理函数  
    107.     SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);  
    108.   
    109.     //使SetUnhandledExceptionFilter  
    110.     DisableSetUnhandledExceptionFilter();  
    111. }  


    4.测试代码

    //test.cpp

    [cpp] view plain copy
     
     print?
      1. #include <iostream>  
      2. #include "minidump.h"  
      3. void test()  
      4. {  
      5.     std::string s = "abcd";  
      6.   
      7.     try{  
      8.         s[100] = 'b';  
      9.     }  
      10.     catch(std::exception& e)  
      11.     {  
      12.         std::cout << "with exception:[" << e.what() << "]" << std::endl;  
      13.     }  
      14.     catch(...)  
      15.     {  
      16.         std::cout << "with unknown exception" << std::endl;  
      17.     }  
      18. }  
      19.   
      20. void main()  
      21. {  
      22.     InitMinDump();  
      23.   
      24.     test();  
      25.   
      26.     system("pause");  
      27. }  
  • 相关阅读:
    (一)Java基本数据类型及运算符
    (二)Java控制执行流程
    ArrayList类源码解析——ArrayList动态数组的实现细节(基于JDK8)
    Java的四个标记接口:Serializable、Cloneable、RandomAccess和Remote接口
    Java容器类源码分析之Iterator与ListIterator迭代器(基于JDK8)
    Java容器类源码分析前言之集合框架结构(基于JDK8)
    浅谈虚树
    点分治
    Ze_Min Tree 主席树
    笛卡尔树的妙用
  • 原文地址:https://www.cnblogs.com/hushaojun/p/6388171.html
Copyright © 2020-2023  润新知