[Windows] Crashpad demo

测试有效,可以抓到 dump。

// 示例:基于 Crashpad 的 Windows 崩溃模拟与 dump 捕获
// 说明:
// - 默认使用 Windows DbgHelp 的 MiniDumpWriteDump 作为兜底;
// - 当定义 USE_CRASHPAD 且提供 crashpad_handler 与库时,启用 Crashpad 上报/采集;
// - 生成的 dump 输出到可执行文件旁的 artifacts/dumps 目录。
// 使用:
// - 正常构建运行:CrashPadSample.exe(默认立即触发崩溃)
// - 若需要参数控制,可改回解析 --crash 开关。
// 环境变量(启用 Crashpad 时可选):
// - CRASHPAD_HANDLER:crashpad_handler.exe 路径;为空则默认 bin/crashpad_handler.exe
// - CRASHPAD_INCLUDE:Crashpad 头文件目录(用于 CMake)
// - CRASHPAD_LIB_DIR:Crashpad 链接库目录(用于 CMake)
#include <windows.h>
#include <dbghelp.h>
#include <string>
#include <vector>
#include <filesystem>
#include <iostream>
#include <chrono>
#include <iomanip>
#include <sstream>

using namespace std;
#ifdef USE_CRASHPAD
#include "client/crashpad_client.h"
#include "client/crash_report_database.h"
#include "client/settings.h"
#include "base/files/file_path.h"
#endif

// 工具函数:UTF-8 转宽字符串(当前示例未用,可留作扩展)
static std::wstring WStringFromUtf8(const std::string& s) {
    int len = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, nullptr, 0);
    std::wstring ws;
    ws.resize(len ? len - 1 : 0);
    if (len) MultiByteToWideChar(CP_UTF8, 0, s.c_str(), -1, ws.data(), len);
    return ws;
}

// 获取当前可执行文件所在目录
static std::wstring ModuleDir() {
    wchar_t buffer[MAX_PATH];
    GetModuleFileNameW(nullptr, buffer, MAX_PATH);
    std::filesystem::path p(buffer);
    return p.parent_path().wstring();
}

// 生成时间戳(YYYYMMDD_HHMMSS),用于 dump 文件名
static std::wstring Timestamp() {
    auto now = std::chrono::system_clock::now();
    auto t = std::chrono::system_clock::to_time_t(now);
    std::tm tm{};
    localtime_s(&tm, &t);
    std::wstringstream ss;
    ss << std::put_time(&tm, L"%Y%m%d_%H%M%S");
    return ss.str();
}

// 未处理异常回调:写出本地 minidump(DbgHelp)
// 说明:
// - MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithThreadInfo
//   提供较完整的内存与线程上下文,便于分析;
// - 写入路径:<exe-dir>/artifacts/dumps/dssapp_<ts>.dmp
static LONG WINAPI DumpFilter(EXCEPTION_POINTERS* ep) {
    std::filesystem::path base = ModuleDir();
    std::filesystem::path dumps = base / L"artifacts" / L"dumps";
    std::error_code ec;
    std::filesystem::create_directories(dumps, ec);
    std::filesystem::path file = dumps / (L"dssapp_" + Timestamp() + L".dmp");
    HANDLE hFile = CreateFileW(file.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
    if (hFile == INVALID_HANDLE_VALUE) return EXCEPTION_EXECUTE_HANDLER;
    MINIDUMP_EXCEPTION_INFORMATION mei{};
    mei.ThreadId = GetCurrentThreadId();
    mei.ExceptionPointers = ep;
    mei.ClientPointers = FALSE;
    MINIDUMP_TYPE type = (MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithThreadInfo);
    MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, type, &mei, nullptr, nullptr);
    CloseHandle(hFile);
    return EXCEPTION_EXECUTE_HANDLER;
}

// 人为制造访问违规以触发崩溃
static void CauseCrash() {
    volatile int* p = nullptr;
    *p = 1;
}

#ifdef USE_CRASHPAD
// 启动 Crashpad handler:
// - 优先从环境变量 CRASHPAD_HANDLER 读取 handler 路径;否则尝试 bin/crashpad_handler.exe
// - 数据库目录设为 artifacts/dumps(方便统一查看)
// - 打印路径与启动结果,便于定位集成问题
static bool StartCrashpad() {
	std::wstring base = ModuleDir();
	std::wstring dumps = (std::filesystem::path(base) / L"artifacts" / L"dumps").wstring();
	std::wstring handler;

	wchar_t* env = nullptr;
	size_t sz = 0;
	_wdupenv_s(&env, &sz, L"CRASHPAD_HANDLER");
	if (env && sz) handler = env;
	if (env) free(env);

	if (handler.empty())
		handler = (std::filesystem::path(base) / L"bin" / L"crashpad_handler.exe").wstring();

	std::wcout << L"[Crashpad] Handler path: " << handler << std::endl;
	std::wcout << L"[Crashpad] DB path: " << dumps << std::endl;

	if (!std::filesystem::exists(handler)) {
		std::wcout << L"[Crashpad] ERROR: handler does NOT exist!" << std::endl;
	}

	std::filesystem::create_directories(dumps);
	if (!std::filesystem::exists(dumps)) {
		std::wcout << L"[Crashpad] ERROR: dumps directory NOT created!" << std::endl;
	}

	crashpad::CrashpadClient client;
	base::FilePath handler_path(handler);
	base::FilePath db_path(dumps);

	std::map<std::string, std::string> annotations;
	std::vector<std::string> arguments;

	bool success = client.StartHandler(handler_path, db_path, db_path, "",
		annotations, arguments,
		true /*restartable*/,
		false /*async*/);

	std::wcout << L"[Crashpad] StartHandler returned: " << success << std::endl;

	return success;
}

#endif

int main(int argc, wchar_t* argv[]) {
    // 程序入口:设置未处理异常过滤器、可选启动 Crashpad、触发崩溃
    cout << "hello world";
	SetUnhandledExceptionFilter(DumpFilter);
	bool use_crash = true;
#ifdef USE_CRASHPAD
	StartCrashpad();
#endif
	if (use_crash) {
		CauseCrash();
	}
	else {
		OutputDebugStringW(L"CrashPadSample running. Use --crash to simulate crash.\n");
	}
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值