docs+tools: scope the guest-PC experiment properly, and let ob_bitflag find the counter itself
The freeze's named next step is more expensive than it looked, and the reasons are recorded before anyone starts it: xenia's stack walker is a TWENTY-LINE STUB on POSIX (Create logs "unimplemented" and returns nullptr), so ThreadDebugInfo::guest_pc is never filled here; PPCContext carries no live PC either. A reverse host->guest map is buildable - the code cache already learns the mapping in OnCodePlaced - but that plus a way to sample another thread's RIP is a real emulator feature, not a patch. The cheap route that does exist: gdb is installed and ptrace_scope is 1, so attaching to a running emulator is refused but launching it UNDER gdb is not - run-canary execs $XENIA_BIN, so a wrapper that execs "gdb --args <real binary>" keeps the lockfile and flags and makes gdb the parent. That would separate "spinning in guest JIT code" from "spinning in a xenia loop", which is the fork this is stuck on. Not attempted yet. ob_bitflag now locates the counter itself from the three addresses measured so far, instead of refusing when the default one is wrong. That costs no transitions, and with roughly half of all runs ending early, transitions are the scarce resource. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
@@ -40,13 +40,30 @@ import gmem # noqa: E402
|
||||
import gworld # noqa: E402
|
||||
import ob_read # noqa: E402
|
||||
|
||||
VA = int(os.environ.get("OB_VA", "0xBDB59668"), 0)
|
||||
# The counter's address is per-run, but not arbitrary: every run measured so far
|
||||
# has put it in a narrow band, and three exact addresses have now been confirmed
|
||||
# or strongly implicated. Trying the known ones against the HUD costs nothing and
|
||||
# no transitions, where ob_hunt.py needs two — and with roughly half of all runs
|
||||
# ending early, transitions are the scarce resource.
|
||||
KNOWN_VAS = [0xBDB59668, 0xBDB49668, 0xBDB58668]
|
||||
VA = int(os.environ["OB_VA"], 0) if "OB_VA" in os.environ else None
|
||||
LO, HI = -0x400, 0xC00 # window around the position triple
|
||||
DELTA = 0x130
|
||||
|
||||
|
||||
def counter(fd):
|
||||
return struct.unpack(">I", os.pread(fd, 4, gmem.va_to_off(VA)))[0]
|
||||
def counter(fd, va=None):
|
||||
return struct.unpack(">I", os.pread(fd, 4, gmem.va_to_off(va or VA)))[0]
|
||||
|
||||
|
||||
def locate(fd, hud_value):
|
||||
"""Pick whichever known address currently equals the HUD, or None."""
|
||||
for va in ([VA] if VA else KNOWN_VAS):
|
||||
try:
|
||||
if counter(fd, va) == hud_value:
|
||||
return va
|
||||
except Exception:
|
||||
continue
|
||||
return None
|
||||
|
||||
|
||||
def hud(shot):
|
||||
@@ -92,18 +109,26 @@ def main():
|
||||
w = gworld.World()
|
||||
defs = entities2.definitions(w)
|
||||
|
||||
global VA
|
||||
v = None
|
||||
for _ in range(8):
|
||||
v = hud(f"{out}/a.png")
|
||||
n0 = counter(w.fd)
|
||||
if v is not None:
|
||||
break
|
||||
time.sleep(3)
|
||||
print(f"HUD={v} RAM={n0}", flush=True)
|
||||
if v is None or v != n0:
|
||||
print("HUD and RAM disagree (or unreadable) — re-scan with ob_hunt.py",
|
||||
if v is None:
|
||||
print("could not read the HUD counter at all — is this in flight?",
|
||||
flush=True)
|
||||
return 2
|
||||
found = locate(w.fd, v)
|
||||
if found is None:
|
||||
tried = " ".join(f"{a:#x}" for a in ([VA] if VA else KNOWN_VAS))
|
||||
print(f"HUD={v} but none of the known addresses holds it ({tried}) — "
|
||||
f"re-scan with ob_hunt.py and pass OB_VA", flush=True)
|
||||
return 2
|
||||
VA = found
|
||||
n0 = counter(w.fd)
|
||||
print(f"HUD={v} RAM={n0} at {VA:#x}", flush=True)
|
||||
|
||||
for _ in range(6):
|
||||
nA, namesA, wordsA = sample(w, defs, "A")
|
||||
|
||||
Reference in New Issue
Block a user