re: the trigger-count watchpoint fires, but the writer is JIT guest code
trigger_watch.sh + host_addr.py translate the guest VA to a host address (0xBE14DEA4 -> host 0x1BE14DEA4) and watch it. It fires: Thread 50 'Main XThread', old 0, new 16777216 -- which is big-endian 1 read little-endian, so the count going 0 -> 1, independently confirming the field. The write happens on the guest's own main thread, not an emulator worker. But the writer cannot be named from the host stack: the faulting PC is 0xa0c65f23 with no symbol, executing 'mov 0x110(%rsi),%rbx', i.e. Xenia's JIT-compiled guest code, and the frames above it are not host-unwindable. So the watchpoint answers when and which thread, not which guest function. Recorded as a ceiling of the method rather than retried blindly. The way past it is that the JIT holds the guest context in a register (%rsi here), so the guest PC is recoverable from the context block -- which needs Xenia's context layout from the xenia-rs sources on this box, a separate tractable piece of work.
This commit is contained in:
@@ -368,3 +368,36 @@ watchpoint on the count word** during a live mission. The address is known at
|
|||||||
runtime (`ScriptPhase + 272 + 20`), the count demonstrably changes within ~2
|
runtime (`ScriptPhase + 272 + 20`), the count demonstrably changes within ~2
|
||||||
minutes of flight, and the watchpoint reports the writing instruction directly
|
minutes of flight, and the watchpoint reports the writing instruction directly
|
||||||
instead of inferring it from static shape.
|
instead of inferring it from static shape.
|
||||||
|
|
||||||
|
## 🟡 The watchpoint fired — the writer is JIT-compiled GUEST code, not host code
|
||||||
|
|
||||||
|
`tools/re-capture/trigger_watch.sh` + `host_addr.py` translate the guest VA into
|
||||||
|
a host address and set a gdb watchpoint on it:
|
||||||
|
|
||||||
|
```
|
||||||
|
mission 0xBC7A2A20 phase 0xBE14DD80 va 0xBE14DEA4 off 0x11E14DEA4 -> host 0x1BE14DEA4
|
||||||
|
Hardware watchpoint 1: *(unsigned int*)0x1BE14DEA4
|
||||||
|
Thread 50 "Main XThread" hit it: Old value = 0 New value = 16777216
|
||||||
|
```
|
||||||
|
|
||||||
|
✅ **Two things confirmed.** `16777216` is `0x01000000` — big-endian `1` read
|
||||||
|
little-endian, so this is exactly the count going **0 → 1**, independently
|
||||||
|
confirming that `[ScriptPhase+272+20]` is the field. And the write happens on
|
||||||
|
the **guest's own Main XThread**, not on an emulator worker.
|
||||||
|
|
||||||
|
🔴 **But the writer cannot be named from the host stack.** The faulting PC is
|
||||||
|
`0xa0c65f23`, with no symbol, and the instruction is
|
||||||
|
`mov 0x110(%rsi),%rbx` — this is **Xenia's JIT-compiled guest code**. The
|
||||||
|
backtrace above it is garbage (`0x45e0000000`, `0x100000000`), because JIT frames
|
||||||
|
are not host-unwindable.
|
||||||
|
|
||||||
|
So the host watchpoint answers *when* and *which guest thread*, but **not which
|
||||||
|
guest function** — the thing I actually wanted. The method has a ceiling here,
|
||||||
|
and it is worth recording rather than re-attempting the same way.
|
||||||
|
|
||||||
|
**What would get past it:** the JIT keeps the guest context in a register
|
||||||
|
(`%rsi` here, given `mov 0x110(%rsi),%rbx`), so the **guest PC is recoverable
|
||||||
|
from the context block** at the moment of the write. Reading the right offset out
|
||||||
|
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.
|
||||||
|
|||||||
Reference in New Issue
Block a user