Handoff snapshot of the env-gated diagnostic scaffolding used across the intro-video RE. Kept out of the milestone commits (645feb8..5573ac1) to keep those clean; committed here so nothing is lost on handoff. New — XENIA_PROFILE wall-time profiler (crates/xenia-gpu/src/prof.rs): Coarse buckets attributing playback wall time to interpreter (step_block), kernel HLE (call_export), block decode/cache (lookup_or_build), texture decode, host draw, and present; prints periodic snapshots (every 500M guest instr, or every 500 presents) + a clean-exit report. Hot path is gated on a cached is_on() (one relaxed load) so it is zero-cost when XENIA_PROFILE is unset. Call sites: main.rs run_superblock / parallel worker (step_block, lookup_or_build, call_export), texture_cache ensure_cached, render.rs present + dispatch_xenos_draws. First profile (movie playback, headless single-thread lockstep): effective ~35 MIPS; interpreter body ~40% @ ~95-102 MIPS; texture decode 0.3% (cache works); present ~0%; the rest is per-block dispatch + scheduler plumbing (~13 instr/block over 229M blocks). Overhead-bound, not interpreter-body bound; the levers are coarser execution units (superblock chaining) and ultimately a JIT. Pre-existing read-only probe knobs (were uncommitted; env-gated, observe-only): XENIA_RET_CAPTURE_PC/_REG/_MEM, LOG_RESUMES, LOG_WAITS, LOG_SIGNAL, FORCE_TID, STARVE_LIMIT, INCUMBENT_PICK, INSTR_PER_MS, DUMP_FRAME, DUMP_WGSL, BIND_LOG, CONST_LOG, DISPATCH_REC, AUDIT_PC_TRACE. Tooling: sylph-run.sh (movie oracle loop, 180s default timeout), zq.py (DuckDB disasm/xref helper). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
67 lines
2.8 KiB
Python
Executable File
67 lines
2.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Sylpheed static-analysis helper over DuckDB `sylpheed.db`.
|
|
|
|
Hides the gotchas: DECIMAL bounds (DuckDB rejects 0x literals), read-only connect,
|
|
and the fact that the engine vtable / rdata is NOT in the DB (read it from guest
|
|
memory with `xenia-rs exec ... --dump-addr=0x<va>` instead).
|
|
|
|
Usage:
|
|
zq.py dis <lo_hex> <hi_hex> # disassemble [lo,hi)
|
|
zq.py fn <pc_hex> # function containing pc (address,name,end)
|
|
zq.py xref <target_hex> # xrefs whose target == addr (callers)
|
|
zq.py callers <vtable_off_dec> # call-sites of vtable slot at byte offset N
|
|
# (finds `lwz r11, N(r11)` + reports the fn)
|
|
zq.py grep <substr> # instructions whose operands LIKE %substr%
|
|
zq.py find <word_hex> # instructions whose raw word == value (e.g. a ptr)
|
|
"""
|
|
import duckdb, sys
|
|
|
|
DB = '/home/fabi/RE - Project Sylpheed/xenia-rs/sylpheed.db'
|
|
c = duckdb.connect(DB, read_only=True)
|
|
H = lambda x: '0x%08x' % x
|
|
|
|
|
|
def _fn(pc):
|
|
r = c.execute('SELECT address,name,end_address FROM functions WHERE address<=? AND end_address>? '
|
|
'ORDER BY address DESC LIMIT 1', [pc, pc]).fetchall()
|
|
return f'{r[0][1]}({H(r[0][0])})' if r else '?'
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 2:
|
|
print(__doc__); return
|
|
cmd = sys.argv[1]
|
|
if cmd == 'dis':
|
|
lo, hi = int(sys.argv[2], 16), int(sys.argv[3], 16)
|
|
for a, m, o in c.execute('SELECT address,mnemonic,operands FROM instructions '
|
|
'WHERE address>=? AND address<? ORDER BY address', [lo, hi]).fetchall():
|
|
print(H(a), m, o)
|
|
elif cmd == 'fn':
|
|
print(_fn(int(sys.argv[2], 16)))
|
|
elif cmd == 'xref':
|
|
t = int(sys.argv[2], 16)
|
|
for s, k, i, sf in c.execute('SELECT source,kind,instruction,source_func FROM xrefs '
|
|
'WHERE target=? ORDER BY source', [t]).fetchall():
|
|
print(H(s), k, 'in', _fn(s), ':', i)
|
|
elif cmd == 'callers':
|
|
off = int(sys.argv[2]) # decimal byte offset, e.g. 196 for vtable[49]
|
|
pat = f'r11, {off}(r11)'
|
|
for (a,) in c.execute("SELECT address FROM instructions WHERE mnemonic='lwz' AND operands=? "
|
|
'ORDER BY address', [pat]).fetchall():
|
|
print(H(a), 'in', _fn(a))
|
|
elif cmd == 'grep':
|
|
sub = sys.argv[2]
|
|
for a, m, o in c.execute("SELECT address,mnemonic,operands FROM instructions "
|
|
"WHERE operands LIKE ? ORDER BY address", [f'%{sub}%']).fetchall():
|
|
print(H(a), m, o, ' in', _fn(a))
|
|
elif cmd == 'find':
|
|
w = int(sys.argv[2], 16)
|
|
for (a,) in c.execute('SELECT address FROM instructions WHERE raw=? ORDER BY address', [w]).fetchall():
|
|
print(H(a))
|
|
else:
|
|
print(__doc__)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|