diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index 8b36e1fc..543921a1 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -696,6 +696,18 @@ search cannot find a *schedule*. nothing. ✅ **Fixed: `INDEX.md` now has a generated table of all 59 notes** with title + status and says to search it before starting. Regenerate when notes are added. +* ✅🔴 **(2026-08-25) Freeze frontier: wait confirmed, but `info args` won't work.** + ✅ **Verified** the frozen frame's export by ordinal: the shim's + `(unsigned short)176` = `0xB0` = **`KeWaitForSingleObject`** + (`xboxkrnl_table.inc:190`) — previously read off frame names, now pinned. + 🔴 **Corrected:** the doc's "the handle is one `info args` away" is wrong for + this binary — `readelf` shows **0 debug sections**, symtab only (27 807 entries). + Not stripped ≠ has debug info; gdb can name frames and nothing inside them. + **Two routes, costs recorded:** (1) prologue-guided stack read of `XObject::Wait`'s + spilled `this` — no rebuild, keeps the oracle identical, but per-frame + archaeology; (2) a `RelWithDebInfo` build via `build-canary` — makes this and all + future freeze questions easy, at a full compile and a binary differing from the + one every other measurement used. * ~~🚧 BLOCKER: t=210/240 unreachable in one turn~~ — **superseded, see above**; it rested on an untested assumption that a turn is one shell call. 595 s shell cap − ~220 s boot (a ~190 s title movie that cannot be tapped through) − ~25 s startup = **~350 s observation ≈ 193 game-seconds**. diff --git a/docs/re/mission-freeze-resume-spin.md b/docs/re/mission-freeze-resume-spin.md index c8cab18e..a1424715 100644 --- a/docs/re/mission-freeze-resume-spin.md +++ b/docs/re/mission-freeze-resume-spin.md @@ -671,3 +671,60 @@ was simply blind. `docs/re/`, 59 entries with title and status, and says outright that it should be searched before starting an investigation. Regenerating it is a few lines of Python and should be redone whenever notes are added. + +--- + +# 2026-08-25 — the wait is confirmed as `KeWaitForSingleObject`, but `info args` will not work + +Two corrections to the plan this file leaves for the next pass, both cheap to +establish and both worth having before a run is spent on them. + +## ✅ Verified: the export in the frozen frame is `KeWaitForSingleObject` + +The backtrace's shim frame carries its ordinal as a template parameter: + +``` +xe::kernel::shim::ExportRegistrerHelper<(KernelModuleId)0, (unsigned short)176, …> +``` + +`176` decimal is `0xB0`, and `xboxkrnl_table.inc:190` reads: + +``` +XE_EXPORT(xboxkrnl, 0x000000B0, KeWaitForSingleObject, kFunction), +``` + +So the two hot threads really are in `KeWaitForSingleObject` — previously read +off the frame names, now pinned by ordinal. + +## 🔴 Corrected: there is no DWARF, so the handle is not one `info args` away + +This file's next step says the wait target is "one `info args`-equivalent away +now that a debugger can be attached at will". That is **not true of this binary**: + +``` +readelf -S xenia_canary | grep -c 'debug_info|debug_line' -> 0 +.debug* sections -> none +symtab entries -> 27 807 +``` + +The Release build is **not stripped**, which is why frames carry function names, +but it has **no debug info at all**. gdb can therefore name a frame and nothing +inside it — no `info args`, no `p *this`, no struct members. The earlier note +conflated "not stripped" with "has debug info"; they are different things. + +## The two routes that remain, with their real costs + +1. **Prologue-guided stack read.** `XObject::Wait`'s `this` arrives in `RDI` and + is almost certainly spilled to a known stack slot. Disassembling the prologue + (`x/20i`) locates the slot, and the frozen frame's `RBP`/`RSP` then give the + pointer, from which the object's vtable identifies its type. No rebuild, but + it is per-frame archaeology and must be redone if the binary changes. +2. **A `RelWithDebInfo` build** via `build-canary`. Makes `info args`, `p *this` + and member access work as the note assumed, at the price of a full compile and + a binary that is not the one every other measurement in this corpus was taken + against. + +Route 1 is cheaper and keeps the oracle identical; route 2 is what makes this and +every future freeze question easy. Neither is attempted here — recorded so the +next pass picks with the costs visible instead of discovering the missing DWARF +mid-run.