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.
53 lines
1.7 KiB
Python
Executable File
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)
|