Repository navigation
feat(libc): implement sceLibcBacktraceSelf and GetBufferSize on Windows - #8137
Conversation
|
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
590c396 to
47591f2
Compare
…kopovar#8137 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011krDVCnnMQPaEFEqCDnKmA
| HMODULE callerHandle = nullptr; | ||
| const auto address = reinterpret_cast<std::uintptr_t>(handle) + records.front().offset; | ||
| Require(GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, | ||
| reinterpret_cast<LPCSTR>(address), &callerHandle) != 0 && callerHandle == handle, |
There was a problem hiding this comment.
The Windows assertion currently proves only that the first frame resolves to the same executable module. The Linux branch also checks the exact caller symbol (caller.dli_saddr == self.dli_saddr), so it would catch an off-by-one in the skipped frames that this Windows branch could miss. Since handle came from &CheckBacktrace, could this assert that reinterpret_cast<std::uintptr_t>(handle) + records.front().offset == reinterpret_cast<std::uintptr_t>(&CheckBacktrace) as well?
There was a problem hiding this comment.
Fixed in 28d0b16: since records.front().offset is the call-site return RVA inside CheckBacktrace rather than the function entry &CheckBacktrace, the Windows branch now brackets sceLibcBacktraceSelf_nid_postfix with CurrentIp() (address > before && address < after) and checks that records[1].offset matches __builtin_return_address(0).
|
Head Windows 11 (10.0.26300), Ryzen 5 9600X, WinLibs GCC 15.2.0 UCRT, Release,
Ubuntu 24.04 (WSL2), GCC 13.3, Release, same merge: AI-assisted: yes (Claude Code); results above were run on this machine. |
|
Thanks @MarcZX10 and @wachi35676 for the review and catches! Addressed in the latest commit:
|
|
Re-ran
The case of a native caller with a C++ cleanup frame is unchanged. I re-ran the probe 3 times, and the output was identical with
So the change doesn't fix the empty trace. Building AI-assisted: yes (Claude Code); results above were run on this machine. |
|
Thanks @wachi35676 for digging into that in |
|
Rebased / synced with |
What
During the startup and runtime of Unity Engine titles such as God of War: Sons of Sparta (PPSA28997), the IL2CPP runtime (
Il2cppUserAssemblies.prx) and Boehm garbage collector query stack backtraces viasceLibcBacktraceSelfandsceLibcBacktraceGetBufferSize.PR #7060 implemented these exports for Linux using
backtrace()anddladdr(), leaving other platforms callingNotImplemented_nid_no_patch(__func__). On Windows, attempting to capture a backtrace aborts the process immediately with an unhandled runtime error:This PR implements the missing Windows support for
CaptureFramesinlibc/src/Backtrace.cpp:_Unwind_Backtrace_nid_postfix/_Unwind_GetIP_nid_postfix), which unwinds relinked guest and AnyPS5.ehmeta/.ehframframes and steps through foreign PE frames without exception/termination handlers viaVirtualUnwind(Unwind.cpp:417).GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, ...)and queries the module path through internal helperBacktraceModulePath_nid_no_patch(handle, initialCapacity), which starts atMAX_PATHin production and grows exponentially up to 32 KiB onERROR_INSUFFICIENT_BUFFERorlength == capacity./\\) and trims the.guest.prxsuffix, producing the same clean module names as the Linux implementation.guest_backtrace(core/libs/tests/GuestBacktrace.cpp) to Windows (callingBacktraceModulePath_nid_no_patch(handle, 1)to exercise the buffer-growth loop directly without depending on a long checkout path) and registers it incore/libs/prx/libc/CMakeLists.txtrestricted toLinuxandWIN32.docs/dev/debt/libc.mdnoting that both Linux and Windows are supported and documenting that on Windows, unwinding stops at a frame without.ehmetaor.ehframtables whose PE unwind data has an exception or termination handler, leaving the trace empty or cut short while returning 0.Tested
Automated Test Suite:
guest_backtraceinctestpasses 100% on Windows (MinGW-w64 GCC 15, Release):guest_backtraceaborts with:Title Verification (God of War: Sons of Sparta, PPSA28997):
main+ this PR: BecauseIl2cppUserAssemblies.prximports 7 Dinkumware thread helpers directly fromlibc.prx(which onmainare currently exported only fromlibSceAmpr.prxvia feat(libSceAmpr): implement the std::_Pad thread launch helpers #3743 / libkernel: execv/execve and the setuid/setgroups/setrlimit family are absent (XPSemu, PS5MC); fix branch ready #3558), launching against standalonemainstops at the ELF import resolution stage before reaching guest code:libc.prxDinkumware thread imports resolved (tested together with feat(libc): export Dinkumware thread primitives from libc.prx #8148):Il2cppUserAssemblies.prxinvokessceLibcBacktraceSelfand terminates immediately withstd::runtime_error: sceLibcBacktraceSelf not implemented.sceLibcBacktraceSelfreturns 0 and populates valid frame records (Il2cppUserAssemblies.prx,libkernel.prx,libc.prx, etc.), allowing the title to pass engine initialization into menus and in-game rendering.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)