生活随笔
收集整理的這篇文章主要介紹了
编写的windows程序,崩溃时产生crash dump文件的办法
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
一、引言
dump文件是C++程序發(fā)生異常時,保存當(dāng)時程序運行狀態(tài)的文件,是調(diào)試異常程序重要的方法,所以程序崩潰時,除了日志文件,dump文件便成了我們查找錯誤的最后一根救命的稻草。windows程序產(chǎn)生dump文件和linux程序產(chǎn)生dump文件的方式不一樣,linux默認(rèn)是不讓產(chǎn)生core dump文件,只要在用戶自己的~/.bash_profile文件中增加
ulimit -S -c unlimited > /dev/null 2>&1
這樣程序崩潰就可以產(chǎn)生可調(diào)試的core dump文件了。但是windows環(huán)境就得寫代碼才能實現(xiàn)了。
二、原理
windows程序當(dāng)遇到異常,沒有try-catch或者try-catch也無法捕獲到的異常時,程序就會自動退出,如果這時候沒有dump文件的話,我們是沒有得到任何程序退出的信息。在windows程序異常退出之前,會預(yù)先調(diào)用一個在程序中注冊的異常處理回調(diào)函數(shù)(默認(rèn)是沒有設(shè)置),只要我們在這個回調(diào)函數(shù)中調(diào)用MiniDumpWriteDump函數(shù)就可以產(chǎn)生我們想要的dump文件。
三、實現(xiàn)
1.調(diào)用SetUnhandledExceptionFilter注冊一個自定義的異常處理回調(diào)函數(shù)
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
異常處理回調(diào)函數(shù)的原型
LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo);
2.CreateFile創(chuàng)建dump文件,調(diào)用MiniDumpWriteDump函數(shù)往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函數(shù)是在異常處理回調(diào)函數(shù)MyUnhandledExceptionFilter中調(diào)用的
[cpp]?view plain
?copy ?print?
LONG?__stdcall?MyUnhandledExceptionFilter(PEXCEPTION_POINTERS?pExceptionInfo)?? {?? ????CreateMiniDump(pExceptionInfo,?"core.dmp");?? ?? ????return?EXCEPTION_EXECUTE_HANDLER;?? }??
3.將SetUnhandledExceptionFilter失效
vs2005中,編譯的過程中,編譯器會自動給你的程序加上一句SetUnhandledExceptionFilter(NULL),這就會導(dǎo)致你之前自定義的
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
無效,就有可能不會產(chǎn)生dump文件,因此我們必須在自定義的SetUnhandledExceptionFilter之后,讓之后調(diào)用的SetUnhandledExceptionFilter無效。增加以下代碼:
[cpp]?view plain
?copy ?print?
?? 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;?? }?? ?? ?? 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);?? ?? ?????? ????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");?? }??
總結(jié)
以上是生活随笔為你收集整理的编写的windows程序,崩溃时产生crash dump文件的办法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。