windows下捕获dump
生活随笔
收集整理的這篇文章主要介紹了
windows下捕获dump
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
一般要捕獲異常只需要兩個函數(shù):SetUnhandledExceptionFilter截獲異常;MiniDumpWriteDump寫dump文件。但是由于CRT函數(shù)可能會在內(nèi)部調(diào)用SetUnhandledExceptionFilter(NULL),解除我們程序設(shè)置的異常處理,這導(dǎo)致我們的程序無法完整捕獲崩潰。另外,還有一部分非異常的CRT錯誤,不屬于SEH異常捕獲的范疇,需要通過_set_invalid_parameter_handler、_set_purecall_handler攔截,否則會彈出很丑陋的Runtime Error提示框。為保證所有異常都能由我們捕獲,需要把SetUnhandledExceptionFilter函數(shù)Hook掉,不讓“其他人”去設(shè)置自己的Exception處理,有Exception我們自己搞定;還有,對CRT錯誤做攔截,避免彈出錯誤窗口:_set_invalid_parameter_handler、_set_purecall_handler。 chromium的breakpad當(dāng)前只是使用了上邊提到的_set_invalid_parameter_handler、_set_purecall_handler函數(shù),并沒有屏蔽“其他人”的SetUnhandledExceptionFilter行為,可能導(dǎo)致了部分Crash無法捕獲,為什么不這么做呢?有待考察。(stackoverflow也有人提到這個問題:http://stackoverflow.com/questions/11350801/why-does-google-breakpad-not-handle-all-crashes-how-can-i-debug-these-cases)。 進程內(nèi)捕獲dump示例代碼: .h 1 namespace CatchDumpFile 2 {3 4 void simple_log(const std::wstring& log_msg);5 6 class CDumpCatch7 {8 public:9 CDumpCatch();
10 ~CDumpCatch();
11 private:
12
13 static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI TempSetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
14 static BOOL ReleaseDumpFile(const std::wstring& strPath, EXCEPTION_POINTERS *pException);
15 static LONG WINAPI UnhandledExceptionFilterEx(struct _EXCEPTION_POINTERS *pException);
16 static void MyPureCallHandler(void);
17 static void MyInvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved);
18
19
20 BOOL AddExceptionHandle();
21 BOOL RemoveExceptionHandle();
22 BOOL PreventSetUnhandledExceptionFilter();
23 void SetInvalidHandle();
24 void UnSetInvalidHandle();
25 private:
26 LPTOP_LEVEL_EXCEPTION_FILTER m_preFilter;
27 _invalid_parameter_handler m_preIph;
28 _purecall_handler m_prePch;
29 };
30 };
.cc
1 namespace CatchDumpFile2 {3 void simple_log(const std::wstring& log_msg)4 {5 std::wstring strLogWnd = L"cswuyg_simple_debug_log";6 HWND hSend = ::FindWindow(NULL, strLogWnd.c_str());7 COPYDATASTRUCT copydate;8 copydate.cbData = (DWORD)(log_msg.length() + 1) * sizeof(wchar_t);9 copydate.lpData = (PVOID)log_msg.c_str();10 ::SendMessage(hSend, WM_COPYDATA, 0, (LPARAM)©date);11 }12 13 void CDumpCatch::MyPureCallHandler(void)14 { 15 //simple_log(L"MyPureCallHandler");16 throw std::invalid_argument("");17 }18 19 void CDumpCatch::MyInvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)20 {21 //simple_log(L"MyPureCallHandler");22 //The parameters all have the value NULL unless a debug version of the CRT library is used.23 throw std::invalid_argument("");24 }25 26 void CDumpCatch::SetInvalidHandle()27 {28 #if _MSC_VER >= 1400 // MSVC 2005/829 m_preIph = _set_invalid_parameter_handler(MyInvalidParameterHandler);30 #endif // _MSC_VER >= 140031 m_prePch = _set_purecall_handler(MyPureCallHandler); //At application, this call can stop show the error message box.32 }33 void CDumpCatch::UnSetInvalidHandle()34 {35 #if _MSC_VER >= 1400 // MSVC 2005/836 _set_invalid_parameter_handler(m_preIph);37 #endif // _MSC_VER >= 140038 _set_purecall_handler(m_prePch); //At application this can stop show the error message box.39 }40 41 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI CDumpCatch::TempSetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter )42 {43 return NULL;44 }45 46 BOOL CDumpCatch::AddExceptionHandle()47 {48 m_preFilter = ::SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);49 PreventSetUnhandledExceptionFilter();50 return TRUE;51 }52 53 BOOL CDumpCatch::RemoveExceptionHandle()54 {55 if(m_preFilter != NULL)56 {57 ::SetUnhandledExceptionFilter(m_preFilter);58 m_preFilter = NULL;59 }60 return TRUE;61 }62 63 CDumpCatch::CDumpCatch()64 {65 SetInvalidHandle();66 AddExceptionHandle();67 }68 69 CDumpCatch::~CDumpCatch()70 {71 UnSetInvalidHandle();72 RemoveExceptionHandle();73 }74 75 BOOL CDumpCatch::ReleaseDumpFile(const std::wstring& strPath, EXCEPTION_POINTERS *pException)76 {77 HANDLE hDumpFile = ::CreateFile(strPath.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 78 if (hDumpFile == INVALID_HANDLE_VALUE)79 {80 return FALSE;81 }82 MINIDUMP_EXCEPTION_INFORMATION dumpInfo; 83 dumpInfo.ExceptionPointers = pException; 84 dumpInfo.ThreadId = ::GetCurrentThreadId(); 85 dumpInfo.ClientPointers = TRUE; 86 // ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hDumpFile, MiniDumpNormal, &dumpInfo, NULL, NULL); 87 BOOL bRet = ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hDumpFile, MiniDumpWithFullMemory, &dumpInfo, NULL, NULL); 88 ::CloseHandle(hDumpFile); 89 return bRet;90 }91 92 LONG WINAPI CDumpCatch::UnhandledExceptionFilterEx( struct _EXCEPTION_POINTERS *pException )93 {94 //simple_log(L"UnhandledExceptionFilterEx");95 wchar_t szPath[MAX_PATH] = { 0 };96 ::GetModuleFileName(NULL, szPath, MAX_PATH);97 ::PathRemoveFileSpec(szPath);98 std::wstring strPath = szPath;99 strPath += L"\\CrashDumpFile.dmp"; 100 BOOL bRelease = ReleaseDumpFile(strPath.c_str(), pException); 101 //::FatalAppExit(0, L"Error"); 102 if (bRelease) 103 { 104 return EXCEPTION_EXECUTE_HANDLER; 105 } 106 return EXCEPTION_CONTINUE_SEARCH; 107 } 108 109 BOOL CDumpCatch::PreventSetUnhandledExceptionFilter() 110 { 111 HMODULE hKernel32 = LoadLibrary(L"kernel32.dll"); 112 if (hKernel32 == NULL) 113 { 114 return FALSE; 115 } 116 void *pOrgEntry = ::GetProcAddress(hKernel32, "SetUnhandledExceptionFilter"); 117 if(pOrgEntry == NULL) 118 { 119 return FALSE; 120 } 121 122 unsigned char newJump[5]; 123 DWORD dwOrgEntryAddr = (DWORD)pOrgEntry; 124 dwOrgEntryAddr += 5; //jump instruction has 5 byte space. 125 126 void *pNewFunc = &TempSetUnhandledExceptionFilter; 127 DWORD dwNewEntryAddr = (DWORD)pNewFunc; 128 DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr; 129 130 newJump[0] = 0xE9; //jump 131 memcpy(&newJump[1], &dwRelativeAddr, sizeof(DWORD)); 132 SIZE_T bytesWritten; 133 DWORD dwOldFlag, dwTempFlag; 134 ::VirtualProtect(pOrgEntry, 5, PAGE_READWRITE, &dwOldFlag); 135 BOOL bRet = ::WriteProcessMemory(::GetCurrentProcess(), pOrgEntry, newJump, 5, &bytesWritten); 136 ::VirtualProtect(pOrgEntry, 5, dwOldFlag, &dwTempFlag); 137 return bRet; 138 } 139 140 } 能引發(fā)pure function called 錯誤的代碼: class IPureCall { public:virtual ~IPureCall(){};IPureCall(){//indirect call the virtual function, the compiler would not treat as "static binding", it is "dynamic binding".//At this time, the CPureCall class hasn't been constructed, the virtual table didn't has the pure_call function's point, so it cause "pure virtual function called exception".call_by_constructor();};virtual void pure_call() = 0;void call_by_constructor(){pure_call();} };class CPureCall : public IPureCall { public:CPureCall(){}void pure_call(){} }; pure virtual function called在之前的文章里介紹過(http://www.cnblogs.com/cswuyg/archive/2012/08/22/2650610.html)。 進程外捕獲崩潰的做法是使用進程間通信(IPC,內(nèi)存映射文件或者管道都行),把EXCEPTION_POINTERS指針數(shù)據(jù)等信息通知捕獲進程,讓捕獲進程去寫dump(windows下捕獲dump之Google breakpad_client的理解)。進程外捕獲dump是比較推薦的做法,chromium的breakpad文檔解釋說,“一般認為在崩潰進程內(nèi)部寫minidump是不安全的:關(guān)鍵的進程數(shù)據(jù)結(jié)構(gòu)可能會被破壞掉,或者異常處理程序獲取到的堆棧可能是被覆蓋了的”(原文:http://code.google.com/p/google-breakpad/wiki/GettingStartedWithBreakpad)。 可復(fù)用源碼分享:https://github.com/cswuyg/simple_win/tree/master/dump_catch/dump_catch ?多模塊dump處理相關(guān)補充: 1、如果CRT是/MD,那么CRT錯誤捕獲EXE、DLL共用;dump捕獲多EXE、DLL共用,只需要在EXE里加上處理就ok; 2、如果CRT是/MT,那么CRT錯誤捕獲各PE文件獨立,EXE、DLL必須有自己的處理;dump捕獲多EXE、DLL共用。 這方面的知識MSDN也稍有提及: http://technet.microsoft.com/zh-cn/library/t296ys27(v=vs.71) http://msdn.microsoft.com/en-us/library/windows/desktop/ms680634(v=vs.85).aspx 不錯的編程資料: http://www.cppblog.com/woaidongmao/archive/2009/10/21/99129.html http://www.codeproject.com/Articles/154686/SetUnhandledExceptionFilter-and-the-C-C-Runtime-Li http://www.cnblogs.com/FCoding/archive/2012/07/05/2578543.html 不錯的抓dump工具介紹: http://wintellect.com/blogs/jrobbins/how-to-capture-a-minidump-let-me-count-the-ways breakpad相關(guān)代碼: https://code.google.com/p/chromium/codesearch#chromium/src/breakpad/src/client/windows/handler/exception_handler.h總結(jié)
以上是生活随笔為你收集整理的windows下捕获dump的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php定义常量 define vs co
- 下一篇: LinQ中Skip()方法和Take()