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
|
"""Phase 1 of the complete version-diff plan: build a base IDB for EVERY firmware
build and record coverage metrics. No symbol porting yet — this phase only
establishes that every build analyses cleanly and reports how much of each image
IDA actually recognised as code.
Anti-corner-cutting: every build is reported, including failures. A build with
anomalously low coverage is a problem to fix, not to silently skip.
"""
import glob, os, sys, json, time
import idapro, idautils, idc
rows=[]
elfs = sorted(glob.glob('handover/elf/versions/*/*.elf'))
print("building IDBs for %d builds\n" % len(elfs), flush=True)
for i, p in enumerate(elfs, 1):
fam = os.path.basename(os.path.dirname(p))
name = os.path.basename(p)
t0=time.time()
try:
rc = idapro.open_database(p, run_auto_analysis=True)
if rc != 0:
rows.append(dict(fam=fam, name=name, ok=False, err="open rc=%s"%rc)); continue
fns = list(idautils.Functions())
tot = sum(idc.get_func_attr(f, idc.FUNCATTR_END)-f for f in fns)
span = sum(idc.get_segm_end(s)-idc.get_segm_start(s) for s in idautils.Segments())
cov = 100.0*tot/span if span else 0.0
rows.append(dict(fam=fam, name=name, ok=True, nfunc=len(fns), bytes_in_funcs=tot,
span=span, coverage=round(cov,1), secs=round(time.time()-t0,1)))
idapro.close_database(save=True)
print(" [%2d/%2d] %-40s funcs=%-5d cov=%5.1f%% (%.1fs)" %
(i, len(elfs), name, len(fns), cov, time.time()-t0), flush=True)
except Exception as e:
rows.append(dict(fam=fam, name=name, ok=False, err=repr(e)[:120]))
print(" [%2d/%2d] %-40s FAILED %r" % (i, len(elfs), name, e), flush=True)
json.dump(rows, open('phase1_coverage.json','w'), indent=1)
print("\nwrote phase1_coverage.json")
|