来源:
软件发生异常,没有调试环境,怎么快速定位问题?遇到这类问题,最有的信息就是生成dump文件,然后通过dump文件查看callstack等信息定位。
Dump文件生成原理:
利用dbghelp使用SetUnhandledExceptionFilter设置回调函数生成dump文件,后分析异常地方。
本文实现方式:分装类在MFC程序中调用并分析
1、类的实现
//CreateDump.h
#pragma once
#include <string>
using namespace std;
class CCreateDump
{
public:
CCreateDump();
~CCreateDump(void);
static CCreateDump* Instance();
static long __stdcall UnhandleExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo);
//声明Dump文件,异常时会自动生成。会自动加入.dmp文件名后缀
void DeclarDumpFile(std::string dmpFileName = "");
private:
static std::string strDumpFile;
static CCreateDump* __instance;
};
//CreateDump.cpp
#include "stdafx.h"
#include "CreateDump.h"
#include <DbgHelp.h>
#pragma comment(lib, "dbghelp.lib")
CCreateDump* CCreateDump::__instance = NULL;
std::string CCreateDump::strDumpFile = "";
CCreateDump::CCreateDump()
{
}
CCreateDump::~CCreateDump(void)
{
}
long CCreateDump::UnhandleExceptionFilter(_EXCEPTION_POINTERS* ExceptionInfo)
{
HANDLE hFile = CreateFileA(strDumpFile.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL, NULL );
if(hFile!=INVALID_HANDLE_VALUE)
{
MINIDUMP_EXCEPTION_INFORMATION ExInfo;
ExInfo.ThreadId = ::GetCurrentThreadId();
ExInfo.ExceptionPointers = ExceptionInfo;
ExInfo.ClientPointers = FALSE;
// write the dump
BOOL bOK = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL );
CloseHandle(hFile);
if (!bOK)
{
DWORD dw = GetLastError();
//写dump文件出错处理,异常交给windows处理
return EXCEPTION_CONTINUE_SEARCH;
}
else
{ //在异常处结束
return EXCEPTION_EXECUTE_HANDLER;
}
}
else
{
return EXCEPTION_CONTINUE_SEARCH;
}
}
void CCreateDump::DeclarDumpFile(std::string dmpFileName)
{
SYSTEMTIME syt;
GetLocalTime(&syt);
char c[MAX_PATH];
sprintf_s(c,MAX_PATH,"[%04d-%02d-%02d %02d:%02d:%02d]",syt.wYear,syt.wMonth,syt.wDay,syt.wHour,syt.wMinute,syt.wSecond);
strDumpFile = std::string(c);
if (!dmpFileName.empty())
{
strDumpFile += dmpFileName;
}
strDumpFile += std::string(".dmp");
SetUnhandledExceptionFilter(UnhandleExceptionFilter);
}
CCreateDump* CCreateDump::Instance()
{
if (__instance == NULL)
{
__instance = new CCreateDump;
}
return __instance;
}
2、调用和产生方式
在程序初始化时候调用:
CCreateDump::Instance()->DeclarDumpFile("dumpfile");
3、写出异常代码
int a = 9;
int b = 0;
int c = 0;
c = a / b;
运行程序,并执行此处代码(运行目录下生成dump文件)
4、把dmp文件和exe, pdb文件放在同一目录下,然后用编译器(如vc)打开dmp文件,然后开始调试就会中断到刚才异常的地方。