Unify stack walking

This commit is contained in:
nmzik
2026-08-11 15:39:34 +02:00
parent 4980efa9b7
commit 97514884b1
6 changed files with 39 additions and 111 deletions
+1
View File
@@ -378,6 +378,7 @@ add_executable(page_manager_tests EXCLUDE_FROM_ALL
"${KYTY_TESTS_DIR}/PageManagerTests.cpp" "${KYTY_TESTS_DIR}/PageManagerTests.cpp"
"${KYTY_SOURCE_DIR}/graphics/host_gpu/pageManager.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}) target_include_directories(page_manager_tests PRIVATE ${inc_headers})
add_executable(bit_array_tests EXCLUDE_FROM_ALL add_executable(bit_array_tests EXCLUDE_FROM_ALL
+1 -49
View File
@@ -15,56 +15,8 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/platform/sysDbg.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<void*>(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) { void SysStackWalk(void** stack, int* depth) {
int n = WalkStack(*depth, stack); *depth = static_cast<int>(CaptureStackBackTrace(0, static_cast<DWORD>(*depth), stack, nullptr));
*depth = n;
// unwind_info_t info = {stack, 0, *depth};
// _Unwind_Backtrace(&trace_fcn, &info);
// *depth = info.depth;
} }
void SysStackUsagePrint(sys_dbg_stack_info_t& stack) { void SysStackUsagePrint(sys_dbg_stack_info_t& stack) {
+9 -8
View File
@@ -1,5 +1,6 @@
#include "graphics/host_gpu/pageManager.h" #include "graphics/host_gpu/pageManager.h"
#include "common/platform/sysDbg.h"
#include "graphics/host_gpu/regionDefinitions.h" #include "graphics/host_gpu/regionDefinitions.h"
#include "kernel/memory.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("PageManager fail-fast: ", stderr);
std::fputs(reason != nullptr ? reason : "invalid page state", stderr); std::fputs(reason != nullptr ? reason : "invalid page state", stderr);
std::fputc('\n', stderr); std::fputc('\n', stderr);
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS #if !defined(__APPLE__)
void* frames[16] {}; void* frames[16] {};
const auto frame_count = int frame_count = static_cast<int>(std::size(frames));
CaptureStackBackTrace(0, static_cast<DWORD>(std::size(frames)), frames, nullptr); SysStackWalk(frames, &frame_count);
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
const auto image_base = reinterpret_cast<uintptr_t>(GetModuleHandleW(nullptr)); const auto image_base = reinterpret_cast<uintptr_t>(GetModuleHandleW(nullptr));
for (uint16_t i = 0; i < frame_count; i++) { for (int i = 0; i < frame_count; i++) {
const auto address = reinterpret_cast<uintptr_t>(frames[i]); const auto address = reinterpret_cast<uintptr_t>(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); address, address >= image_base ? address - image_base : 0);
} }
#elif !defined(__APPLE__) #else
void* frames[16] {};
const int frame_count = ::backtrace(frames, static_cast<int>(std::size(frames)));
::backtrace_symbols_fd(frames, frame_count, STDERR_FILENO); ::backtrace_symbols_fd(frames, frame_count, STDERR_FILENO);
#endif
#endif #endif
std::fflush(stderr); std::fflush(stderr);
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS #if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
+1 -1
View File
@@ -226,7 +226,7 @@ static void PrintAbortPointerArrayCandidate(const char* name, uint64_t addr) {
PrintAbortPointerArrayCandidate("arg5", arg5); PrintAbortPointerArrayCandidate("arg5", arg5);
if (rbp != 0) { if (rbp != 0) {
Common::Singleton<Loader::RuntimeLinker>::Instance()->StackTrace(rbp); Common::Singleton<Loader::RuntimeLinker>::Instance()->StackTrace(rbp, rsp);
} }
if (rsp != 0) { if (rsp != 0) {
+27 -53
View File
@@ -672,48 +672,39 @@ static Common::VirtualMemory::Mode GetMode(Elf64_Word flags) {
} }
} }
struct FrameS { struct GuestStackFrame {
FrameS* next; GuestStackFrame* next;
uintptr_t ret_addr; uintptr_t return_address;
}; };
static void KYTY_SYSV_ABI StackwalkX86(uint64_t rbp, void** stack, int* depth, uintptr_t stack_addr, static bool IsReadableRange(uint64_t addr, uint64_t size);
size_t stack_size, uintptr_t code_addr, size_t code_size) {
auto* frame = reinterpret_cast<FrameS*>(rbp);
int d = *depth; static int WalkGuestStack(uint64_t rbp, uint64_t rsp, void** stack, int capacity) {
int i = 0; constexpr uintptr_t STACK_SIZE = 1024u * 1024u;
const uintptr_t code_start = SYSTEM_RESERVED + CODE_BASE_OFFSET;
for (; i < d; i++) { const uintptr_t stack_end = rsp + STACK_SIZE;
if (!(reinterpret_cast<uintptr_t>(frame) >= stack_addr && if (stack == nullptr || capacity <= 0 || rsp == 0 || rbp < rsp || stack_end < rsp ||
reinterpret_cast<uintptr_t>(frame) < stack_addr + stack_size)) { g_desired_base_addr <= code_start) {
break; return 0;
} }
if (!(frame->ret_addr >= code_addr && frame->ret_addr < code_addr + code_size)) { auto* frame = reinterpret_cast<GuestStackFrame*>(rbp);
int depth = 0;
while (depth < capacity) {
const auto frame_addr = reinterpret_cast<uintptr_t>(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;
}
stack[depth++] = reinterpret_cast<void*>(frame->return_address);
if (reinterpret_cast<uintptr_t>(frame->next) <= frame_addr) {
break; break;
} }
stack[i] = reinterpret_cast<void*>(frame->ret_addr);
frame = frame->next; frame = frame->next;
} }
return depth;
*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);
} }
// Probe diagnostic ranges without raising another fault. // 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->type == Common::HostException::ExceptionType::AccessViolation) {
if (info->rbp != 0) { if (info->rbp != 0) {
void* stack[20]; Common::Singleton<Loader::RuntimeLinker>::Instance()->StackTrace(info->rbp, info->rsp);
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<uint64_t>(stack[i]);
auto* p =
Common::Singleton<Loader::RuntimeLinker>::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()));
}
} }
auto dump_guest_qwords = [](const char* name, uint64_t addr) { auto dump_guest_qwords = [](const char* name, uint64_t addr) {
@@ -1896,11 +1872,9 @@ Program* RuntimeLinker::FindProgramByAddr(uint64_t vaddr) {
return nullptr; return nullptr;
} }
void RuntimeLinker::StackTrace(uint64_t frame_ptr) { void RuntimeLinker::StackTrace(uint64_t frame_ptr, uint64_t stack_ptr) {
void* stack[20]; void* stack[20];
int depth = 20; int depth = WalkGuestStack(frame_ptr, stack_ptr, stack, static_cast<int>(std::size(stack)));
SysStackWalkX86(frame_ptr, stack, &depth);
LOGF("Stack trace [thread = %d]:\n", Common::Thread::GetThreadIdUnique()); LOGF("Stack trace [thread = %d]:\n", Common::Thread::GetThreadIdUnique());
+1 -1
View File
@@ -183,7 +183,7 @@ public:
static uint8_t* TlsGetAddr(Program* program); static uint8_t* TlsGetAddr(Program* program);
static void DeleteTls(Program* program, int thread_id); 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: private:
static void LoadProgramToMemory(Program* program); static void LoadProgramToMemory(Program* program);