mingw崩溃日志分析。
This commit is contained in:
176
dumpDemo/crashdump.cpp
Normal file
176
dumpDemo/crashdump.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
#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();
|
||||
}
|
||||
Reference in New Issue
Block a user