Add script to rip the number of args from 68k code

This commit is contained in:
Elliot Nunn 2019-03-20 22:42:35 +08:00
parent be378eb3c4
commit 1c238512f7
1 changed files with 76 additions and 0 deletions

76
search_call_sigs.py Executable file
View File

@ -0,0 +1,76 @@
#!/usr/bin/env python3
import argparse
parser = argparse.ArgumentParser(description='''
Search a 68k binary file for the "MOVE.L <selector>,d0; DC.W $FE22"
motif. Use the upper word of the selector to determine how many
32-bit arguments the call takes. This is useful because, while many
selector names are known from reversing the BlueAbstractionLayerLib,
that PowerPC binary does not reveal anything about their function
signatures. Instead this falls to 68k code, in which the number of
arguments is often passed to a trap via the selector in order to
avoid catastrophic stack damage in the unknown-selector case.
''')
parser.add_argument('src', action='store', help='Source file')
parser.add_argument('-o', nargs='?', action='store', help='Listing file to update')
args = parser.parse_args()
with open(args.src, 'rb') as f:
binary = f.read()
def matches(long, short):
keepers = bytearray()
for i in range(len(short)):
if short[i] == 0:
keepers.append(long[i])
if short[i] not in (0, long[i]):
return False
return bytes(keepers)
MOTIF = b'\x20\x3C\x00\x00\x00\x00\xFE\x22'
for i in range(len(binary) - len(MOTIF)):
match = matches(binary[i:i+len(MOTIF)], MOTIF)
if match:
long = int.from_bytes(match, byteorder='big')
selector = long & 0xFFFF
nargs = long >> 16
print('selector %04x: %d' % (selector, nargs))
if args.o:
with open(args.o) as f:
lines = [l.rstrip('\n').split(' ') for l in f]
for line in lines:
line[0] = int(line[0], 16) # interpret the hex at the start!
for line in lines:
if line[0] == selector:
if line[1] == '?':
print('...updated')
line[1] = str(nargs)
elif line[1] != str(nargs):
print('...WARNING: the listing file says %s' % line[1])
break
else:
lines.append([selector, nargs, '???'])
lines.sort()
for line in lines:
line[0] = '%04X' % line[0]
with open(args.o, 'w') as f:
f.write(''.join(' '.join(l)+'\n' for l in lines))