欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 运维知识 > windows >内容正文

windows

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

发布时间:2023/12/20 windows 79 豆豆
生活随笔 收集整理的这篇文章主要介绍了 编写的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?
  • 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  print?
  • 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  print?
  • // 此函数一旦成功调用,之后对 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  print?
  • #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  print?
  • #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");  
  • }  
  • 总结

    以上是生活随笔为你收集整理的编写的windows程序,崩溃时产生crash dump文件的办法的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。