diff --git a/CMakeLists.txt b/CMakeLists.txt index fdf11de89..c9221e048 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -378,6 +378,7 @@ add_executable(page_manager_tests EXCLUDE_FROM_ALL "${KYTY_TESTS_DIR}/PageManagerTests.cpp" "${KYTY_SOURCE_DIR}/graphics/host_gpu/pageManager.cpp" ) +target_link_libraries(page_manager_tests common) target_include_directories(page_manager_tests PRIVATE ${inc_headers}) add_executable(bit_array_tests EXCLUDE_FROM_ALL diff --git a/src/common/platform/sysWindowsDbg.cpp b/src/common/platform/sysWindowsDbg.cpp index 976d2506a..d0e0264a6 100644 --- a/src/common/platform/sysWindowsDbg.cpp +++ b/src/common/platform/sysWindowsDbg.cpp @@ -15,56 +15,8 @@ #include "common/assert.h" #include "common/platform/sysDbg.h" -struct FrameS { - struct FrameS* next; - void* ret_addr; -}; - -int WalkStack(int z_stack_depth, void** z_stack_trace) { - CONTEXT context; - // KNONVOLATILE_CONTEXT_POINTERS NvContext; - PRUNTIME_FUNCTION runtime_function = nullptr; - PVOID handler_data = nullptr; - ULONG64 establisher_frame = 0; - ULONG64 image_base = 0; - - RtlCaptureContext(&context); - - int frame = 0; - - while (true) { - if (frame >= z_stack_depth) { - break; - } - - z_stack_trace[frame] = reinterpret_cast(context.Rip); - - frame++; - - runtime_function = RtlLookupFunctionEntry(context.Rip, &image_base, nullptr); - - if (runtime_function == nullptr) { - break; - } - - // RtlZeroMemory(&NvContext, sizeof(KNONVOLATILE_CONTEXT_POINTERS)); - RtlVirtualUnwind(0, image_base, context.Rip, runtime_function, &context, &handler_data, - &establisher_frame, nullptr /*&NvContext*/); - - if (context.Rip == 0u) { - break; - } - } - - return frame; -} - void SysStackWalk(void** stack, int* depth) { - int n = WalkStack(*depth, stack); - *depth = n; - // unwind_info_t info = {stack, 0, *depth}; - // _Unwind_Backtrace(&trace_fcn, &info); - // *depth = info.depth; + *depth = static_cast(CaptureStackBackTrace(0, static_cast(*depth), stack, nullptr)); } void SysStackUsagePrint(sys_dbg_stack_info_t& stack) { diff --git a/src/graphics/host_gpu/pageManager.cpp b/src/graphics/host_gpu/pageManager.cpp index c819b1161..be911dbea 100644 --- a/src/graphics/host_gpu/pageManager.cpp +++ b/src/graphics/host_gpu/pageManager.cpp @@ -1,5 +1,6 @@ #include "graphics/host_gpu/pageManager.h" +#include "common/platform/sysDbg.h" #include "graphics/host_gpu/regionDefinitions.h" #include "kernel/memory.h" @@ -52,20 +53,20 @@ constexpr uint32_t READ_WRITE_PROTECTION = PAGE_READWRITE; std::fputs("PageManager fail-fast: ", stderr); std::fputs(reason != nullptr ? reason : "invalid page state", stderr); std::fputc('\n', stderr); +#if !defined(__APPLE__) + void* frames[16] {}; + int frame_count = static_cast(std::size(frames)); + SysStackWalk(frames, &frame_count); #if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS - void* frames[16] {}; - const auto frame_count = - CaptureStackBackTrace(0, static_cast(std::size(frames)), frames, nullptr); const auto image_base = reinterpret_cast(GetModuleHandleW(nullptr)); - for (uint16_t i = 0; i < frame_count; i++) { + for (int i = 0; i < frame_count; i++) { const auto address = reinterpret_cast(frames[i]); - std::fprintf(stderr, " frame[%u]=0x%016" PRIxPTR " image_rva=0x%016" PRIxPTR "\n", i, + std::fprintf(stderr, " frame[%d]=0x%016" PRIxPTR " image_rva=0x%016" PRIxPTR "\n", i, address, address >= image_base ? address - image_base : 0); } -#elif !defined(__APPLE__) - void* frames[16] {}; - const int frame_count = ::backtrace(frames, static_cast(std::size(frames))); +#else ::backtrace_symbols_fd(frames, frame_count, STDERR_FILENO); +#endif #endif std::fflush(stderr); #if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS diff --git a/src/libs/libC.cpp b/src/libs/libC.cpp index 43f62dd3e..657be7e23 100644 --- a/src/libs/libC.cpp +++ b/src/libs/libC.cpp @@ -226,7 +226,7 @@ static void PrintAbortPointerArrayCandidate(const char* name, uint64_t addr) { PrintAbortPointerArrayCandidate("arg5", arg5); if (rbp != 0) { - Common::Singleton::Instance()->StackTrace(rbp); + Common::Singleton::Instance()->StackTrace(rbp, rsp); } if (rsp != 0) { diff --git a/src/loader/runtimeLinker.cpp b/src/loader/runtimeLinker.cpp index 6567ffba6..83544837f 100644 --- a/src/loader/runtimeLinker.cpp +++ b/src/loader/runtimeLinker.cpp @@ -672,48 +672,39 @@ static Common::VirtualMemory::Mode GetMode(Elf64_Word flags) { } } -struct FrameS { - FrameS* next; - uintptr_t ret_addr; +struct GuestStackFrame { + GuestStackFrame* next; + uintptr_t return_address; }; -static void KYTY_SYSV_ABI StackwalkX86(uint64_t rbp, void** stack, int* depth, uintptr_t stack_addr, - size_t stack_size, uintptr_t code_addr, size_t code_size) { - auto* frame = reinterpret_cast(rbp); +static bool IsReadableRange(uint64_t addr, uint64_t size); - int d = *depth; - int i = 0; +static int WalkGuestStack(uint64_t rbp, uint64_t rsp, void** stack, int capacity) { + constexpr uintptr_t STACK_SIZE = 1024u * 1024u; + const uintptr_t code_start = SYSTEM_RESERVED + CODE_BASE_OFFSET; + const uintptr_t stack_end = rsp + STACK_SIZE; + if (stack == nullptr || capacity <= 0 || rsp == 0 || rbp < rsp || stack_end < rsp || + g_desired_base_addr <= code_start) { + return 0; + } - for (; i < d; i++) { - if (!(reinterpret_cast(frame) >= stack_addr && - reinterpret_cast(frame) < stack_addr + stack_size)) { + auto* frame = reinterpret_cast(rbp); + + int depth = 0; + while (depth < capacity) { + const auto frame_addr = reinterpret_cast(frame); + if (frame_addr < rsp || frame_addr > stack_end - sizeof(GuestStackFrame) || + !IsReadableRange(frame_addr, sizeof(GuestStackFrame)) || + frame->return_address < code_start || frame->return_address >= g_desired_base_addr) { break; } - - if (!(frame->ret_addr >= code_addr && frame->ret_addr < code_addr + code_size)) { + stack[depth++] = reinterpret_cast(frame->return_address); + if (reinterpret_cast(frame->next) <= frame_addr) { break; } - - stack[i] = reinterpret_cast(frame->ret_addr); - frame = frame->next; } - - *depth = i; -} - -static void KYTY_SYSV_ABI SysStackWalkX86(uint64_t rbp, uint64_t rsp, void** stack, int* depth) { - if (rsp == 0 || rbp < rsp) { - *depth = 0; - return; - } - - StackwalkX86(rbp, stack, depth, rsp, 1024u * 1024u, SYSTEM_RESERVED + CODE_BASE_OFFSET, - g_desired_base_addr - (SYSTEM_RESERVED + CODE_BASE_OFFSET)); -} - -void KYTY_SYSV_ABI SysStackWalkX86(uint64_t rbp, void** stack, int* depth) { - SysStackWalkX86(rbp, rbp, stack, depth); + return depth; } // Probe diagnostic ranges without raising another fault. @@ -961,22 +952,7 @@ static bool KytyExceptionHandler(const Common::HostException::ExceptionInfo& exc if (info->type == Common::HostException::ExceptionType::AccessViolation) { if (info->rbp != 0) { - void* stack[20]; - int depth = 20; - SysStackWalkX86(info->rbp, info->rsp, stack, &depth); - - LOGF("Stack trace [thread = %d]:\n", Common::Thread::GetThreadIdUnique()); - for (int i = 0; i < depth; i++) { - auto vaddr = reinterpret_cast(stack[i]); - auto* p = - Common::Singleton::Instance()->FindProgramByAddr(vaddr); - LOGF("[%d] %016" PRIx64 ", off=%016" PRIx64 ", %s\n", i, vaddr, - (p == nullptr ? 0 : vaddr - p->base_vaddr), - (p == nullptr ? "???" - : Common::FilenameWithoutDirectory( - Common::PathToGenericString(p->file_name)) - .c_str())); - } + Common::Singleton::Instance()->StackTrace(info->rbp, info->rsp); } auto dump_guest_qwords = [](const char* name, uint64_t addr) { @@ -1896,11 +1872,9 @@ Program* RuntimeLinker::FindProgramByAddr(uint64_t vaddr) { return nullptr; } -void RuntimeLinker::StackTrace(uint64_t frame_ptr) { +void RuntimeLinker::StackTrace(uint64_t frame_ptr, uint64_t stack_ptr) { void* stack[20]; - int depth = 20; - - SysStackWalkX86(frame_ptr, stack, &depth); + int depth = WalkGuestStack(frame_ptr, stack_ptr, stack, static_cast(std::size(stack))); LOGF("Stack trace [thread = %d]:\n", Common::Thread::GetThreadIdUnique()); diff --git a/src/loader/runtimeLinker.h b/src/loader/runtimeLinker.h index a09f7d036..dfec7abfb 100644 --- a/src/loader/runtimeLinker.h +++ b/src/loader/runtimeLinker.h @@ -183,7 +183,7 @@ public: static uint8_t* TlsGetAddr(Program* program); static void DeleteTls(Program* program, int thread_id); - void StackTrace(uint64_t frame_ptr); + void StackTrace(uint64_t frame_ptr, uint64_t stack_ptr); private: static void LoadProgramToMemory(Program* program);