Files
mingwSpecial/dumpDemo/crashdump.cpp

177 lines
6.3 KiB
C++
Raw Normal View History

2026-03-23 16:42:28 +08:00
#include "crashdump.h"
#include <iomanip>
#include <sstream>
CrashDump::CrashDump(EXCEPTION_POINTERS* exp) : exp_(exp)
{
}
std::string CrashDump::GetModuleByReAddr(PBYTE retAddr, PBYTE& moduleAddr)
{
MODULEENTRY32 M = {sizeof(M)};
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0);
char moduleName[MAX_PATH]{};
if (hSnapshot != INVALID_HANDLE_VALUE && Module32First(hSnapshot, &M)) {
do {
if (DWORD(retAddr - M.modBaseAddr) < M.modBaseSize) {
std::snprintf(moduleName, MAX_PATH, "%s", M.szExePath);
moduleAddr = M.modBaseAddr;
break;
}
} while (Module32Next(hSnapshot, &M));
}
std::string name(moduleName);
return name;
}
std::string CrashDump::GetVersion()
{
OSVERSIONINFO V = {sizeof(OSVERSIONINFO)};
if (!GetVersionEx((POSVERSIONINFO)&V)) {
ZeroMemory(&V, sizeof(V));
V.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx((POSVERSIONINFO)&V);
}
if (V.dwPlatformId != VER_PLATFORM_WIN32_NT) {
V.dwBuildNumber = LOWORD(V.dwBuildNumber);
}
char buffer[512]{};
std::snprintf(buffer, sizeof(buffer), "Windows: %ld.%ld.%ld, %s.", V.dwMajorVersion, V.dwMinorVersion, V.dwBuildNumber,
V.szCSDVersion);
std::string info(buffer);
return info;
}
std::string CrashDump::GetExceptionInfo()
{
char moduleName[MAX_PATH]{};
PBYTE moduleAddr{};
GetModuleFileName(NULL, moduleName, MAX_PATH);
if (exp_ == nullptr) {
return "Not Set Exception Pointer.";
}
std::ostringstream oss;
auto& E = exp_->ExceptionRecord;
auto& C = exp_->ContextRecord;
oss << "ExceptionAddr: " << E->ExceptionAddress << "\n";
oss << "ExceptionCode: " << E->ExceptionCode << "\n";
if (E->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
oss << (E->ExceptionInformation[0] ? "Write " : "Read ");
oss << E->ExceptionInformation[1] << "\n";
}
oss << "Instruction:";
for (int i = 0; i < 16; i++) {
oss << " " << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(PBYTE(E->ExceptionAddress)[i]);
}
oss << std::hex << std::setfill('0');
// 1. 基本寄存器组
oss << "\nGeneral Purpose Registers:"
<< "\nRAX: " << std::setw(16) << C->Rax << " RBX: " << std::setw(16) << C->Rbx << " RCX: " << std::setw(16) << C->Rcx
<< " RDX: " << std::setw(16) << C->Rdx
<< "\nRSI: " << std::setw(16) << C->Rsi << " RDI: " << std::setw(16) << C->Rdi << " RBP: " << std::setw(16) << C->Rbp
<< " RSP: " << std::setw(16) << C->Rsp
<< "\nR8: " << std::setw(16) << C->R8 << " R9: " << std::setw(16) << C->R9 << " R10: " << std::setw(16) << C->R10
<< " R11: " << std::setw(16) << C->R11
<< "\nR12: " << std::setw(16) << C->R12 << " R13: " << std::setw(16) << C->R13 << " R14: " << std::setw(16) << C->R14
<< " R15: " << std::setw(16) << C->R15;
// 2. 关键控制寄存器
oss << "\n\nControl Registers:"
<< "\nRIP: " << std::setw(16) << C->Rip << " EFLAGS: " << std::setw(8) << C->EFlags << " CS: " << std::setw(4)
<< C->SegCs << " SS: " << std::setw(4) << C->SegSs;
// 3. 调试寄存器(如果有用)
if (C->ContextFlags & CONTEXT_DEBUG_REGISTERS) {
oss << "\n\nDebug Registers:"
<< "\nDR0: " << std::setw(16) << C->Dr0 << " DR1: " << std::setw(16) << C->Dr1 << " DR2: " << std::setw(16)
<< C->Dr2 << " DR3: " << std::setw(16) << C->Dr3 << "\nDR6: " << std::setw(16) << C->Dr6
<< " DR7: " << std::setw(16) << C->Dr7;
}
// 4. MXCSR状态(浮点/SSE)
if (C->ContextFlags & CONTEXT_FLOATING_POINT) {
oss << "\n\nFPU/SSE State:"
<< "\nMXCSR: " << std::setw(8) << C->MxCsr;
}
// 5. 最后分支记录(如果可用)
if (C->LastBranchToRip || C->LastBranchFromRip) {
oss << "\n\nLast Branch:"
<< "\nFrom: " << std::setw(16) << C->LastBranchFromRip << " To: " << std::setw(16) << C->LastBranchToRip;
}
oss << GetCallStack(exp_) << "\n";
return oss.str();
}
std::string CrashDump::GetCallStack(EXCEPTION_POINTERS* exp)
{
struct StackFrame {
StackFrame* prev_frame;
void* return_address;
};
std::ostringstream oss;
StackFrame* current_frame = nullptr;
// 1. 初始化栈帧指针
if (exp) {
// 异常情况:从异常上下文中获取栈帧
#if defined(_M_X64) || defined(__x86_64__)
current_frame = reinterpret_cast<StackFrame*>(exp->ContextRecord->Rbp);
#else
current_frame = reinterpret_cast<StackFrame*>(exp->ContextRecord->Ebp);
#endif
} else {
// 非异常情况:手动获取当前栈帧(编译器相关)
#if defined(__GNUC__) || defined(__clang__)
// GCC/Clang 内联汇编获取 EBP/RBP
#if defined(__x86_64__)
register void* frame_ptr asm("rbp");
#else
register void* frame_ptr asm("ebp");
#endif
current_frame = reinterpret_cast<StackFrame*>(frame_ptr);
#elif defined(_MSC_VER)
// MSVC 内置函数(如果可用)
current_frame = reinterpret_cast<StackFrame*>(_AddressOfReturnAddress() - sizeof(void*));
#else
return "Stack walking not supported on this compiler";
#endif
}
// 2. 遍历调用栈
constexpr size_t max_frames = 64;
PBYTE module_addr = nullptr;
for (size_t i = 0; i < max_frames && current_frame; ++i) {
// 安全检查
if (IsBadReadPtr(current_frame, sizeof(StackFrame)) ||
IsBadCodePtr(reinterpret_cast<FARPROC>(current_frame->return_address))) {
break;
}
// 格式化输出
oss << "\n0x" << std::hex << std::setw(8) << std::setfill('0')
<< reinterpret_cast<uintptr_t>(current_frame->return_address) << " ";
// 获取模块信息
std::string module_name = GetModuleByReAddr(reinterpret_cast<PBYTE>(current_frame->return_address), module_addr);
if (!module_name.empty()) {
DWORD rva = static_cast<DWORD>(reinterpret_cast<PBYTE>(current_frame->return_address) - module_addr);
// 输出模块信息和RVA
oss << " (RVA: 0x" << std::hex << std::setw(8) << std::setfill('0') << rva << ") " << module_name;
}
// 移动到上一栈帧
current_frame = current_frame->prev_frame;
}
return oss.str();
}