Files
Sylpheed/tools/re-capture/host_addr.py
Sylpheed RE agent 7a0ee48c3f re: ISL opcodes decoded; the branch base is PER PHASE and isl.py was wrong
All 25 opcodes now have meanings. Ops 2/4/6/8 are integer compound assignment
(+= -= *= /=) and 3/5/7/9 the float versions; 10 and 11 are integer and float
compare writing three condition bits; 13-18 are je/jne/jl/jle/jg/jge; 21-24 are
push.i/push.f/pop.i/pop.f over deques at phase+44 and phase+64.

The shared-handler question is answered: the dispatcher leaves the opcode in r4
and the shared thunks never overwrite it, so those helpers take an extra opcode
argument and index a secondary table (0x82271448, 0x8227152C).

CORRECTION to my own tool and note: the branch/jump base is [phase+232], which
the phase initialiser sets to 0x24 + the phase's entry from the mission-level
stream -- 0xE4 / 0x14AA8 / 0x24B4C for Stage 02's three phases, not the file's
0x24. Measured on phase 1: base 0xE4 puts 525 of 525 branch targets on an
instruction boundary; base 0x24 manages 188. isl.py had been using 0x24 for
every phase, so its jump targets were wrong throughout. Fixed via
isl.phase_bases().

That also settles two things mission-script-ssb.md left open: offsets ARE
code-base-relative, and 0x1883's operand IS a code pointer -- the earlier worry
that some 'land on IEEE floats' was an artefact of adding the wrong base.
2026-08-25 18:52:09 +00:00

53 lines
1.7 KiB
Python
Executable File

#!/usr/bin/env python3
"""Translate the trigger-count guest VA into a HOST address gdb can watch.
gdb debugs the host emulator process, so a guest VA is meaningless to it. Canary
backs guest memory with one shared-memory file, so the chain is:
guest VA -> file offset gmem.va_to_off
file offset -> host address the shm mapping in /proc/<pid>/maps,
host = map_start - map_file_offset + off
Prints the host address on stdout, and the working on stderr.
"""
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import gmem
import isl
import squadron_state as S
ssb = isl.load('/tmp/Stage02.ssb')
path = gmem.mem_path()
size = os.path.getsize(path)
with open(path, 'rb', buffering=0) as f:
m, _fb = S.find_mission(f, size, ssb)
if m is None:
print('NOTFOUND'); sys.exit(1)
ph = S.u32(f, m + 4)
va = ph + 272 + 20
off = gmem.va_to_off(va)
shm = os.path.basename(path)
pids = [p for p in os.listdir('/proc') if p.isdigit()
and os.path.exists('/proc/%s/comm' % p)
and open('/proc/%s/comm' % p).read().strip() == 'xenia_canary']
if not pids:
print('NOPID'); sys.exit(1)
host = None
for line in open('/proc/%s/maps' % pids[0]):
if shm not in line:
continue
rng, _perm, mo = line.split()[0], line.split()[1], line.split()[2]
a, b = (int(x, 16) for x in rng.split('-'))
mo = int(mo, 16)
if mo <= off < mo + (b - a):
host = a - mo + off
break
if host is None:
print('NOMAP'); sys.exit(1)
print('mission 0x%08X phase 0x%08X va 0x%08X off 0x%X -> host 0x%X'
% (m, ph, va, off, host), file=sys.stderr)
print('0x%X' % host)