64 lines
2.8 KiB
Python
Executable file
64 lines
2.8 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# Static 6502 code discovery for an overlay image: follows jsr/jmp/branches
|
|
# from the given entry points (plus optional executed-PC seeds) and prints
|
|
# code ranges, data gaps and the out-of-window call targets.
|
|
# usage: codeMap.py image.bin base_hex entry_hex[,entry_hex...] [pcs.txt]
|
|
import sys
|
|
img=open(sys.argv[1],'rb').read(); base=int(sys.argv[2],16)
|
|
entries=[int(x,16) for x in sys.argv[3].split(',')]
|
|
seeds=set()
|
|
if len(sys.argv)>4:
|
|
for line in open(sys.argv[4]):
|
|
v=int(line.strip().lstrip('$'),16)
|
|
if base<=v<base+len(img): seeds.add(v)
|
|
# opcode lengths / kinds
|
|
LEN={}
|
|
for op in range(256): LEN[op]=None
|
|
def setl(ops,n):
|
|
for o in ops: LEN[o]=n
|
|
imm=[0x69,0x29,0xC9,0xE0,0xC0,0x49,0xA9,0xA2,0xA0,0x09,0xE9]
|
|
zp=[0x65,0x25,0x06,0x24,0xC5,0xE4,0xC4,0xC6,0x45,0xE6,0xA5,0xA6,0xA4,0x46,0x05,0x26,0x66,0xE5,0x85,0x86,0x84]
|
|
zpx=[0x75,0x35,0x16,0xD5,0xD6,0x55,0xF6,0xB5,0xB4,0x56,0x15,0x36,0x76,0xF5,0x95,0x94]
|
|
zpy=[0xB6,0x96]
|
|
indx=[0x61,0x21,0xC1,0x41,0xA1,0x01,0xE1,0x81]
|
|
indy=[0x71,0x31,0xD1,0x51,0xB1,0x11,0xF1,0x91]
|
|
absl=[0x6D,0x2D,0x0E,0x2C,0xCD,0xEC,0xCC,0xCE,0x4D,0xEE,0x4C,0x20,0xAD,0xAE,0xAC,0x4E,0x0D,0x2E,0x6E,0xED,0x8D,0x8E,0x8C]
|
|
absx=[0x7D,0x3D,0x1E,0xDD,0xDE,0x5D,0xFE,0xBD,0xBC,0x5E,0x1D,0x3E,0x7E,0xFD,0x9D]
|
|
absy=[0x79,0x39,0xD9,0x59,0xB9,0xBE,0x19,0xF9,0x99]
|
|
impl=[0x0A,0x00,0x18,0xD8,0x58,0xB8,0xCA,0x88,0xE8,0xC8,0x4A,0xEA,0x48,0x08,0x68,0x28,0x2A,0x6A,0x40,0x60,0x38,0xF8,0x78,0xAA,0xA8,0xBA,0x8A,0x9A,0x98]
|
|
br=[0x10,0x30,0x50,0x70,0x90,0xB0,0xD0,0xF0]
|
|
setl(imm,2);setl(zp,2);setl(zpx,2);setl(zpy,2);setl(indx,2);setl(indy,2);setl(absl,3);setl(absx,3);setl(absy,3);setl(impl,1);setl(br,2)
|
|
LEN[0x6C]=3
|
|
code=set(); starts=set(); ext={}; work=list(entries)+sorted(seeds)
|
|
def rd(a): return img[a-base]
|
|
while work:
|
|
pc=work.pop()
|
|
while base<=pc<base+len(img) and pc not in starts:
|
|
op=rd(pc); n=LEN[op]
|
|
if n is None: break # illegal -> treat as data
|
|
starts.add(pc)
|
|
for i in range(n): code.add(pc+i)
|
|
if op in br:
|
|
t=pc+2+((rd(pc+1)^0x80)-0x80); work.append(t); pc+=2; continue
|
|
if op==0x20 or op==0x4C:
|
|
t=rd(pc+1)|(rd(pc+2)<<8)
|
|
if base<=t<base+len(img): work.append(t)
|
|
else: ext.setdefault(t,set()).add(pc)
|
|
if op==0x4C: break
|
|
pc+=3; continue
|
|
if op in (0x60,0x40,0x00,0x6C): break
|
|
pc+=n
|
|
rs=[]
|
|
for a in sorted(code):
|
|
if rs and a==rs[-1][1]+1: rs[-1][1]=a
|
|
else: rs.append([a,a])
|
|
print('code bytes:',len(code),'of',len(img))
|
|
print('code ranges:',' '.join('%04X-%04X'%(a,b) for a,b in rs))
|
|
gaps=[]
|
|
prev=base
|
|
for a,b in rs:
|
|
if a>prev: gaps.append((prev,a-1))
|
|
prev=b+1
|
|
if prev<base+len(img): gaps.append((prev,base+len(img)-1))
|
|
print('data gaps:',' '.join('%04X-%04X(%d)'%(a,b,b-a+1) for a,b in gaps if b-a>=0))
|
|
print('external targets:',' '.join('%04X'%t for t in sorted(ext)))
|