1. 头文件
本文介绍在 MSVC 下使用 Win32 API 导出崩溃信息的方法。
#pragma once
// 必要的系统头文件
#include <Windows.h>
#include <DbgHelp.h>
#include <time.h>
#include <string>
#include <vector>
#include <sstream>
#include <iomanip>
// 链接 DbgHelp 库(MSVC 专用)
#pragma comment(lib, "Dbghelp.lib")
// 禁用安全警告(localtime_s 已替代不安全的 localtime)
#pragma warning(disable:4996)
namespace CRASHDMP_CPP {
// 异常代码转可读字符串
inline std::string ExceptionCodeToString(DWORD exceptionCode) {
switch (exceptionCode) {
case EXCEPTION_ACCESS_VIOLATION: return "EXCEPTION_ACCESS_VIOLATION (非法内存访问)";
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED (数组越界)";
case EXCEPTION_BREAKPOINT: return "EXCEPTION_BREAKPOINT (断点异常)";
EXCEPTION_DATATYPE_MISALIGNMENT: ;
EXCEPTION_FLT_DENORMAL_OPERAND: ;
EXCEPTION_FLT_DIVIDE_BY_ZERO: ;
EXCEPTION_FLT_INEXACT_RESULT: ;
EXCEPTION_FLT_INVALID_OPERATION: ;
EXCEPTION_FLT_OVERFLOW: ;
EXCEPTION_FLT_STACK_CHECK: ;
EXCEPTION_FLT_UNDERFLOW: ;
EXCEPTION_ILLEGAL_INSTRUCTION: ;
EXCEPTION_IN_PAGE_ERROR: ;
EXCEPTION_INT_DIVIDE_BY_ZERO: ;
EXCEPTION_INT_OVERFLOW: ;
EXCEPTION_INVALID_DISPOSITION: ;
EXCEPTION_NONCONTINUABLE_EXCEPTION: ;
EXCEPTION_PRIV_INSTRUCTION: ;
EXCEPTION_SINGLE_STEP: ;
EXCEPTION_STACK_OVERFLOW: ;
: {
buf[] = {};
(buf, , exceptionCode);
buf;
}
}
}
{
std::ostringstream oss;
SYSTEM_INFO sysInfo = {};
(&sysInfo);
oss << << (sysInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 ? : ) << ;
oss << << () << ;
oss << << () << ;
oss.();
}
{
(pExceptionPointers == ) ;
std::ostringstream oss;
HANDLE hProcess = ();
HANDLE hThread = ();
CONTEXT* pContext = pExceptionPointers->ContextRecord;
SYSTEM_INFO sysInfo = {};
(&sysInfo);
* szSymbolPath = ;
(!(hProcess, szSymbolPath, TRUE)) {
oss << << () << ;
oss.();
}
(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
STACKFRAME64 stackFrame = {};
DWORD machineType = ;
machineType = IMAGE_FILE_MACHINE_AMD64;
stackFrame.AddrPC.Offset = pContext->Rip;
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrFrame.Offset = pContext->Rbp;
stackFrame.AddrFrame.Mode = AddrModeFlat;
stackFrame.AddrStack.Offset = pContext->Rsp;
stackFrame.AddrStack.Mode = AddrModeFlat;
machineType = IMAGE_FILE_MACHINE_I386;
stackFrame.AddrPC.Offset = pContext->Eip;
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrFrame.Offset = pContext->Ebp;
stackFrame.AddrFrame.Mode = AddrModeFlat;
stackFrame.AddrStack.Offset = pContext->Esp;
stackFrame.AddrStack.Mode = AddrModeFlat;
oss << ;
frameIndex = ;
MAX_FRAMES = ;
((machineType, hProcess, hThread, &stackFrame, pContext, , SymFunctionTableAccess64, SymGetModuleBase64, ) && frameIndex < MAX_FRAMES) {
(stackFrame.AddrPC.Offset == ) ;
oss << << std::() << frameIndex << ;
oss << << std::hex << std::uppercase << stackFrame.AddrPC.Offset << ;
DWORD64 dwDisplacement = ;
szFuncName[] = ;
szModuleName[MAX_PATH] = ;
SYMBOL_INFO* pSymbol = (SYMBOL_INFO*)((SYMBOL_INFO) + );
(pSymbol != ) {
(pSymbol, , (SYMBOL_INFO) + );
pSymbol->SizeOfStruct = (SYMBOL_INFO);
pSymbol->MaxNameLen = ;
((hProcess, stackFrame.AddrPC.Offset, &dwDisplacement, pSymbol)) {
(szFuncName, (szFuncName), pSymbol->Name);
IMAGEHLP_MODULE64 moduleInfo = {};
moduleInfo.SizeOfStruct = (IMAGEHLP_MODULE64);
((hProcess, stackFrame.AddrPC.Offset, &moduleInfo)) {
(szModuleName, (szModuleName), moduleInfo.ModuleName);
}
}
(pSymbol);
}
oss << szFuncName << << szModuleName << << std::hex << dwDisplacement << ;
frameIndex++;
}
(frameIndex == ) {
oss << ;
}
(hProcess);
oss.();
}
;
CrashDumper* g_pGlobalCrashDumper = ;
{
:
m_originalErrorMode = (SEM_NOGPFAULTERRORBOX);
m_originalExceptionFilter = (UnhandledExceptionHandler);
}
~() {
(m_originalExceptionFilter);
(m_originalErrorMode);
}
( CrashDumper&) = ;
CrashDumper& =( CrashDumper&) = ;
:
std::vector<MINIDUMP_TYPE> s_miniDumpTypes;
std::vector<std::string> s_miniDumpTypeNames;
std::string m_successfulDumpType;
std::string m_dumpFilePrefix;
LPTOP_LEVEL_EXCEPTION_FILTER m_originalExceptionFilter;
UINT m_originalErrorMode;
{
now = ();
tm localTime{};
(&localTime, &now);
timeStamp[] = {};
(timeStamp, (timeStamp), , &localTime);
m_dumpFilePrefix + + timeStamp + ;
}
{
dumpPath + ;
}
{
(pExceptionPointers == ) ;
HANDLE hFile = (txtPath.(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, , CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, );
(hFile == INVALID_HANDLE_VALUE) ;
std::ostringstream oss;
oss << ;
SYSTEMTIME sysTime = {};
(&sysTime);
oss << << sysTime.wYear << << std::() << std::() << sysTime.wMonth << << std::() << sysTime.wDay << << std::() << sysTime.wHour << << std::() << sysTime.wMinute << << std::() << sysTime.wSecond << << std::() << sysTime.wMilliseconds << ;
oss << << () << ;
oss << << m_successfulDumpType << ;
oss << ;
oss << () << ;
oss << ;
EXCEPTION_RECORD* pExceptionRecord = pExceptionPointers->ExceptionRecord;
oss << << (pExceptionRecord->ExceptionCode) << ;
oss << << std::hex << std::uppercase << pExceptionRecord->ExceptionCode << ;
oss << << std::hex << std::uppercase << (DWORD64)pExceptionRecord->ExceptionAddress << ;
oss << << pExceptionRecord->NumberParameters << ;
(DWORD i = ; i < pExceptionRecord->NumberParameters; ++i) {
oss << << i + << << std::hex << std::uppercase << pExceptionRecord->ExceptionInformation[i] << ;
}
oss << ;
CONTEXT* pContext = pExceptionPointers->ContextRecord;
oss << << std::hex << std::uppercase << pContext->Rax << ;
oss << << std::hex << std::uppercase << pContext->Rbx << ;
oss << << std::hex << std::uppercase << pContext->Rcx << ;
oss << << std::hex << std::uppercase << pContext->Rdx << ;
oss << << std::hex << std::uppercase << pContext->Rip << ;
oss << << std::hex << std::uppercase << pContext->Rsp << ;
oss << << std::hex << std::uppercase << pContext->Eax << ;
oss << << std::hex << std::uppercase << pContext->Ebx << ;
oss << << std::hex << std::uppercase << pContext->Ecx << ;
oss << << std::hex << std::uppercase << pContext->Edx << ;
oss << << std::hex << std::uppercase << pContext->Eip << ;
oss << << std::hex << std::uppercase << pContext->Esp << ;
oss << ;
oss << (pExceptionPointers) << ;
std::string logContent = oss.();
DWORD bytesWritten = ;
BOOL writeResult = (hFile, logContent.(), (DWORD)logContent.(), &bytesWritten, );
(hFile);
writeResult && (bytesWritten == logContent.());
}
{
MINIDUMP_EXCEPTION_INFORMATION exceptionInfo = {};
exceptionInfo.ThreadId = ();
exceptionInfo.ExceptionPointers = pExceptionPointers;
exceptionInfo.ClientPointers = TRUE;
( i = ; i < s_miniDumpTypes.(); ++i) {
MINIDUMP_TYPE dumpType = s_miniDumpTypes[i];
std::string& dumpTypeName = s_miniDumpTypeNames[i];
HANDLE hFile = (dumpPath.(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, , CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, );
(hFile == INVALID_HANDLE_VALUE) {
;
}
BOOL dumpResult = ((), (), hFile, dumpType, pExceptionPointers ? &exceptionInfo : , , );
(hFile);
(dumpResult) {
m_successfulDumpType = dumpTypeName;
((dumpPath), pExceptionPointers);
;
}
}
(dumpPath);
;
}
{
HANDLE hFile = (filePath.(), GENERIC_READ, FILE_SHARE_READ, , OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, );
(hFile != INVALID_HANDLE_VALUE) {
DWORD fileSize = (hFile, );
(hFile);
(fileSize == ) {
(filePath.());
}
}
}
{
(g_pGlobalCrashDumper == ) {
(EXIT_FAILURE);
}
std::string dumpPath = g_pGlobalCrashDumper->();
g_pGlobalCrashDumper->(dumpPath, pExceptionPointers);
(EXIT_FAILURE);
EXCEPTION_EXECUTE_HANDLER;
}
};
LPTOP_LEVEL_EXCEPTION_FILTER CrashDumper::m_originalExceptionFilter = ;
UINT CrashDumper::m_originalErrorMode = ;
std::vector<MINIDUMP_TYPE> CrashDumper::s_miniDumpTypes = {
MiniDumpWithFullMemory,
MiniDumpWithFullMemoryInfo,
MiniDumpWithHandleData,
MiniDumpWithThreadInfo,
MiniDumpWithUnloadedModules,
MiniDumpNormal
};
std::vector<std::string> CrashDumper::s_miniDumpTypeNames = {
,
,
,
,
,
};
{
;
g_pGlobalCrashDumper = &crashDumper;
}
}


