diff --git a/rpcsx-os/CMakeLists.txt b/rpcsx-os/CMakeLists.txt index 6da387192..38678353a 100644 --- a/rpcsx-os/CMakeLists.txt +++ b/rpcsx-os/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable(rpcsx-os iodev/zero.cpp main.cpp + backtrace.cpp bridge.cpp vm.cpp ops.cpp diff --git a/rpcsx-os/backtrace.cpp b/rpcsx-os/backtrace.cpp new file mode 100644 index 000000000..1ac7af911 --- /dev/null +++ b/rpcsx-os/backtrace.cpp @@ -0,0 +1,121 @@ +#include "backtrace.hpp" +#include +#include +#include +#include +#include +#include + +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; + } + + return std::snprintf(dest, destLen, "%s+%#" PRIx64, module->soName, + address - moduleBase); + } + + return 0; +} + +void rx::printStackTrace(ucontext_t *context, int fileno) { + unw_cursor_t cursor; + + char buffer[1024]; + + 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); + 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 < 32); +} + +void rx::printStackTrace(ucontext_t *context, orbis::Thread *thread, + int fileno) { + unw_cursor_t cursor; + + char buffer[1024]; + + 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); + 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 < 32); +} diff --git a/rpcsx-os/backtrace.hpp b/rpcsx-os/backtrace.hpp new file mode 100644 index 000000000..bd350e3d1 --- /dev/null +++ b/rpcsx-os/backtrace.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "orbis/thread/Thread.hpp" +#include +#include + +namespace rx { +std::size_t printAddressLocation(char *dest, std::size_t destLen, + orbis::Thread *thread, std::uint64_t address); +void printStackTrace(ucontext_t *context, int fileno); +void printStackTrace(ucontext_t *context, orbis::Thread *thread, int fileno); +} // namespace rx diff --git a/rpcsx-os/main.cpp b/rpcsx-os/main.cpp index a50831e25..83867d9a7 100644 --- a/rpcsx-os/main.cpp +++ b/rpcsx-os/main.cpp @@ -1,5 +1,5 @@ -#include "align.hpp" #include "amdgpu/bridge/bridge.hpp" +#include "backtrace.hpp" #include "bridge.hpp" #include "io-device.hpp" #include "io-devices.hpp" @@ -9,8 +9,8 @@ #include "vfs.hpp" #include "vm.hpp" +#include #include -#include #include #include #include @@ -20,15 +20,9 @@ #include #include -#include #include -#include -#include #include -#include -#include #include -#include #include #include @@ -36,120 +30,6 @@ static int g_gpuPid; -static void printStackTrace(ucontext_t *context, int fileno) { - unw_cursor_t cursor; - - char buffer[1024]; - - 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); - 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 < 32); -} - -static std::size_t 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; - } - - return std::snprintf(dest, destLen, "%s+%#" PRIx64, module->soName, - address - moduleBase); - } - - return 0; -} - -static void printStackTrace(ucontext_t *context, orbis::Thread *thread, - int fileno) { - unw_cursor_t cursor; - - char buffer[1024]; - - 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); - 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 < 32); -} - __attribute__((no_stack_protector)) static void handle_signal(int sig, siginfo_t *info, void *ucontext) { if (auto hostFs = _readgsbase_u64()) { @@ -171,17 +51,17 @@ handle_signal(int sig, siginfo_t *info, void *ucontext) { write(2, buf, len); if (std::size_t printed = - printAddressLocation(buf, sizeof(buf), rx::thread::g_current, + rx::printAddressLocation(buf, sizeof(buf), rx::thread::g_current, (std::uint64_t)info->si_addr)) { printed += std::snprintf(buf + printed, sizeof(buf) - printed, "\n"); write(2, buf, printed); } if (rx::thread::g_current) { - printStackTrace(reinterpret_cast(ucontext), + rx::printStackTrace(reinterpret_cast(ucontext), rx::thread::g_current, 2); } else { - printStackTrace(reinterpret_cast(ucontext), 2); + rx::printStackTrace(reinterpret_cast(ucontext), 2); } }