场景:
1. Release的程序崩溃时,崩溃报告可以让开发人员查明代码哪里出了问题,用处大大的。
2. 只有用VS的编译器才支持,所以MinGW就无缘了。
3. 使用了未处理异常过滤处理函数.
4. 生成的.dmp文件用zlib库压缩, 用到以下的ZipHelper类,编译时还是需要zlib库和dbghelp.lib
http://blog.csdn.net/infoworld/article/details/41290969
5. 使用方式就是把DbgReport作为app类的成员变量,或者文件范围的全局变量初始化后,在程序运行开始前调用
RegisterCrashFilter
6. 更新: 增加VC CRT异常捕抓. 2015-09-25
参考:
http://blog.csdn.net/limiteee/article/details/8472179
bas_dbg_report.h
#ifndef __BAS_DBG_REPORT #define __BAS_DBG_REPORT #include "bas_exp.h" //1.可以自己修改参数,添加额外信息. typedef void (*BASReportCallbackFunc)(const wchar_t* dump_zip_path); class LIB_BASIC BASDbgReport { public: void RegisterCrashFilter(const wchar_t* dump_path,BASReportCallbackFunc func); }; #endif
bas_dbg_report.cpp
#include "basic/bas_dbg_report.h" #include <Windows.h> #include <DbgHelp.h> #include "basic/bas_utility_string.h" #include "basic/bas_wrap_object.h" #include "basic/bas_utility_zip.h" static std::wstring gDumpPath; static std::wstring gDumpZipPath; static BASReportCallbackFunc gReportCallbackFunc = NULL; static BOOL IsDataSectionNeeded(const WCHAR* pModuleName) { if(pModuleName == NULL) { return FALSE; } WCHAR szFileName[_MAX_FNAME] = L""; _wsplitpath(pModuleName, NULL, NULL, szFileName, NULL); if(wcsicmp(szFileName, L"ntdll") == 0) return TRUE; return FALSE; } static 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; } static LONG WINAPI TopLevelUnhandledExceptionFilter(PEXCEPTION_POINTERS pExInfo) { HANDLE hFile = ::CreateFile( gDumpPath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if( hFile != INVALID_HANDLE_VALUE) { MINIDUMP_EXCEPTION_INFORMATION einfo; einfo.ThreadId = ::GetCurrentThreadId(); einfo.ExceptionPointers = pExInfo; einfo.ClientPointers = FALSE; MINIDUMP_CALLBACK_INFORMATION mci; mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback; mci.CallbackParam = NULL; ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile,MiniDumpNormal,&einfo, NULL, &mci); ::CloseHandle(hFile); } //1.压缩dmp文件和其他 char* utf8 = BASUtilityString::ConvertUnicodeToUtf8(gDumpPath.c_str()); BASWrapMalloc wm1(utf8); BASUtilityZip z; z.AddFile(utf8); std::string output(utf8); output.append(".zip"); wchar_t* unicode = BASUtilityString::ConvertUtf8ToUnicode(output.c_str()); BASWrapMalloc wm2(unicode); gDumpZipPath.append(unicode); z.ToZip(output.c_str()); if(gReportCallbackFunc) { gReportCallbackFunc(gDumpZipPath.c_str()); } return EXCEPTION_EXECUTE_HANDLER; } static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) { return NULL; } static BOOL PreventSetUnhandledExceptionFilter() { HMODULE hKernel32 = LoadLibrary(L"kernel32.dll"); if (hKernel32 == NULL) return FALSE; void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter"); if(pOrgEntry == NULL) return FALSE; unsigned char newJump[ 100 ]; DWORD dwOrgEntryAddr = (DWORD) pOrgEntry; dwOrgEntryAddr += 5; // add 5 for 5 op-codes for jmp far void *pNewFunc = &MyDummySetUnhandledExceptionFilter; DWORD dwNewEntryAddr = (DWORD) pNewFunc; DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr; newJump[ 0 ] = 0xE9; // JMP absolute memcpy(&newJump[ 1 ], &dwRelativeAddr, sizeof(pNewFunc)); SIZE_T bytesWritten; BOOL bRet = WriteProcessMemory(GetCurrentProcess(), pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten); return bRet; } void BASDbgReport::RegisterCrashFilter(const wchar_t* dump_path,BASReportCallbackFunc func) { #ifndef _DEBUG gDumpPath.append(dump_path); gReportCallbackFunc = func; SetUnhandledExceptionFilter(TopLevelUnhandledExceptionFilter); BOOL bRet = PreventSetUnhandledExceptionFilter(); #endif }