Repository navigation
Description
On Linux, sceKernelGetModuleInfoForUnwind (core/libs/prx/libkernel/Module/src/Module.cpp) reads /proc/self/maps and always returns eh_frame_hdr_addr, eh_frame_addr and eh_frame_size as 0. A title that ships its own libc.prx unwinds with the console's unwinder, which asks this function for each frame's tables. With no tables it finds no handler, so a C++ exception thrown in guest code reaches terminate even when the title catches it. Windows already reports the tables from the guest module's .ehmeta section.
I opened #2401 with a fix. The intake check closed it because I have fewer than 20 merged PRs, so I'm filing it here with the patch for whoever can carry it.
Title: Hollow Knight: Silksong (PPSA12544)
After a new game's opening video, the title stops:
Terminating due to uncaught exception of type Il2CppExceptionWrapper
- The exception, read from the object:
System.Reflection.AmbiguousMatchException. - The path, from the stack and a breakpoint on
RuntimeType.GetMethodImplCommon:PlayMakerFSM.Init → Fsm.Init → CallMethodProper.PreCache → Type.GetMethod("CancelAttackNotDownspikeBounce"). HeroControllerhas two overloads with that name, so the throw is expected.- The LSDA of
CallMethodProper.PreCacheinIl2cppUserAssemblies.prxhas a catch clause over that call: call site0x123+0xd, landing pad0x1e1, action 3. On the console the exception is caught there. - The bundled
libc.prximportssceKernelGetModuleInfoForUnwind.
With the patch below, the title gets past the opening into gameplay. It was played for several minutes, including dying and respawning, with no exception reaching terminate. Base: main + #1836 + #1431 + #846 + #2323 + #861, which are needed to reach the opening.
Measured on a PS5 (firmware 13.60)
A payload calls the function for addresses in libkernel and libSceLibcInternal. It checks each field on its own: it decodes the returned header, compares the eh_frame pointer, and walks the records to the terminator.
| libkernel | libSceLibcInternal | |
|---|---|---|
| return (flags 1) | 0 | 0 |
st_size |
0x130 | 0x130 |
eh_frame_hdr_addr |
header, version 1, encodings 1b/03/3b | same |
eh_frame_addr |
equals the header's decoded eh_frame_ptr |
same |
eh_frame_size |
0x1391c = walk 0x13918 + 4 | 0x2ccc0 = walk 0x2ccbc + 4 |
seg0 |
0x800000000 + 0x4c000, the code segment; the header lies outside it | 0x8000a8000 + 0x128000 |
name |
empty | empty |
- Flags 0, 3 and 8 return
0x80020016, and flags 2 returns0x80020003. - An address outside every module returns
0x80020003. - Any failure zeroes the whole structure.
- So the console's
eh_frame_sizeincludes the 4-byte zero terminator. That settles the open point in the current TechnicalDebt entry.
Patch
Commit f5c9a833 on hugodearaujo:fix/linux-module-unwind-info, based on main f8c2f072:
- Linux. The module is found with
dl_iterate_phdr, as the macOS branch already does. A guest module (the main program or a*.guest.prx) with aPT_GNU_EH_FRAMEgets that header, theeh_frameit points to, and the record size.seg0is the firstPT_LOAD. Host libraries still get no tables, as on Windows. - Both platforms. The header parsing and the record walk become one helper.
eh_frame_sizeincludes the terminator, as measured. The Windows test expectation moves from4 + 12to4 + 12 + 4. - Test.
guest_unwind_module_infogets a Linux version. It compares every field againstdl_iterate_phdrand its own header decode and record walk, for the main program, a module loaded as*.guest.prx, a host library and an unmapped address. It aborts onmain'sModule.cpp. - TechnicalDebt. The entry now records what still differs from the console:
flagsis ignored, andnamegets the host path.
Results: Linux 514/514. Windows (MinGW, CI flags, no GPU) 507/507. #2193 touches the same file in a different function, which causes a text conflict near the includes.
AI-assisted: yes.
Activity
MarcZX10 commentedon Oct 9, 2026
I updated the existing
sceKernelGetModuleInfoForUnwindTechnicalDebt entry with the firmware 13.60 measurements from this issue: flags/results, zeroing on failure, the terminator-inclusive size, and the measuredname/seg0behavior. The entry also states the current Linux gap.\n\nThe documentation-only commit is2a58b076ec1d530a288edf40c39c40523ec0f9fcon fork branchcodex/unwind-info-console-evidence.git diff --checkand the repository conventions check pass. I have not opened a PR.MarcZX10 commentedon Oct 9, 2026
I carried the Linux implementation from closed PR #2401 onto current upstream
mainas a reviewable branch, without opening a new PR:1d139108preserves the original implementation commit and author.61b4a924limits the new Linux-specific CTest registration to Linux, so macOS does not try to compile thelink.htest.On current
main8b393b6e,libkernelandguest_unwind_module_info_testsbuild, andguest_unwind_module_infopasses (1/1). The conventions checker andgit diff --checkpass. I reviewed the complete five-file diff; it still needs the official current-base Linux/Windows build matrix and runtime confirmation on the reported title. This branch is pushed to the fork ascodex/unwind-info-linux-current; no PR was opened.MarcZX10 commentedon Oct 9, 2026
Correction to my previous update: an open PR already covers this same Linux unwind implementation: #1600. Its author has also received a focused follow-up commit (
132c3a50) for the failed-lookup review request, with Linux regression coverage. My branchcodex/unwind-info-linux-currentadded no distinct fix, so I removed that redundant branch from my fork. Please use #1600 and its follow-up as the review path; I have not opened a PR.oneandonlydean commentedon Oct 10, 2026
#1600 is merged: on Linux,
sceKernelGetModuleInfoForUnwindnow fills theeh_frameheader, address and size for the main program and*.guest.prxmodules. Could you retest Silksong past the opening on current main?hugodearaujo commentedon Oct 10, 2026
Thanks. #2401 duplicated #1600, which I missed.
I can't retest past the opening on current
mainyet. Two of the PRs the title needs no longer merge cleanly:feat(relinker): add --module-dir for modules loaded at run time #846 conflicts with
maininModule.cpp, the relinker CLI andGuestModuleBuilder(--macosand fix(libkernel): pass module args and argp to runtime-loaded modules on Linux #1102). I resolved it locally for the test: fix(libkernel): pass module args and argp to runtime-loaded modules on Linux #1102's handoff insceKernelLoadStartModule,main'sBuildsignature plusmoduleDirectories.On
mainf6af6d11d+ that feat(relinker): add --module-dir for modules loaded at run time #846 + fix(guest-arena): place guest address space in the PS5 window on Linux #861, relinked with--module-dir Media/Plugins, the title stops 0.12 s after launch:That is what feat(libkernel): deliver sceKernelRaiseException on Linux #1431 (Linux signal delivery) fixed in my earlier runs. It now conflicts with
maininPthread.hpp,Thread.cpp(thread creation since fix(libkernel): give Linux guest threads the stack size they request #1988),Exception.cppandGuestRaiseException.cpp. I didn't resolve those myself, because a wrong merge of the thread and signal code would make the result meaningless.Once #846 and #1431 are rebased, I'll rerun past the opening and report here.
For reference, the earlier run that got past the opening used #2401's implementation of the same change, on
maind70b89989+ #1836 + #1431 + #846 + #2323 + #861.oneandonlydean commentedon Oct 10, 2026
Closing: #1600 is on main, and on Linux it fills the
eh_framefields for relinked images (core/libs/prx/libkernel/Module/src/Module.cpp:190). Please reopen if the title still loses its exceptions once #846 and #1431 are rebased.test(relinker): expect the terminator in the macOS unwind-info size
test(relinker): expect the terminator in the macOS unwind-info size
test(relinker): expect the terminator in the macOS unwind-info size