fix: 移除 ExceptionStacktrace.hpp

This commit is contained in:
status102
2026-01-11 08:50:43 +08:00
parent ae1ab6291c
commit 9c99a93dd2
2 changed files with 0 additions and 441 deletions

View File

@@ -1,420 +0,0 @@
#pragma once
#ifdef _WIN32
#include <fcntl.h>
#include <io.h>
#define NOMINMAX
#include <dbghelp.h>
#include <windows.h>
#include <winsock2.h>
#pragma comment(lib, "dbghelp.lib")
#undef NOMINMAX
#elif defined(__unix__) || defined(__APPLE__)
#include <cxxabi.h>
#include <dlfcn.h>
#include <execinfo.h>
#include <unistd.h>
#endif
#ifdef __linux__
#include <cstdio>
#include <cstring>
#include <fstream>
#include <limits.h>
#endif
#ifdef __APPLE__
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
#endif
#include <format>
#include <iostream>
#include <string>
#include "Logger.hpp"
namespace asst::utils
{
class ExceptionStacktrace
{
public:
static uintptr_t get_base_address()
{
#ifdef _WIN32
// 获取 MaaCore.dll 的基址(通过当前函数地址定位所属模块)
HMODULE hModule = NULL;
BOOL ret = GetModuleHandleExA(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
reinterpret_cast<LPCSTR>(&get_base_address),
&hModule);
if (!ret) {
return 0;
}
return reinterpret_cast<uintptr_t>(hModule);
#elif defined(__APPLE__)
// MacOS: 通过当前函数地址查找所属模块
Dl_info info;
if (dladdr(reinterpret_cast<void*>(&get_base_address), &info)) {
return reinterpret_cast<uintptr_t>(info.dli_fbase);
}
// 回退到主模块
const struct mach_header* header = _dyld_get_image_header(0);
return reinterpret_cast<uintptr_t>(header);
#else // Linux and other Unix-like systems
// 优先通过 dladdr 获取当前函数所属模块
Dl_info info;
if (dladdr(reinterpret_cast<void*>(&get_base_address), &info) && info.dli_fbase) {
return reinterpret_cast<uintptr_t>(info.dli_fbase);
}
// 回退:扫描 /proc/self/maps优先匹配当前可执行文件的 r-x 段
std::ifstream maps("/proc/self/maps");
if (!maps.is_open()) {
return 0;
}
// 读取当前可执行文件路径
std::string exe_path;
{
char buf[PATH_MAX] = { 0 };
ssize_t len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
if (len > 0) {
buf[len] = '\0';
exe_path.assign(buf);
}
}
auto trim_deleted = [](std::string& p) {
constexpr const char* suffix = " (deleted)";
size_t len = std::strlen(suffix);
if (p.size() >= len && p.compare(p.size() - len, len, suffix) == 0) {
p.erase(p.size() - len);
}
};
uintptr_t fallback_addr = 0;
std::string line;
while (std::getline(maps, line)) {
// 格式示例00400000-0040c000 r--p ... /path/to/exe
unsigned long start_raw = 0;
char perms[5] = { 0 };
char pathbuf[PATH_MAX] = { 0 };
int matched = std::sscanf(line.c_str(), "%lx-%*lx %4s %*s %*s %*s %4095s", &start_raw, perms, pathbuf);
if (matched < 2) { // 至少要有地址和权限
continue;
}
// 只考虑可执行段
if (std::strlen(perms) < 3 || perms[0] != 'r' || perms[2] != 'x') {
continue;
}
uintptr_t start_addr = static_cast<uintptr_t>(start_raw);
std::string path = matched == 3 ? pathbuf : "";
if (!path.empty()) {
trim_deleted(path);
// 跳过虚拟段
if (!path.empty() && path.front() == '[') {
continue;
}
if (!exe_path.empty() && path == exe_path) {
return start_addr;
}
}
// 记录首个可执行段兜底
if (fallback_addr == 0) {
fallback_addr = start_addr;
}
}
return fallback_addr;
#endif
}
#ifdef _WIN32
// Windows 异常堆栈跟踪实现
static std::string capture_exception_stack_trace(PEXCEPTION_POINTERS pExceptionInfo)
{
std::string result;
HANDLE process = GetCurrentProcess();
HANDLE thread = GetCurrentThread();
// 初始化符号处理器
SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
if (!SymInitialize(process, NULL, TRUE)) {
return "Failed to initialize symbol handler";
}
// 设置上下文
CONTEXT* context = pExceptionInfo->ContextRecord;
STACKFRAME64 frame = {};
DWORD imageType;
#ifdef _M_IX86
imageType = IMAGE_FILE_MACHINE_I386;
frame.AddrPC.Offset = context->Eip;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context->Ebp;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrStack.Offset = context->Esp;
frame.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
imageType = IMAGE_FILE_MACHINE_AMD64;
frame.AddrPC.Offset = context->Rip;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context->Rsp;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrStack.Offset = context->Rsp;
frame.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
imageType = IMAGE_FILE_MACHINE_IA64;
frame.AddrPC.Offset = context->StIIP;
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Offset = context->IntSp;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrBStore.Offset = context->RsBSP;
frame.AddrBStore.Mode = AddrModeFlat;
frame.AddrStack.Offset = context->IntSp;
frame.AddrStack.Mode = AddrModeFlat;
#else
return "Unsupported platform for stack walking";
#endif
// 分配符号信息结构
constexpr int MAX_NAME_LEN = 256;
BYTE symbolBuffer[sizeof(SYMBOL_INFO) + MAX_NAME_LEN];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)symbolBuffer;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_NAME_LEN;
// 行号信息
IMAGEHLP_LINE64 line = {};
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
result += std::format("Exception Code: 0x{:08X}\n", pExceptionInfo->ExceptionRecord->ExceptionCode);
result +=
std::format("Exception Address: 0x{:016X}\n", (ULONG_PTR)pExceptionInfo->ExceptionRecord->ExceptionAddress);
result += "Call Stack:\n";
int frameNum = 0;
while (StackWalk64(
imageType,
process,
thread,
&frame,
context,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL)) {
if (frame.AddrPC.Offset == 0) {
break;
}
result += std::format(" #{:2}: ", frameNum);
// 获取符号信息
DWORD64 displacement = 0;
bool hasSymbol = SymFromAddr(process, frame.AddrPC.Offset, &displacement, symbol);
if (hasSymbol) {
result += std::format("{}+0x{:X}", symbol->Name, displacement);
}
else {
result += "<unknown>";
}
// 获取行号信息
DWORD lineDisplacement = 0;
bool hasLine = SymGetLineFromAddr64(process, frame.AddrPC.Offset, &lineDisplacement, &line);
if (hasLine) {
result += std::format(" at {}:{}", line.FileName, line.LineNumber);
}
// 获取模块信息
IMAGEHLP_MODULE64 moduleInfo = {};
moduleInfo.SizeOfStruct = sizeof(moduleInfo);
bool hasModule = SymGetModuleInfo64(process, frame.AddrPC.Offset, &moduleInfo);
if (hasModule) {
result += std::format(" [{}]", moduleInfo.ModuleName);
}
result += std::format(" (0x{:016X})\n", frame.AddrPC.Offset);
frameNum++;
if (frameNum > 64) { // 防止无限循环
break;
}
}
SymCleanup(process);
return result;
}
// 在异常抛出点捕获堆栈跟踪
static std::string capture_current_stack_trace()
{
HANDLE process = GetCurrentProcess();
// 初始化符号处理器
SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
if (!SymInitialize(process, NULL, TRUE)) {
return "Failed to initialize symbol handler";
}
// 捕获当前堆栈
void* stack[64];
USHORT frames = CaptureStackBackTrace(0, 64, stack, NULL);
// 分配符号信息结构
constexpr int MAX_NAME_LEN = 256;
BYTE symbolBuffer[sizeof(SYMBOL_INFO) + MAX_NAME_LEN];
PSYMBOL_INFO symbol = (PSYMBOL_INFO)symbolBuffer;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_NAME_LEN;
// 行号信息
IMAGEHLP_LINE64 line = {};
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
std::vector<std::string> frame_strings;
int index = 0;
for (USHORT i = 0; i < frames && i < 64; i++) {
std::string frame;
DWORD64 address = (DWORD64)(stack[i]);
// 获取符号信息
DWORD64 displacement = 0;
bool hasSymbol = SymFromAddr(process, address, &displacement, symbol);
if (hasSymbol) {
frame = std::format("{}+0x{:X}", symbol->Name, displacement);
}
else {
frame = "<unknown>";
}
if (frame.starts_with("abort") || frame.starts_with("terminate")) {
index = i;
}
// 获取行号信息
DWORD lineDisplacement = 0;
bool hasLine = SymGetLineFromAddr64(process, address, &lineDisplacement, &line);
if (hasLine) {
frame += std::format(" at {}:{}", line.FileName, line.LineNumber);
}
// 获取模块信息
IMAGEHLP_MODULE64 moduleInfo = {};
moduleInfo.SizeOfStruct = sizeof(moduleInfo);
bool hasModule = SymGetModuleInfo64(process, address, &moduleInfo);
if (hasModule) {
frame += std::format(" [{}]", moduleInfo.ModuleName);
}
frame += std::format(" (0x{:016X})\n", address);
frame_strings.emplace_back(std::move(frame));
}
SymCleanup(process);
std::string result = "Current Stack Trace:\n";
for (int i = index; i < frames; i++) {
result += std::format(" #{:2}: {}", i - index, frame_strings[i]);
}
return result;
}
#elif defined(__unix__) || defined(__APPLE__)
// Unix/Linux/macOS 堆栈跟踪实现
static std::string capture_current_stack_trace()
{
std::string result;
result += "Current Stack Trace:\n";
// 捕获堆栈帧
constexpr int MAX_FRAMES = 64;
void* buffer[MAX_FRAMES];
int frames = backtrace(buffer, MAX_FRAMES);
if (frames <= 0) {
return "Failed to capture stack trace";
}
// 获取符号信息
char** symbols = backtrace_symbols(buffer, frames);
if (!symbols) {
return "Failed to get symbol information";
}
// 解析并格式化每一帧
for (int i = 0; i < frames && i < 64; i++) {
result += std::format(" #{:2}: ", i);
// 尝试解析符号名称
std::string frame_info = demangle_symbol(symbols[i], buffer[i]);
result += frame_info;
result += "\n";
}
free(symbols);
return result;
}
private:
// 辅助函数:解析和 demangle 符号名称
static std::string demangle_symbol(const char* symbol_raw, void* address)
{
std::string result;
// 尝试使用 dladdr 获取更详细的信息
Dl_info info;
if (dladdr(address, &info)) {
// 获取模块名称
if (info.dli_fname) {
const char* fname = std::strrchr(info.dli_fname, '/');
result += fname ? (fname + 1) : info.dli_fname;
result += " ";
}
// 获取函数名称并 demangle
if (info.dli_sname) {
int status = 0;
char* demangled = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
if (status == 0 && demangled) {
result += demangled;
free(demangled);
}
else {
result += info.dli_sname;
}
// 计算偏移量
if (info.dli_saddr) {
ptrdiff_t offset = static_cast<char*>(address) - static_cast<char*>(info.dli_saddr);
result += std::format("+0x{:X}", static_cast<size_t>(offset));
}
}
else {
result += "<unknown>";
}
// 添加地址
result += std::format(" (0x{:016X})", reinterpret_cast<uintptr_t>(address));
}
else {
// 如果 dladdr 失败,使用原始符号信息
result = symbol_raw;
}
return result;
}
#else
// 不支持的平台
static std::string capture_current_stack_trace() { return "Stack trace not supported on this platform"; }
#endif
};
} // namespace asst::utils

