Windows c++ 崩溃时生成 dump 文件

1、背景

在做 Windows 客户端应用开发时,难免遇到程序的崩溃,当程序在 debug 崩溃时,我们可以直接定位到崩溃点,但是当程序打包成 release 发布时,难免也会遇到一些崩溃问题(当然在开发时要尽量保障程序的稳定性),一般遇到这样的崩溃,我们就需要使用 dump 文件加上符号表文件来进行调试程序,所以一般的 CI 除了将 exe 上传以外还需要将符号表信息上传。

2、在代码中生成 dump 文件

#include <Windows.h>
#include <DbgHelp.h>
#include <tchar.h>
#include <shlobj_core.h>
#include <io.h>
#include <direct.h>

#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>

// 生成 dump 文件的目录名称
const std::string& kDUMPDir = "\\MyDumpTest";
typedef BOOL(WINAPI * MiniDumpWriteDumpT)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
	PMINIDUMP_EXCEPTION_INFORMATION, PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION);

int CreateDump(PEXCEPTION_POINTERS pointers) {
	HMODULE dbg_help = LoadLibrary("DbgHelp.dll");
	if (NULL == dbg_help) {
		return EXCEPTION_CONTINUE_EXECUTION;
	}

	MiniDumpWriteDumpT dump_writer = (MiniDumpWriteDumpT)GetProcAddress(dbg_help, "MiniDumpWriteDump");
	if (NULL == dump_writer) {
		FreeLibrary(dbg_help);
		return EXCEPTION_CONTINUE_EXECUTION;
	}

	// 获取到 %localappdata% 目录
	char buffer[256] = "";
	SHGetSpecialFolderPathA(NULL, buffer, CSIDL_LOCAL_APPDATA, FALSE);

	std::string dump_dir = buffer;
	dump_dir += kDUMPDir;
	std::cout << "dump_dir:" << dump_dir << std::endl;
	// 判断文件夹是否存在
	if (_access(dump_dir.c_str(), 0) == -1) {
		// 如果不存在,那么就创建
		_mkdir(dump_dir.c_str());
	}

	// dmp 文件名
	SYSTEMTIME local_time;
	GetLocalTime(&local_time);

	std::stringstream ss;
	ss << dump_dir << "\\dump-" << local_time.wYear << "-" <<
		std::setw(2) << std::setfill('0') << local_time.wMonth << "-" <<
		std::setw(2) << std::setfill('0') << local_time.wDay << "-" <<
		std::setw(2) << std::setfill('0') << local_time.wHour <<
		std::setw(2) << std::setfill('0') << local_time.wMinute <<
		std::setw(2) << std::setfill('0') << local_time.wSecond << ".dmp";

	HANDLE dump_file = CreateFile(ss.str().c_str(), GENERIC_READ | GENERIC_WRITE,
		FILE_SHARE_WRITE | FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
	if (INVALID_HANDLE_VALUE == dump_file) {
		FreeLibrary(dbg_help);
		return EXCEPTION_CONTINUE_EXECUTION;
	}

	// 写入 dmp 文件
	MINIDUMP_EXCEPTION_INFORMATION param;
	param.ThreadId = GetCurrentThreadId();
	param.ExceptionPointers = pointers;
	param.ClientPointers = FALSE;

    // MiniDumpWithDataSegs : dump 文件的类型,一般这个就够了
    // MiniDumpNormal 比较小 MiniDumpWithFullMemory 比较大
	dump_writer(GetCurrentProcess(), GetCurrentProcessId(),
		dump_file, MiniDumpWithDataSegs, (pointers ? &param : NULL), NULL, NULL);

	// 释放文件
	CloseHandle(dump_file);
	FreeLibrary(dbg_help);
	return 0;
}

LONG WINAPI ExceptionFilter(LPEXCEPTION_POINTERS pointers) {
	// 这里做一些异常的过滤或提示
	if (IsDebuggerPresent()) {
		return EXCEPTION_CONTINUE_SEARCH;
	}
	return CreateDump(pointers);
}
int main(int argc, char *argv[]) {
	SetUnhandledExceptionFilter(ExceptionFilter);
	// 执行程序
	int* p = nullptr;
	p[0] = 1;
	std::cout << "end" << std::endl;
	getchar();
	return 0;
}

3、运行程序

这里运行程序,不是在 vs 里面运行,而是指双击 exe 进行运行,然后程序会 crash ,这个时候在对应目录下面查看是否有生成 dump 文件

下来就可以使用 windbg 或者 vs 调试 dump 文件了


版权声明:本文为yp18792574062原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。