aboutsummaryrefslogtreecommitdiffstats
path: root/psp_out/emitscan.py
blob: c62f6103979145e52cea3159d64c184881c23520 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
"""Emitter scan that handles BOTH `str rX,[sp]` and `stm sp,{rX,...}` opcode stores.

The earlier version only matched `str [sp]` and therefore MISSED every stub that
uses STM -- which is how several HDCP disp_* stubs write frame[0]. Any previous
"no module emits X" conclusion produced by the old scanner is unsound.
"""
import struct, os, sys
from capstone import *
md=Cs(CS_ARCH_ARM,CS_MODE_THUMB)
MODS=(('sos','handover/elf/sos2.elf'),('sys_drv','handover/elf/sys_drv2.elf'),
      ('asd','handover/elf/asd2.elf'),('hdcp','handover/elf/hdcp2.elf'),
      ('dtm','handover/elf/dtm2.elf'),('ras','handover/elf/ras2.elf'))
def load(p):
    raw=open(p,'rb').read(); ph=struct.unpack('<I',raw[28:32])[0]
    o,v,pa,f=struct.unpack('<IIII',raw[ph+4:ph+20]); return raw[o:o+f],v
def emitted(body,v):
    out={}
    sites=[v+a for a in range(0,len(body)-1,2) if body[a]==0xF2 and body[a+1]==0xDF]
    for s in sites:
        lo=max(v,s-0x60); regs={}; svc_r0=None
        for i in md.disasm(body[lo-v:s-v+2], lo):
            m=i.mnemonic; op=i.op_str
            if m in ('movs','mov.w','movw','mov') and ',' in op:
                d,src=[x.strip() for x in op.split(',',1)]
                if src.startswith('#'):
                    try: regs[d]=int(src[1:],0)
                    except: pass
                elif src in regs: regs[d]=regs[src]
                else: regs.pop(d,None)
            elif m.startswith('str') and '[sp]' in op:
                r=op.split(',')[0].strip()
                if r in regs: out.setdefault(regs[r],[]).append(hex(s))
            elif m.startswith('stm') and 'sp' in op.split('{')[0]:
                inner=op.split('{')[1].split('}')[0]
                first=inner.split(',')[0].strip()      # STM writes the FIRST reg to [sp]
                if first in regs: out.setdefault(regs[first],[]).append(hex(s))
    return out
targets=[int(x,0) for x in sys.argv[1:]] or None
for name,p in MODS:
    if not os.path.exists(p): continue
    body,v=load(p); e=emitted(body,v)
    if targets:
        hit={k:v2 for k,v2 in e.items() if k in targets}
        print("  %-8s emits %s"%(name, {hex(k):v2[:2] for k,v2 in sorted(hit.items())} or 'NONE'))
    else:
        print("  %-8s %d distinct opcodes: %s"%(name, len(e), sorted(hex(k) for k in e)[:24]))