re: sub_8226E458 is a splice, but not shown to touch the trigger queue

Chasing which of sub_8226EAB8's 16 callers grows the trigger count: sub_8226E458
decrements a count at 8(r30) then calls the insert helper -- a splice -- and has
exactly one caller, inside sub_8226D740, the per-frame engine->script drain. That
suggests the engine moves records into the phase queue each frame.

But the call site refutes the neat reading: at 0x8226D780 the argument is
lwz r4, 324(r29), the UNIT ARRAY, not the trigger container. So I have not shown
sub_8226E458 touches the trigger queue at all, and 'the engine feeds triggers
each frame' is my inference rather than the disassembly's.

Recorded unresolved. Taking a function's shape for its purpose is what produced
the 'push' mislabel on sub_8226E3B8 and the ADN110-for-null pretty-print, each of
which cost an iteration.

Unaffected and solid: sub_8226EAB8 increments a count at +8 of its container, the
trigger container embeds its list at +12, so the watched word at phase+272+20 is
that inner list's count, and the guest was inside sub_8226EAB8 at the write.

Next: instead of guessing among 16 callers, re-run the watchpoint and read the
guest LR from the context -- the technique that named the writer will name its
caller.
This commit is contained in:
Sylpheed RE agent
2026-08-25 19:44:16 +00:00
parent 53e7dd48cc
commit 5d20de34cb

View File

@@ -442,3 +442,39 @@ from the context block** at the moment of the write. Reading the right offset ou
of `$rsi` would name the guest instruction. That needs Xenia's context layout —
which is in the xenia-rs sources on this box — and is a separate, tractable
piece of work rather than another blind run.
## 🟡 `sub_8226E458` is a splice — but I have not shown it touches the trigger queue
Chasing which of `sub_8226EAB8`'s 16 callers grows the trigger count, the
promising one is `sub_8226E458`:
```
8226e504 lwz r11, 8(r30) ; source count
8226e508 subi r11, r11, 1
8226e50c stw r11, 8(r30) ; source -= 1
8226e51c bl 0x8226EAB8 ; ... then insert into the destination (+1)
```
Remove from one list, insert into another — a **splice**. And it has exactly one
caller, `0x8226D780`, **inside `sub_8226D740`**, the per-frame engine→script
drain. That is a tidy story: the engine moves records into the phase's queue each
frame, and the count I watched rises as it does.
🔴 **The tidy story is not supported by the call site.** At `0x8226D780` the
argument is `lwz r4, 324(r29)``[ScriptPhase+324]`, the **unit array**, not the
trigger container. So whatever `sub_8226E458` splices between, I have **not**
shown it is the trigger queue, and the "engine feeds triggers each frame"
reading is mine rather than the disassembly's.
Recording it unresolved. The same over-reach — taking a function's shape as its
purpose — produced the "push" mislabel on `sub_8226E3B8` and the
`ADN110`-for-null pretty-print, both of which cost an iteration to undo.
**What is solid** and does not depend on this: `sub_8226EAB8` increments a count
at `+8` of the container it is handed; the trigger container embeds its list at
`+12`; and the watched word at `phase+272+20` is therefore that inner list's
count. The guest was executing inside `sub_8226EAB8` at the moment of the write.
**Next:** rather than guessing among 16 callers, set the watchpoint again and
read the **guest LR** out of the context (`%rsi`) at the hit — the same technique
that named `sub_8226EAB8` will name its caller.