re: freeze frontier — wait confirmed by ordinal, but info args will not work here

Two corrections to the plan the freeze file leaves for the next pass, both cheap
to establish and both worth having before a run is spent discovering them.

The export in the frozen frame is confirmed. The shim frame carries its ordinal
as a template parameter, 176 decimal, which is 0xB0, and xboxkrnl_table.inc line
190 maps that to KeWaitForSingleObject. The identification was previously read
off frame names; it is now pinned by ordinal.

The file's stated next step does not work on this binary. It says the wait
target is one info-args-equivalent away now that a debugger can be attached, but
readelf shows zero debug sections and only a symtab of 27807 entries. The
Release build is not stripped, which is why frames carry function names, but it
has no debug info at all, so gdb can name a frame and nothing inside it: no info
args, no p *this, no member access. The earlier note conflated "not stripped"
with "has debug info".

Two routes remain and their costs are now recorded. A prologue-guided stack read
can recover XObject::Wait's spilled this pointer from a known stack slot, needing
no rebuild and keeping the oracle byte-identical to the one every other
measurement in this corpus used, at the price of per-frame archaeology that must
be redone if the binary changes. Alternatively a RelWithDebInfo build via
build-canary makes this and every future freeze question straightforward, at the
price of a full compile and a binary that differs from the measured one.

Neither is attempted here. Recorded so the next pass picks with the costs
visible.
This commit is contained in:
Sylpheed RE agent
2026-08-25 07:36:56 +00:00
parent 1c4b89d24d
commit 37ba2a9169
2 changed files with 69 additions and 0 deletions

View File

@@ -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**.

View File

@@ -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.