re: audit the gdb session -- withdraw the sub_82457780 localisation

Went back to verify the instrumentation before building on it.  Some does not
hold.

Verified: the trailing comments in ppc_context.h are not struct offsets (the
struct opens with eight cr unions and fpscr), but rsi+0x20 for r[32] is
nonetheless correct -- confirmed empirically because the f[32] doubles begin at
+0x140 and 32*8 back from there lands on +0x20.

Withdrawn: the context is STALE mid-function.  The same dump shows r1 = 0, and a
guest stack pointer cannot be zero inside a function -- Xenia's JIT keeps live
guest registers in host registers and spills only at certain points.  So
r13 = 0x82457864 does not show where the guest is executing, and identifying
sub_82457780 as the stuck function is withdrawn as unproven.  The description of
what that code does (grow-and-copy, beq exit) is still accurate; it is just not
established that the guest is in it.

Three readings retracted for broken instrumentation:

  * "rip identical across samples ⇒ no progress" -- gdb stops the process
    between samples, and the JIT lays code out differently per run (a05be939 vs
    a05bc839 for the same instruction).
  * "zero minor faults on the stuck thread" and "utime=0" -- both parsed
    /proc/<pid>/task/<tid>/stat with awk positional fields, but comm is
    parenthesised AND contains spaces ("Main XThread (F"), so every index after
    it was wrong.  Printing state=XThread should have been the giveaway.
  * the SIGSEGV fault-storm refutation rested on the same parse; downgraded to
    unproven, though the process-wide ~300/s still argues against a tight loop.

Survives: the freeze reproduces without gdb; with the process stopped exactly
one thread is in userspace JIT code while a wchan census puts the rest in
futex_do_wait (55) or hrtimer_nanosleep (11); the instruction is a 16-bit store
through the membase to guest 0x701d0000, a stack-region address, first of a
four-store group; and that memory was unchanged over seconds of running time.

Next step is a host->guest code mapping from Xenia's own code cache rather than
inference from a stale context.
This commit is contained in:
Sylpheed RE agent
2026-08-26 17:38:49 +00:00
parent a70b1d8724
commit ee2f737d78

View File

@@ -746,3 +746,66 @@ freeze itself is not a gdb artefact — it reproduces in every non-gdb run — b
longer window, and identify what `0x824F7240` returns — if that allocator hands longer window, and identify what `0x824F7240` returns — if that allocator hands
back a buffer whose end is not `start + count×8`, the loop's equality test is the back a buffer whose end is not `start + count×8`, the loop's equality test is the
freeze. freeze.
---
# ⚠️ Auditing the gdb session — what survives and what does not
**2026-08-26.** Went back to verify the previous section's instrumentation
before building on it. Some of it does not hold.
## ✅ The context layout is now verified, not assumed
The trailing comments in `ppc_context.h` (`uint64_t r[32]; // 0x20`) are **not
struct offsets** — the struct opens with eight `cr` unions and `fpscr`. So the
previous section's `rsi+0x20` was a guess that happened to be right. Confirmed
empirically from a dump: the `f[32]` doubles (`0x3ff0000000000000` = 1.0 and
friends) begin at **`+0x140`**, and 32 × 8 bytes back from there puts
**`r[32]` at `+0x20 … +0x11F`**. Good.
## 🔴 But the context is **stale mid-function**, so its GPRs are not evidence
In the same dump, **`r1 = 0`**. The guest stack pointer cannot be zero inside a
function. Xenia's JIT keeps live guest registers in *host* registers and spills
only at certain points, so a mid-function `PPCContext` read is a snapshot of
whatever was last written back.
**Therefore `r13 = 0x82457864` does not show where the guest is executing**, and
the previous section's identification of `sub_82457780` is **withdrawn as
unproven**. The value may be a leftover from an earlier spill. What the code at
that address does (a grow-and-copy with a `beq` exit) is accurately described —
it just is not established that the guest is *in* it.
## 🔴 Three readings retracted for broken instrumentation
* **"`rip` identical across samples ⇒ no progress".** gdb stops the process
between samples, and the JIT lays code out differently per run — `rip` was
`a05be939` in one run and `a05bc839` in the next for the *same* instruction.
Constant `rip` across samples inside one gdb session does not establish a hang.
* **"Zero minor faults on the stuck thread"** and **"utime=0"** — both parsed
`/proc/<pid>/task/<tid>/stat` with `awk` positional fields. The `comm` field is
parenthesised **and contains spaces** (`Main XThread (F`), so every field index
after it was wrong. The state I printed as `state=XThread` should have been the
giveaway. Both numbers are void.
* The earlier **SIGSEGV fault-storm refutation** rested on the same per-thread
parse and is downgraded to unproven — though the process-wide rate (~300/s)
still argues against a tight fault loop.
## ✅ What does survive
* The freeze reproduces **without gdb**, in every run, so it is not a debugger
artefact.
* With the process stopped, exactly **one** thread is in userspace JIT code; a
`wchan` census puts every other thread in `futex_do_wait` (55) or
`hrtimer_nanosleep` (11). The active thread is `Main XThread`.
* Its host instruction is a **16-bit store through the membase**,
`mov %r12w,(%rdi,%rax,1)` with `rdi = 0x100000000` and `rax = 0x701d0000` — a
guest **stack-region** address — and it is the first of a four-store group at
`+0`, `+2`, `+4`, `+6`.
* Guest memory at `0x701d0000` and the surrounding 4 KB were **unchanged** over
several seconds of running time.
❔ So the thread is identified and the instruction is identified; *which guest
function* it belongs to is not. The way to get that honestly is a host→guest code
mapping from Xenia itself rather than inference from a stale context — its code
cache knows the answer, and dumping that mapping is the next step.