re: the JIT context is in %rsi; but the re-run could not locate the mission

From Canary's own source (x64_emitter.cc:881) GetContextReg() returns rsi, so at
any JIT instruction %rsi is the PPCContext* -- which is also why the faulting
instruction read 0x110(%rsi), a guest register load. That is the way past the
watchpoint's ceiling: the guest register file is available at the write, and a
0x82xxxxxx word picked out of it resolves against sylpheed.db to name the caller.
trigger_watch.sh now dumps x/128wx  instead of a useless host backtrace.

The re-run then failed for an unrelated and unexplained reason: it reached
flight, the pilot bound, the guest was animating, and find_mission returned
NOTFOUND. Narrowed: the .ssb header is absent from guest memory (0 hits where
earlier runs hit immediately), ADN110 is absent too, but the manifest string
'Stage02.ssb' IS present at 0xBDA6C50B. So memory is readable and the manifest
is loaded while the script is not, in a mission that is flying.

No explanation offered. The cheap discriminator for next time is to poll for the
header from the moment flight starts and record when it appears, instead of
sampling once.
This commit is contained in:
Sylpheed RE agent
2026-08-25 19:03:33 +00:00
parent c50ab7275f
commit 761dcd004c
2 changed files with 54 additions and 1 deletions

View File

@@ -407,3 +407,47 @@ could not be the `1500` the pilot logs. **Wrong.** This run reads
`0x44BB8000` = **1500.0f** at the same offset. It is the same field; the value
simply differs between runs (craft or loadout). The "different field or scale"
note is retracted.
## ✅ The JIT keeps the guest context in `%rsi` — from Canary's own source
The watchpoint's ceiling was that the writer is JIT code with no host symbols.
The way past it is in the emulator's source, not the disassembly:
```
src/xenia/cpu/backend/x64/x64_emitter.cc:881
Xbyak::Reg64 X64Emitter::GetContextReg() const { return rsi; }
Xbyak::Reg64 X64Emitter::GetMembaseReg() const { return rdi; }
```
So at any JIT instruction, **`%rsi` is the `PPCContext*`** — which is also why
the faulting instruction read `0x110(%rsi)`: it was loading a guest register.
The whole guest register file is available at the moment of the write, and a
guest code address (`0x82xxxxxx`) picked out of it resolves against
`sylpheed.db` to name the calling function.
`trigger_watch.sh` now dumps `x/128wx $rsi` at the hit rather than a useless host
backtrace. ⚠️ Reading the LR *by offset* would need `PPCContext`'s layout;
scanning the dump for `0x82…`-range words avoids parsing a 900-line struct and
is what the script does.
## 🔴 The re-run could not locate the mission — unexplained
The run reached flight (`readyroom at 18s`, `IN FLIGHT at 40s`), the pilot bound,
the guest was **animating**, and yet `find_mission` returned `NOTFOUND`.
Narrowing it:
* the `.ssb` **header is not in guest memory** — 0 hits for its 20-byte
signature, where previous runs hit it immediately;
* **`ADN110` is not in guest memory either** — so the script's symbol table is
not resident;
* but **`Stage02.ssb` (the manifest string) *is*** present, at `0xBDA6C50B`.
So guest memory is readable and the manifest is loaded, while the script itself
is not — in a mission that is demonstrably flying. That contradicts four earlier
runs where the header was found within seconds of flight.
**I do not have an explanation**, and I am not going to invent one. Candidates
worth separating next time: the script is loaded later than I assumed and the
earlier runs sampled later; the probe raced a load; or this run entered flight
by a different path. The cheap discriminator is to poll for the header from the
moment flight starts and record *when* it appears, rather than sampling once.