View File

@@ -25,7 +25,6 @@
#include "Meta.hpp"
#include "NullStreambuf.hpp"
#include "Platform.hpp"
#include "Utils/ExceptionStacktrace.hpp"
#include "WorkingDir.hpp"
#if defined(__APPLE__) || defined(__linux__)
@@ -878,17 +877,12 @@ private:
{
try {
auto& logger = Logger::get_instance();
std::string exception_details = utils::ExceptionStacktrace::capture_exception_stack_trace(pExceptionInfo);
logger.error("=== UNHANDLED EXCEPTION ===");
logger.error("Version", MAA_VERSION);
logger.error("Built at", __DATE__, __TIME__);
logger.error("User Dir", UserDir.get());
logger.error(std::format("Module Base Address: 0x{:016X}", utils::ExceptionStacktrace::get_base_address()));
logger.error("Exception details with stack trace:");
logger.error(exception_details);
logger.error("============================");
logger.flush();
write_crash_file("Unhandled Exception with Stack Trace", exception_details.c_str());
}
catch (...) {
// 如果日志记录失败,直接写入文件
@@ -921,18 +915,15 @@ private:
// 再处理 C++ 异常
std::string exception_info = "Unknown exception";
std::string stack_trace;
if (auto eptr = std::current_exception()) {
try {
std::rethrow_exception(eptr);
}
catch (const std::exception& e) {
exception_info = std::string("std::exception: ") + e.what() + " (type: " + typeid(e).name() + ")";
stack_trace = utils::ExceptionStacktrace::capture_current_stack_trace();
}
catch (...) {
exception_info = "Unknown exception type";
stack_trace = utils::ExceptionStacktrace::capture_current_stack_trace();
}
}
@@ -940,19 +931,7 @@ private:
logger.error("Version", MAA_VERSION);
logger.error("Built at", __DATE__, __TIME__);
logger.error("User Dir", UserDir.get());
logger.error(
"MaaCore Base Address:",
std::format("0x{:016X}", utils::ExceptionStacktrace::get_base_address()));
logger.error("Unhandled exception caught:", exception_info);
logger.error("Exception stack trace:");
if (!stack_trace.empty()) {
logger.error(stack_trace);
write_crash_file("Unhandled exception stack trace:", stack_trace.c_str());
}
else {
logger.error("empty");
write_crash_file("empty");
}
logger.error("Program terminating...");
logger.error("===================");
logger.flush();