CrashReport,BugReport的核心--创建dump文件
2016-04-20 14:45
417 查看
// minidmp.h #pragma once #include <windows h=""> #include <imagehlp h=""> #include <stdlib h=""> #include <strsafe h=""> #pragma comment(lib, "dbghelp.lib") 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); break; case IncludeModuleCallback: case IncludeThreadCallback: case ThreadCallback: case ThreadExCallback: return TRUE; default: break; } return FALSE; } //创建Dump文件 inline void CreateMiniDump(EXCEPTION_POINTERS *pep, LPCWSTR strFileName) { HANDLE hFile = CreateFileW(strFileName, GENERIC_WRITE, 0, 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 = FALSE; MINIDUMP_CALLBACK_INFORMATION mci; mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback; mci.CallbackParam = 0; MINIDUMP_TYPE mdt = (MINIDUMP_TYPE)0x0000ffff; MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, NULL, &mci); CloseHandle(hFile); } } LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) { return NULL; } BOOL PreventSetUnhandledExceptionFilter() { HMODULE hKernel32 = LoadLibrary(_T("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; } LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException) { WCHAR szPath[MAX_PATH]; WCHAR szFileName[MAX_PATH]; WCHAR *szAppName = L"DumpFile"; HANDLE hDumpFile; SYSTEMTIME stLocalTime; MINIDUMP_EXCEPTION_INFORMATION ExpParam; GetLocalTime( &stLocalTime ); //GetTempPath( dwBufferSize, szPath ); GetModuleFileNameW(NULL, szPath, MAX_PATH); wchar_t *pstr = wcsrchr(szPath, '\\'); memset(pstr + 1, 0, 2); StringCchPrintfW( szFileName, MAX_PATH, L"%s%s", szPath, szAppName ); CreateDirectoryW( szFileName, NULL ); StringCchPrintfW( szFileName, MAX_PATH, L"%s%s\\%04d%02d%02d-%02d%02d%02d.dmp", szPath, szAppName, stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay, stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond); CreateMiniDump(pException, szFileName); // TODO: 这里可以将dump文件通过邮件发送给开发者,也可以通过http发送给服务端,服务端管理dump文件 FatalAppExit(-1, _T("*** Unhandled Exception! ***")); return EXCEPTION_CONTINUE_SEARCH; } //运行异常处理 void RunCrashHandler() { SetUnhandledExceptionFilter(UnhandledExceptionFilterEx); PreventSetUnhandledExceptionFilter(); }
// Test.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include "minidmp.h" void CrashTest() { strcpy(NULL,"adfadfg"); } int _tmain(int argc, _TCHAR* argv[]) { //设置异常处理回调函数 RunCrashHandler(); CrashTest(); getchar(); return 0; }
核心就是这样了,注意点:程序发布时记得带上dbghelp.dll,这个是系统dll,开发机上肯定都会有。剩下的就是把dump文件上传到服务器或者直接使用邮件发到指定邮箱了。
有了dump文件,结合发布版本的pdb文件以及源代码就能很快定位到崩溃点了。
相关文章推荐
- CSS渲染原理
- eclipse 中解决 git 冲突
- RequiredFieldValidator控件用法简介
- Jqurey图片放大镜插件
- 车载导航系统中常用物理量和单位
- ESB 12种跑法
- Unhandled event loop exception Item not added
- iOS - 系统自带的分享功能
- 模拟spi如何写
- C++自定义缓冲区streambuf
- HTML5 Speech API和Audio API
- Linux常用命令
- java开发工具下载地址汇总
- 第十七篇【测试数据准备的那些事儿】
- [改善Java代码]警惕自增的陷阱
- 圣杯布局
- redis-cli 命令总结
- vsearch 去除重复序列和singleton 序列
- 比较数字大小
- 二分查找的递归及非递归实现