The previous section concluded the guest spins forever in sub_82457780.
Measured without gdb, that is false. Every observation behind it came from a
gdb-hosted run, and gdb intercepts every SIGSEGV -- which Xenia uses for guest
memory watches -- so it perturbs precisely what was being measured.
Same measurement, no debugger, per-thread /proc sampling parsed after the last
')':
Main XThread 0 ms CPU per 3 s, 0 faults, state S, futex_do_wait
GPU Commands 10 ms
WSI swapchain queue 130 ms
llvmpipe-0..9 ~1030 ms each per 6 s
Process at 265% of a core, essentially all in the software rasterizer. The
guest thread is BLOCKED on a futex using zero CPU -- not spinning, and not in
sub_82457780.
Under gdb that same thread appeared as the top CPU consumer (890 ms / 4 s) and
appeared to be in guest JIT code, then in xe::ExceptionHandlerCallback. That
was signal interception plus gdb re-stopping it between samples (state t,
wchan ptrace_stop).
Withdrawn: "an infinite copy loop in sub_82457780 is the freeze", and "Main
XThread is the top CPU consumer, so it is a spin not a block". The opposite
holds.
Survives: the emit_source_annotations technique is sound and did prove the PC
was 0x824578A0 while the guest ran under gdb, so the guest does pass through
that copy loop. The bne-exact-equality reading remains an accurate description
of the disassembly and a plausible hazard -- just not this freeze.
What the freeze actually is: guest blocked on a host futex at zero CPU, software
rasterizer saturated for six minutes without producing a frame, nothing
faulting, screen unchanged. That is the guest waiting on a GPU operation that
never completes, with lavapipe spinning -- a HOST RENDERING problem, which is
also why every game-side hypothesis this session was refuted in turn.
Method rule earned the hard way and recorded on the page: do not diagnose a
performance or liveness question under a debugger. Use it to read state at a
known stopping point, then re-measure timing and CPU detached.