"""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)