libretro: report where the core was executing when it dies - #158
Open
WizzardSK wants to merge 1 commit into
Open
libretro: report where the core was executing when it dies#158WizzardSK wants to merge 1 commit into
WizzardSK wants to merge 1 commit into
Conversation
A crash in the Android core currently leaves nothing behind. The report in pcee2-libretro#30 is a RetroArch log that simply stops mid-sentence, in the middle of microVU1 compiling VU1 programs, because RetroArch's log cannot capture a native crash and the core installs no reporter of its own - the only sigaction in the tree is the fastmem page fault filter. So the one question a crash in a recompiled core turns on goes unanswered: was the program counter in generated code, or in the core's own text? A backtrace cannot say, since JIT pages carry no unwind information and the unwinder stops at the signal frame. /proc/self/maps can, because generated code lives in an anonymous mapping and compiled code lives in the .so. This installs a handler for SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGABRT and SIGTRAP that prints the signal and its code, the faulting thread's name, pc/lr/sp/fp and the fault address, and the /proc/self/maps line each of those falls in. It goes to logcat as well as stderr, since logcat is where an Android crash is actually readable. It installs from retro_init(), before vtlb reaches HostSys::InstallPageFaultHandler(). That ordering is the whole trick: fastmem takes SIGSEGV (and SIGBUS on aarch64) and chains to whatever it displaced when a fault is not one of its own, so going in first puts this on the end of that chain instead of out of it. Fastmem's own handling is untouched, and this reports only faults fastmem has already declined. Having reported, it chains onward to whatever was there before it, so the process still dies the way it would have. Tested by faulting on purpose, both ways round. A store to 0x1234 reports SIGSEGV with pc and lr resolved to the executable and the fault address unmapped; jumping into an anonymous PROT_EXEC page holding an undefined encoding reports SIGILL with "pc in ... rwxp 00000000 00:00 0" and lr pointing back at the caller - which is exactly the shape a codegen bug would take. Both then die with the default action, 139 and 132.
This was referenced Aug 28, 2026
LibretroAdmin
pushed a commit
that referenced
this pull request
Aug 28, 2026
#159 reports God of War crashing shortly after boot on Android. The reporter ran the triage that would have implicated the recompilers - MTVU off, VU1 softfloat on, EE interpreter - and it still crashed, which is what pointed away from CPU emulation entirely. Their log ends immediately after this: SET_SYSTEM_AV_INFO: 640x448, Aspect: 1.3333, FPS: 59.9401, Sample rate: 48000 ... video and audio drivers reinitialised ... SET_SYSTEM_AV_INFO: 640x448, Aspect: 1.3333, FPS: 59.9401, Sample rate: 48000 ... video and audio drivers reinitialised again ... Two announcements carrying identical values, each making the frontend tear down and rebuild its whole video driver, which on the HW-render path means context_destroy and a fresh negotiation. update_av_info() sent the announcement unconditionally whenever pending_update_av_info was set, without comparing against what had last gone out, and without regard for what the GS thread was doing - so the rebuild could land on top of a thread still submitting to the shared Vulkan queue. Both guards are the ones pcee2 already carries for the same defect (adf456e28d): - Announce only on a real timing change. The fps compare needs a tolerance, since NTSC reports 59.94005994 Hz against a 59.94 default and that 0.00006 Hz difference must not rebuild anything. Geometry needs no announcement on the HW-render path: SET_GEOMETRY carries it without a reinit, which is already how the widescreen hint does it, so it is forwarded that way instead. - Drain the GS thread before an announcement that does go out. The CPU thread is already parked at this point - retro_run has not resumed it. Software rendering keeps the old behaviour for a geometry change, matching pcee2 rather than widening the change. This is a hypothesis the log supports rather than a confirmed fix: nothing in that log says what the crash was, because the core has no crash reporter yet (#158), and the reporter cannot get logcat without root. What can be said is that the frontend was rebuilding its video driver for no reason at the moment everything stopped, and that this is a defect either way.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A crash in the Android core currently leaves nothing behind. The report in #159 is a RetroArch log that stops mid-sentence in the middle of microVU1 compiling VU1 programs — RetroArch cannot log a signal that kills the process, and the core installs no reporter of its own. The only
sigactionin the tree is the fastmem page fault filter.So the question a crash in a recompiled core turns on goes unanswered: was the program counter in generated code, or in the core’s own text? A backtrace cannot say — JIT pages carry no unwind information, so the unwinder stops at the signal frame.
/proc/self/mapscan, because generated code lives in an anonymous mapping and compiled code lives in the.so.This installs a handler for SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGABRT and SIGTRAP that prints the signal and its code, the faulting thread’s name, pc/lr/sp/fp and the fault address, and the
/proc/self/mapsline each of those falls in. Output goes to logcat as well as stderr, since logcat is where an Android crash is actually readable.Ordering
It installs from
retro_init(), before vtlb reachesHostSys::InstallPageFaultHandler(). That is the whole trick: fastmem takes SIGSEGV (and SIGBUS on aarch64) and chains to whatever it displaced when a fault is not one of its own, so going in first puts this on the end of that chain instead of out of it. Fastmem’s own handling is untouched and this only ever sees faults fastmem has already declined. Having reported, it chains onward to whatever was there before it, so the process still dies the way it would have.Testing
Faulting on purpose, both ways round:
0x1234reports SIGSEGV, with pc and lr resolved to the executable and the fault addressunmapped;PROT_EXECpage holding an undefined encoding reports SIGILL, withpc in ... rwxp 00000000 00:00 0and lr pointing back at the caller — the shape a codegen bug would take.Both then die with the default action, 139 and 132. Compiles clean with
-Wallon this base; non-POSIX targets get an emptyCrashHandler_Install().