前言:通過(guò)drwtsn32、NTSD、CDB等調(diào)試工具生成Dump文件, drwtsn32存在的缺點(diǎn)雖然NTSD、CDB可以完全解決,但并不是所有的操作系統(tǒng)中都安裝了NTSD、CDB等調(diào)試工具。了解了mini dump文件格式后,完全可以程序自動(dòng)生成Dump文件。
本文主要討論以下內(nèi)容:
1、 運(yùn)行原理
2、 程序修改
3、 注意事項(xiàng)
一、 運(yùn)行原理
當(dāng)程序遇到未處理異常(主要指非指針造成)導(dǎo)致程序崩潰死,如果在異常發(fā)生之前調(diào)用了SetUnhandledExceptionFilter()函數(shù),異常交給函數(shù)處理。MSDN中描述為:
Issuing SetUnhandledExceptionFilter replaces the existing top-level exception filter for all existing and all future threads in the calling process.
因而,在程序開(kāi)始處增加SetUnhandledExceptionFilter()函數(shù),并在函數(shù)中利用適當(dāng)?shù)姆椒ㄉ?/span>Dump文件,即可實(shí)現(xiàn)需要的功能。
二、 程序修改
1、 重載 << 操作符。(本步可以不實(shí)現(xiàn))
std::ostream& operator<<(std::ostream& os, const EXCEPTION_RECORD& red)
{
return os << " Thread ID:" << GetCurrentThreadId()
<< " ExceptionCode: " << red.ExceptionCode << "\n"
<< " ExceptionFlags: " << red.ExceptionFlags << "\n"
<< " ExceptionAddress: " << red.ExceptionAddress << "\n"
<< " NumberParameters: " << red.NumberParameters;
}
2、 實(shí)現(xiàn)UnhandledExceptionFilter
#include "minidmp.h"
LONG WINAPI GPTUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
CreateMiniDump(pExceptionInfo, L"Exception.dmp");
std::cerr << "未知錯(cuò)誤:" << (*pExceptionInfo->ExceptionRecord) << std::endl;
exit(pExceptionInfo->ExceptionRecord->ExceptionCode);
return EXCEPTION_EXECUTE_HANDLER; // 程序停止運(yùn)行
}
3、 在異常發(fā)生之前調(diào)用SetUnhandledExceptionFilter(GPTUnhandledExceptionFilter);
通常在Main()函數(shù)開(kāi)始時(shí)調(diào)用即可。
4、 CreateMiniDump()函數(shù)在minidmp.h頭文件中定義,文件如下:
#pragma once
#include <windows.h>
#include <imagehlp.h>
#include <stdlib.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);
case IncludeModuleCallback:
case IncludeThreadCallback:
case ThreadCallback:
case ThreadExCallback:
return TRUE;
default:;
}
return FALSE;
}
inline void CreateMiniDump(EXCEPTION_POINTERS* pep, LPCTSTR strFileName)
{
HANDLE hFile = CreateFile(strFileName, GENERIC_READ | 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)(MiniDumpWithPrivateReadWriteMemory |
MiniDumpWithDataSegs |
MiniDumpWithHandleData |
0x00000800 /*MiniDumpWithFullMemoryInfo*/ |
0x00001000 /*MiniDumpWithThreadInfo*/ |
MiniDumpWithUnloadedModules);
MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
hFile, mdt, (pep != 0) ? &mdei : 0, 0, &mci);
CloseHandle(hFile);
}
}
三、 注意事項(xiàng)
1、 可執(zhí)行文件(exe)必須找到dbghelp.dll,才能生成Dump文件。這個(gè)DLL可以從調(diào)試工具包中找到。
2、 當(dāng)異常代碼定位成功以后,如果無(wú)法阻止異常的產(chǎn)生,可以用 __try 結(jié)構(gòu)包裝異常代碼,__try 和 try 不同,前者可以捕獲非法指針產(chǎn)生的異常。
__try {
// 會(huì)異常的函數(shù)
}
__except( EXCEPTION_EXECUTE_HANDLER ){
// 異常處理
}
參考文檔:
http://blog.csdn.net/ArCoolGG/archive/2007/04/05/1553027.aspx
http://www.debuginfo.com/articles/effminidumps.html