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

    xiaoxiao2021-03-25  88

    原文:http://blog.csdn.net/fhxpp_27/article/details/9701867

    一、引言

    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 inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)   {       HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,           FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);          if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))       {           MINIDUMP_EXCEPTION_INFORMATION mdei;           mdei.ThreadId           = GetCurrentThreadId();           mdei.ExceptionPointers  = pep;           mdei.ClientPointers     = NULL;              MINIDUMP_CALLBACK_INFORMATION mci;           mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;           mci.CallbackParam       = 0;              ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);              CloseHandle(hFile);       }   }   CreateMiniDump函数是在异常处理回调函数MyUnhandledExceptionFilter中调用的

    [cpp]  view plain copy LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)   {       CreateMiniDump(pExceptionInfo, "core.dmp");          return EXCEPTION_EXECUTE_HANDLER;   }   3.将SetUnhandledExceptionFilter失效

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

    SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

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

    [cpp]  view plain copy // 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效   void DisableSetUnhandledExceptionFilter()   {       void* addr = (void*)GetProcAddress(LoadLibrary("kernel32.dll"),           "SetUnhandledExceptionFilter");          if (addr)       {           unsigned char code[16];           int size = 0;              code[size++] = 0x33;           code[size++] = 0xC0;           code[size++] = 0xC2;           code[size++] = 0x04;           code[size++] = 0x00;              DWORD dwOldFlag, dwTempFlag;           VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);           WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);           VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);       }   }   最终代码整理:

    //minidump.h

    [cpp]  view plain copy #pragma once   #include <windows.h>   #include <DbgHelp.h>   #include <stdlib.h>   #pragma comment(lib, "dbghelp.lib")      #ifndef _M_IX86   #error "The following code only works for x86!"   #endif      inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)   {       if(pModuleName == 0)       {           return FALSE;       }          WCHAR szFileName[_MAX_FNAME] = L"";       _wsplitpath(pModuleName, NULL, NULL, szFileName, NULL);          if(wcsicmp(szFileName, L"ntdll") == 0)           return TRUE;          return FALSE;   }      inline BOOL CALLBACK MiniDumpCallback(PVOID                            pParam,                                         const PMINIDUMP_CALLBACK_INPUT   pInput,                                         PMINIDUMP_CALLBACK_OUTPUT        pOutput)   {       if(pInput == 0 || pOutput == 0)           return FALSE;          switch(pInput->CallbackType)       {       case ModuleCallback:           if(pOutput->ModuleWriteFlags & ModuleWriteDataSeg)               if(!IsDataSectionNeeded(pInput->Module.FullPath))                   pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);       case IncludeModuleCallback:       case IncludeThreadCallback:       case ThreadCallback:       case ThreadExCallback:           return TRUE;       default:;       }          return FALSE;   }      inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)   {       HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,           FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);          if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))       {           MINIDUMP_EXCEPTION_INFORMATION mdei;           mdei.ThreadId           = GetCurrentThreadId();           mdei.ExceptionPointers  = pep;           mdei.ClientPointers     = NULL;              MINIDUMP_CALLBACK_INFORMATION mci;           mci.CallbackRoutine     = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;           mci.CallbackParam       = 0;              ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0, NULL, &mci);              CloseHandle(hFile);       }   }      LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)   {       CreateMiniDump(pExceptionInfo, "core.dmp");          return EXCEPTION_EXECUTE_HANDLER;   }      // 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效   void DisableSetUnhandledExceptionFilter()   {       void* addr = (void*)GetProcAddress(LoadLibrary("kernel32.dll"),           "SetUnhandledExceptionFilter");          if (addr)       {           unsigned char code[16];           int size = 0;              code[size++] = 0x33;           code[size++] = 0xC0;           code[size++] = 0xC2;           code[size++] = 0x04;           code[size++] = 0x00;              DWORD dwOldFlag, dwTempFlag;           VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);           WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);           VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);       }   }      void InitMinDump()   {       //注册异常处理函数       SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);          //使SetUnhandledExceptionFilter       DisableSetUnhandledExceptionFilter();   }   4.测试代码

    //test.cpp

    [cpp]  view plain copy #include <iostream>   #include "minidump.h"   void test()   {       std::string s = "abcd";          try{           s[100] = 'b';       }       catch(std::exception& e)       {           std::cout << "with exception:[" << e.what() << "]" << std::endl;       }       catch(...)       {           std::cout << "with unknown exception" << std::endl;       }   }      void main()   {       InitMinDump();          test();          system("pause");   }   转:http://blog.csdn.net/fhxpp_27/article/details/9701867
    转载请注明原文地址: https://ju.6miu.com/read-19124.html

    最新回复(0)