mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-10-01 23:52:03 -04:00
b76ad85157
Option (b) from the SESSION-12 checkpoint: fresh-exemplar crack-wave on the P27-onboarded ov_SC07_006 (84.6% -> 84.8%). New reusable builder tools/build_wave_args.py emits wave_binary.js args from a fuel manifest. - Drafting wave (wave_binary.js, 24 xHigh drafters over the top-24 reach-138 WAVE families by leverage): 16 self-assessed MATCH, 8 hit the session usage limit (redraft later). - Byte-gate: plain harvest_verify banked 2 (func_801325B8, func_80165CA0); gate_stage reconcile ladder (arity pre-pass + cast/sig_unify) banked +4 (func_8014FE60, func_8014A048, func_801678F0, func_80167540). 7 near, 6 reconcile-fail, 2 CC1-FAIL, 2 DIFF (the incomplete session-limit drafts). - R14/R35 leverage reality-check: nins*reach over-counts. 5 of 6 are already matched in ~135 overlays (only the onboarded SC07 tail ov_SC07_007/010/011 is live, +2-3 each). func_80165CA0 is a TRUE fresh family (135 live) — the x135 sweep prize, propagated next. - R22 clean-fleet 140/140 (engine_core.h arity edit fleet-safe); tools-health green (dedup 1849/0). Propagation is the next commit (§55b: banks first).
90 lines
3.8 KiB
Python
90 lines
3.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Emit wave_binary.js args from a fuel manifest (build_fuel_manifest.py output).
|
|
|
|
Selects draft-now targets (WAVE class, reach>=REACH, Ghidra-C cached), resolves the
|
|
per-function asm / asm_subdir / ghidra_c paths by globbing the overlay's asm tree,
|
|
and detects own_jtbl (an in-body computed jump: a `jr` to a register other than $ra).
|
|
|
|
Splits output into a NON-JTBL list (plain harvest_verify / family_sweep --hseq path)
|
|
and a JTBL list (needs the §8e carve path), sorted by leverage desc. Writes a
|
|
batch-sized wave-args file plus the full pool for later batches.
|
|
|
|
Usage:
|
|
build_wave_args.py --fuel .run/fuel_ov_SC07_006.json --binary ov_SC07_006 \
|
|
--batch 24 --out-prefix .run/wave_sc07006 --draft-dir .run/drafts-sc07006-b1
|
|
"""
|
|
import argparse, glob, json, os, re, sys
|
|
|
|
JR = re.compile(r"\bjr\s+\$(\w+)")
|
|
|
|
def has_own_jtbl(asm_path):
|
|
try:
|
|
with open(asm_path) as f:
|
|
for line in f:
|
|
for m in JR.finditer(line):
|
|
if m.group(1) != "ra":
|
|
return True
|
|
except OSError:
|
|
return False
|
|
return False
|
|
|
|
def resolve_asm(binary, name):
|
|
"""Find func_<ADDR>.s under asm/<binary>/nonmatchings/*/. Returns (asm, subdir) or (None,None)."""
|
|
hits = glob.glob(f"asm/{binary}/nonmatchings/*/{name}.s")
|
|
if not hits:
|
|
return None, None
|
|
asm = hits[0]
|
|
return asm, os.path.dirname(asm)
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--fuel", required=True)
|
|
ap.add_argument("--binary", required=True)
|
|
ap.add_argument("--reach", type=int, default=134)
|
|
ap.add_argument("--batch", type=int, default=24)
|
|
ap.add_argument("--out-prefix", required=True)
|
|
ap.add_argument("--draft-dir", required=True)
|
|
ap.add_argument("--klass", default="WAVE")
|
|
ap.add_argument("--max-nins", type=int, default=150, help="skip GIANT-sized bodies")
|
|
args = ap.parse_args()
|
|
|
|
targets = json.load(open(args.fuel))["targets"]
|
|
pool = [t for t in targets
|
|
if t["class"] == args.klass and t["reach"] >= args.reach
|
|
and t.get("cached") and t["nins"] <= args.max_nins]
|
|
pool.sort(key=lambda t: -t["leverage"])
|
|
|
|
recs_nonjtbl, recs_jtbl, missing = [], [], []
|
|
for t in pool:
|
|
name = t["name"]
|
|
asm, subdir = resolve_asm(args.binary, name)
|
|
if asm is None:
|
|
missing.append(name)
|
|
continue
|
|
rec = {
|
|
"name": name, "addr": t["addr"], "nins": t["nins"], "reach": t["reach"],
|
|
"asm": asm, "asm_subdir": subdir, "ghidra_c": f".run/ghidra_c/{name}.c",
|
|
"own_jtbl": has_own_jtbl(asm), "o0": False, "sibling_ov077": None,
|
|
"leverage": t["leverage"], "region": t.get("region"),
|
|
}
|
|
(recs_jtbl if rec["own_jtbl"] else recs_nonjtbl).append(rec)
|
|
|
|
batch = recs_nonjtbl[:args.batch]
|
|
b1 = {"binary": args.binary, "draftDir": args.draft_dir, "targets": batch}
|
|
json.dump(b1, open(f"{args.out_prefix}_b1_args.json", "w"), indent=1)
|
|
json.dump(recs_nonjtbl, open(f"{args.out_prefix}_nonjtbl_pool.json", "w"), indent=1)
|
|
json.dump(recs_jtbl, open(f"{args.out_prefix}_jtbl_pool.json", "w"), indent=1)
|
|
|
|
print(f"binary={args.binary} reach>={args.reach} class={args.klass} cached-pool={len(pool)}")
|
|
print(f" non-jtbl: {len(recs_nonjtbl)} jtbl: {len(recs_jtbl)} asm-missing: {len(missing)}")
|
|
if missing:
|
|
print(f" missing asm (skipped): {missing[:8]}{'...' if len(missing)>8 else ''}")
|
|
print(f" batch-1 = top {len(batch)} non-jtbl by leverage "
|
|
f"(sum leverage {sum(r['leverage'] for r in batch)}):")
|
|
for r in batch:
|
|
print(f" {r['name']} {r['addr']} nins={r['nins']} reach={r['reach']} lever={r['leverage']}")
|
|
print(f" -> {args.out_prefix}_b1_args.json / _nonjtbl_pool.json / _jtbl_pool.json")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|