#include "backtrace.hpp" #include "thread.hpp" #include "xbyak/xbyak.h" #include #include #include #include #include #include #include extern std::uint64_t monoPimpAddress; static auto callGuest = [] { struct SetContext : Xbyak::CodeGenerator { SetContext() { mov(rbx, rsp); mov(rsp, rdx); sub(rsp, 128); push(rbx); call(rsi); pop(rsp); ret(); } } static setContextStorage; return setContextStorage .getCode(); }(); bool allowMonoDebug = false; std::size_t rx::printAddressLocation(char *dest, std::size_t destLen, orbis::Thread *thread, std::uint64_t address) { if (thread == nullptr || address == 0) { return 0; } for (auto [id, module] : thread->tproc->modulesMap) { auto moduleBase = reinterpret_cast(module->base); if (moduleBase > address || moduleBase + module->size <= address) { continue; } const char *name = ""; if (monoPimpAddress && allowMonoDebug && (std::string_view(module->soName).contains(".dll.") || std::string_view(module->soName).contains(".exe."))) { allowMonoDebug = false; auto ctx = reinterpret_cast(thread->context); rx::thread::setupSignalStack(); auto prevFs = _readfsbase_u64(); _writefsbase_u64(thread->fsBase); name = callGuest(address, monoPimpAddress, ctx->uc_mcontext.gregs[REG_RSP]); _writefsbase_u64(prevFs); allowMonoDebug = true; } return std::snprintf(dest, destLen, "%s+%#" PRIx64 " (%#" PRIx64 ") %s", module->soName[0] != '\0' ? module->soName : module->moduleName, address - moduleBase, address, name); } return 0; } void rx::printStackTrace(ucontext_t *context, int fileno) { unw_cursor_t cursor; char buffer[1024]; flockfile(stderr); if (int r = unw_init_local2(&cursor, context, UNW_INIT_SIGNAL_FRAME)) { int len = snprintf(buffer, sizeof(buffer), "unw_init_local: %s\n", unw_strerror(r)); write(fileno, buffer, len); funlockfile(stderr); return; } char functionName[256]; int count = 0; do { unw_word_t ip; unw_get_reg(&cursor, UNW_REG_IP, &ip); unw_word_t off; int proc_res = unw_get_proc_name(&cursor, functionName, sizeof(functionName), &off); Dl_info dlinfo; int dladdr_res = ::dladdr((void *)ip, &dlinfo); unsigned long baseAddress = dladdr_res != 0 ? reinterpret_cast(dlinfo.dli_fbase) : 0; int len = snprintf(buffer, sizeof(buffer), "%3d: %s+%p: %s(%lx)+%#lx\n", count, (dladdr_res != 0 ? dlinfo.dli_fname : "??"), reinterpret_cast(ip - baseAddress), (proc_res == 0 ? functionName : "??"), reinterpret_cast( proc_res == 0 ? ip - baseAddress - off : 0), static_cast(proc_res == 0 ? off : 0)); write(fileno, buffer, len); count++; } while (unw_step(&cursor) > 0 && count < 64); funlockfile(stderr); } void rx::printStackTrace(ucontext_t *context, orbis::Thread *thread, int fileno) { unw_cursor_t cursor; char buffer[1024]; flockfile(stderr); if (int r = unw_init_local2(&cursor, context, UNW_INIT_SIGNAL_FRAME)) { int len = snprintf(buffer, sizeof(buffer), "unw_init_local: %s\n", unw_strerror(r)); write(fileno, buffer, len); funlockfile(stderr); return; } int count = 0; char functionName[256]; do { unw_word_t ip; unw_get_reg(&cursor, UNW_REG_IP, &ip); std::size_t offset = 0; offset += std::snprintf(buffer + offset, sizeof(buffer) - offset, "%3d: ", count); if (auto loc = printAddressLocation(buffer + offset, sizeof(buffer) - offset, thread, ip)) { offset += loc; offset += std::snprintf(buffer + offset, sizeof(buffer) - offset, "\n"); } else { unw_word_t off; int proc_res = unw_get_proc_name(&cursor, functionName, sizeof(functionName), &off); Dl_info dlinfo; int dladdr_res = ::dladdr((void *)ip, &dlinfo); unsigned long baseAddress = dladdr_res != 0 ? reinterpret_cast(dlinfo.dli_fbase) : 0; offset = snprintf(buffer, sizeof(buffer), "%3d: %s+%p: %s(%lx)+%#lx\n", count, (dladdr_res != 0 ? dlinfo.dli_fname : "??"), reinterpret_cast(ip - baseAddress), (proc_res == 0 ? functionName : "??"), reinterpret_cast( proc_res == 0 ? ip - baseAddress - off : 0), static_cast(proc_res == 0 ? off : 0)); } write(fileno, buffer, offset); count++; } while (unw_step(&cursor) > 0 && count < 64); funlockfile(stderr); }