0 dump文件作用
Dump
文件是进程的内存镜像,可以把程序的执行状态通过调试器保存到dump
文件中。
主要用来在系统中出现异常或者崩溃的时候生成dump
文件,然后用调试器进行调试,这样就可以把生产环境中程序崩溃后生成的dmp
文件拷贝到程序员的开发机上,通过调试找到程序出错的位置。
1 dump文件生成
代码封装如下:
#ifndef CREATE_DUMP_H_
#define CREATE_DUMP_H_
#pragma once
#include <string>
#include <Windows.h>
#include <DbgHelp.h>
#include <codecvt>
#pragma comment(lib, "dbghelp.lib")
class CCreateDump
{
public:
CCreateDump();
~CCreateDump(void);
static CCreateDump* Instance();
void CreateDumpFile(std::string str_dmp_file_name = "dumpfile");
private:
static long __stdcall UnhandleExceptionFilter(_EXCEPTION_POINTERS* pt_exception_info);
private:
static std::string m_st_str_dmp_file_name;
static CCreateDump* m_stp_instance;
};
CCreateDump* CCreateDump::m_stp_instance = nullptr;
std::string CCreateDump::m_st_str_dmp_file_name = "";
CCreateDump::CCreateDump()
{
}
CCreateDump::~CCreateDump(void)
{
}
CCreateDump* CCreateDump::Instance()
{
if (!m_stp_instance) {
m_stp_instance = new CCreateDump;
}
return m_stp_instance;
}
void CCreateDump::CreateDumpFile(std::string str_dmp_file_name)
{
SYSTEMTIME sys_time;
GetLocalTime(&sys_time);
char c[MAX_PATH];
sprintf_s(c, MAX_PATH, "%04d-%02d-%02d_%02d-%02d-%02d_", sys_time.wYear, sys_time.wMonth, sys_time.wDay, sys_time.wHour, sys_time.wMinute, sys_time.wSecond);
m_st_str_dmp_file_name = std::string(c);
if (!str_dmp_file_name.empty()) {
m_st_str_dmp_file_name += str_dmp_file_name;
}
m_st_str_dmp_file_name += std::string(".dmp");
SetUnhandledExceptionFilter(UnhandleExceptionFilter);
}
long CCreateDump::UnhandleExceptionFilter(_EXCEPTION_POINTERS* pt_exception_info)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converterX;
std::wstring wstr_dmp_file_name = converterX.from_bytes(m_st_str_dmp_file_name.c_str());
HANDLE h_dmp_file = CreateFile(wstr_dmp_file_name.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
if (h_dmp_file != INVALID_HANDLE_VALUE) {
MINIDUMP_EXCEPTION_INFORMATION mini_dump_ex_info;
mini_dump_ex_info.ThreadId = ::GetCurrentThreadId();
mini_dump_ex_info.ExceptionPointers = pt_exception_info;
mini_dump_ex_info.ClientPointers = FALSE;
// write the dump
BOOL b_ok = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), h_dmp_file, MiniDumpNormal, &mini_dump_ex_info, nullptr, nullptr);
CloseHandle(h_dmp_file);
if (!b_ok) {
DWORD dw = GetLastError();
return EXCEPTION_CONTINUE_SEARCH; //写dump文件出错处理,异常交给windows处理
}
else {
return EXCEPTION_EXECUTE_HANDLER; //在异常处结束
}
}
else {
return EXCEPTION_CONTINUE_SEARCH;
}
return EXCEPTION_EXECUTE_HANDLER;
}
#endif // !CREATE_DUMP_H_
测试demo如下:
#include "create_dump.h"
#include <iostream>
int main(void)
{
CCreateDump::Instance()->CreateDumpFile();
int* p = nullptr;
*p = 5;
std::system("pause");
return 0;
}
2 dump文件调试
编译并运行.exe
可执行程序后,将在.exe
同目录下生成.dmp
文件。
注:如果在
Visual Studio
中直接运行代码,程序将直接崩溃,不会生成.dmp
文件,因为Visual Studio
调试器已经捕获了异常,不会再进入设置的异常捕获函数UnhandleExceptionFilter
。
将.dmp,.exe(.dll),.pdb
文件放在同一目录,通过Visual Studio
打开.dmp
文件,如下:
点击“使用仅限本机进行调试”,调试结果如下,给出了报错的位置及调用堆栈信息:
若.exe(.dll),.pdb
文件与.dmp
文件不在同一目录,那么需要设置.exe(.dll),.pdb
的路径,如下:
否则将会出现未找到或加载.exe(.dll),.pdb
的情况,如下:
3 注意事项
3.1 exe/dll与pdb的版本必须一致
编译生成的.exe/.dll
文件与.pdb
文件版本必须一致,否则也会出现未找到或未加载.exe(.dll),.pdb
的情况。
调试器是如何来判别各文件版本是否一致呢?
每次链接生成.exe
或者.dll
时,链接器都将产生一个唯一的GUID
,然后将其写入到.pdb
文件和.exe
文件,每次重新编译,即使所有代码均没有变化,GUID
也不同。调试器加载这两个文件的时候将检查两者的GUID
,如果一致就表示他们匹配。
也就是说,dump
文件调试所需的.exe/.dll
与.pdb
文件,必须是由编译器在同一次编译过程中生成的,因此要妥善保管好.exe/.dll
和.pdb
文件。