aboutsummaryrefslogtreecommitdiffstats
path: root/psp_out/phase6_dump_c.py
blob: 8e85ff36b6edd7fafca2ef191925ada5bd02d63b (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
"""Produce readable .c files for every component at every version.

Unlike phase3 (which normalises aggressively for diffing), this preserves
everything a human wants: real names, formatting, comments, and each function's
address. One .c per build, plus a per-build index.
"""
import glob, os, sys, time
import idapro, idautils, idc, ida_hexrays

def dump(elf, out):
    rc = idapro.open_database(elf, run_auto_analysis=False)
    if rc != 0: return None
    ida_hexrays.init_hexrays_plugin()
    fns = sorted(idautils.Functions())
    named = sum(1 for f in fns if not idc.get_func_name(f).startswith(('sub_','nullsub')))
    with open(out, 'w') as fh:
        fh.write("/* %s\n   %d functions (%d named) — decompiled with ported symbols\n"
                 "   Generated by phase6_dump_c.py; addresses are the build's own VAs. */\n\n"
                 % (os.path.basename(elf), len(fns), named))
        for f in fns:
            n = idc.get_func_name(f)
            end = idc.get_func_attr(f, idc.FUNCATTR_END)
            cmt = idc.get_func_cmt(f, 1) or idc.get_func_cmt(f, 0) or ''
            fh.write("//" + "-"*76 + "\n// %s  @ %#x-%#x (%d bytes)\n" % (n, f, end, end-f))
            if cmt:
                for line in cmt.splitlines(): fh.write("// %s\n" % line)
            try:
                fh.write(str(ida_hexrays.decompile(f)) + "\n\n")
            except Exception as e:
                fh.write("/* decompilation failed: %r */\n\n" % (e,))
    idapro.close_database(save=False)
    return len(fns), named

if __name__ == '__main__':
    os.makedirs('decompiled', exist_ok=True)
    fams = sys.argv[1:] or ['hdcp','sos','sys_drv','asd']
    for fam in fams:
        for elf in sorted(glob.glob('handover/elf/versions/%s/*.elf' % fam)):
            tag = os.path.basename(elf)[:-4]
            out = 'decompiled/%s.c' % tag
            t0 = time.time()
            r = dump(elf, out)
            if r is None: print("  FAILED %s" % tag, flush=True); continue
            print("  %-42s %5d fns (%4d named)  %7d bytes  %.1fs"
                  % (tag, r[0], r[1], os.path.getsize(out), time.time()-t0), flush=True)