The gdb route works, and the recipe is written down: run-canary execs $XENIA_BIN, so a wrapper that execs "gdb --args <real binary>" keeps the lockfile, the flags and the process name (gdb forks and execs the real binary, so ps -C xenia_canary still finds the inferior) while satisfying ptrace_scope=1 by being the parent. The Release binary is not stripped - 26595 symtab entries - so frames have names. The handle SIGSEGV/SIGBUS/SIG32-35 lines are mandatory: xenia uses SIGSEGV for guest memory watches and the RT signals for thread suspend. A run froze after ~4 minutes of flight, screen still "flight" rather than GAME OVER, and all 79 threads had backtraces. EVERY ONE is in a wait - guest threads in KeWaitForSingleObject / NtWaitForSingleObjectEx / SelfSuspend, the GPU command processor parked idle, the main thread in poll(). It is nevertheless burning 1253 ticks per 10 s: 403 in the TimerQueue thread (nanosleep inside TimerThreadMain) and 290 + 274 in two guest threads that the backtrace shows blocked in KeWaitForSingleObject. A thread genuinely blocked cannot burn 28% of a core, so those two are CYCLING - a timed wait that expires and is re-entered - with the timer thread servicing them hot. Three samples minutes apart show identical frames. That refines the earlier "the guest is spinning, not deadlocked": the CPU burn is real but it is in the WAIT PATH inside the kernel layer, not in guest code. The shape is an event that never gets signalled. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
1.0 KiB
Executable File
1.0 KiB
Executable File