mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-26 13:33:34 -04:00
fix(phase-28 T5): progress.py — #if 0 blindness + the len()-sum; resident 123/146 -> 122/145
R35: fix the instrument before planting a flag on its denominator.
- #if 0 BLINDNESS: classify() knew `#ifdef NON_MATCHING` (:425) but not `#if 0`, so a dead
analysis body was read as a live definition AND its real INCLUDE_ASM stub counted separately —
the SAME function in BOTH `real` and `stubs`. Live case: resident.c:868-925 wraps a full
void func_800D00E4(s32){...} in #if 0 (its jtbl dossier) and re-declares the stub at :926.
Now the block is skipped entirely: dead code is neither matched nor stubbed.
- THE len()-SUM (the dual defect): `placed` was a set union, so it caught a function in NO bucket
— but `matchable` SUMMED len()s, so a function in TWO buckets counted twice and nothing
complained. matchable/byteident are now SET unions, plus a new OVER-coverage assertion that
fails loudly if any fn lands in multiple buckets. R32 means both directions: nothing missing,
nothing double-counted.
- NEGATIVE CONTROL (the fix must change an answer the old tool gave):
resident REAL 123 -> 122 | matchable 146 -> 145 | 85.62% -> 85.52% | func_800D00E4 no longer
double-counted. FLEET instr 68.9% UNCHANGED (no #if 0 in the overlays) — the fix is scoped.
- FINDING (logged for T7's audit-binaries, does NOT block the flag-plant): the two INDEPENDENT
oracles now agree exactly at 144 — corpus (21 stubs + 123 matched, derived from the tree) and
sig_image (the 2nd oracle) — with EMPTY set difference both ways. progress.py still reports 145
because it counts func_800CEDFC and func_800D33E0, which are DEFINED in resident.c but absent
from sig_image. 0x800CEDFC is the resident's vram base +4 (the first function, code starts at
file offset 0x4 after the leading data word), yet make audit-corpus reports 0 PHANTOM +
0 TRUNCATED. Either sig_image has a boundary blind spot or those defs are not image functions.
progress.py's text-scanning classify() is exactly the re-parsing R33 says should be DERIVED from
corpus instead — a real refactor, logged not rushed.
The flag-plant claim is unaffected: it rests on corpus.stubs('resident') == 21 (tree-derived,
verified 5 ways), not on the contested denominator.
This commit is contained in:
@@ -4,21 +4,21 @@
|
||||
# cross-binary collapsible-byte leverage: docs/duplicates.cross.md.
|
||||
|
||||
# THREE progress metrics (all matter — see the labels):
|
||||
FLEET fn-count byte-ident: 296906 / 353723 = 83.94% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay)
|
||||
FLEET fn-count byte-ident: 296905 / 353722 = 83.94% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay)
|
||||
FLEET instr-weighted : 9017152 / 13081451 = 68.9% (shipped .text across resident+138 overlays; the decomp.dev-DISPLAY number)
|
||||
FLEET distinct-code(uniq): 2757078 / 5574674 = 49.5% (53528/87459 unique fns; the DISTINCT-RE number)
|
||||
MAIN game-code weighted : 436 / 60201 = 0.7% (Phase-27 T10; SEPARATE — LINKED-excluding Ghidra sig dated 2026-06-14, PROVISIONAL until a fresh/complete main sig; NOT folded into the fleet number)
|
||||
|
||||
FLEET REAL substantive : 295051 (of which dedup-shared 233341 via 1840 groups / 233385 instances)
|
||||
FLEET REAL substantive : 295050 (of which dedup-shared 233341 via 1840 groups / 233385 instances)
|
||||
FLEET LINKED PsyQ objs : 959
|
||||
FLEET NON_MATCHING : 7 (0 in any default build — G4)
|
||||
FLEET INCLUDE_ASM stubs : 56810
|
||||
FLEET matchable : 353723
|
||||
FLEET matchable : 353722
|
||||
|
||||
| binary | REAL | shared | LINKED | byte-ident | matchable | byte-ident % |
|
||||
|---|---:|---:|---:|---:|---:|---:|
|
||||
| main | 54 | 2 | 959 | 1055 | 2096 | 50.3% |
|
||||
| resident | 123 | 0 | 0 | 125 | 146 | 85.6% |
|
||||
| resident | 122 | 0 | 0 | 124 | 145 | 85.5% |
|
||||
| ov_SC01_000 | 2123 | 1698 | 0 | 2123 | 2403 | 88.3% |
|
||||
| ov_SC01_001 | 2128 | 1698 | 0 | 2130 | 2466 | 86.4% |
|
||||
| ov_SC01_004 | 2120 | 1689 | 0 | 2121 | 2414 | 87.9% |
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# BFM matching progress (generated by tools/progress.py — authoritative)
|
||||
|
||||
REAL substantive matches : 123 <- the Gen1-exit >=25 bar counts THIS
|
||||
REAL substantive matches : 122 <- the Gen1-exit >=25 bar counts THIS
|
||||
LINKED real PsyQ objects : 0 <- byte-identical via linked SDK objects
|
||||
NON_MATCHING (near-miss) : 0
|
||||
splat-auto empty no-ops : 2
|
||||
INCLUDE_ASM stubs : 21
|
||||
data blobs (excluded) : 0
|
||||
----------------------------------------
|
||||
matchable functions : 146
|
||||
REAL / matchable : 123 / 146 = 84.25%
|
||||
byte-identical/ matchable: 125 / 146 = 85.62% (REAL+LINKED+empties)
|
||||
matchable functions : 145
|
||||
REAL / matchable : 122 / 145 = 84.14%
|
||||
byte-identical/ matchable: 124 / 145 = 85.52% (REAL+LINKED+empties)
|
||||
|
||||
LINKED subsegs: (0 fns)
|
||||
REAL matches: DsMix func_800CEDFC func_800CEE40 func_800CEE84 func_800CEF04 func_800CEF34 func_800CEF5C func_800CEFB0 func_800CF104 func_800CF238 func_800CF370 func_800CF398 func_800CF3B8 func_800CF47C func_800CF4D4 func_800CF510 func_800CF584 func_800CF5D4 func_800CF628 func_800CF714 func_800CF764 func_800CF7A4 func_800CF804 func_800CF818 func_800CF82C func_800CF840 func_800CF854 func_800CF864 func_800CF8B4 func_800CF8CC func_800CF8E4 func_800CF94C func_800CF990 func_800CFBBC func_800CFBCC func_800CFBE8 func_800CFBF8 func_800CFC5C func_800CFD68 func_800CFDA4 func_800CFDE8 func_800D00E4 func_800D02C0 func_800D0588 func_800D05E8 func_800D0630 func_800D065C func_800D0694 func_800D06CC func_800D0C48 func_800D0C74 func_800D0CA0 func_800D0CE0 func_800D0EC4 func_800D0F0C func_800D0F4C func_800D0F8C func_800D0FE0 func_800D1000 func_800D1028 func_800D1054 func_800D1078 func_800D109C func_800D10C8 func_800D10EC func_800D11F0 func_800D1714 func_800D1724 func_800D1734 func_800D1744 func_800D1754 func_800D17B8 func_800D185C func_800D18DC func_800D1938 func_800D19DC func_800D19F0 func_800D1B10 func_800D1BF8 func_800D1D24 func_800D1D94 func_800D1DB0 func_800D1EBC func_800D1F58 func_800D1F90 func_800D20C0 func_800D21C4 func_800D222C func_800D2294 func_800D22E4 func_800D2318 func_800D23D0 func_800D2468 func_800D25FC func_800D2624 func_800D2CA8 func_800D2DAC func_800D2DFC func_800D2E20 func_800D2E6C func_800D2EE8 func_800D2F0C func_800D2F48 func_800D2F8C func_800D2FB0 func_800D2FEC func_800D302C func_800D30A8 func_800D30C8 func_800D3104 func_800D3120 func_800D319C func_800D31C0 func_800D31FC func_800D3238 func_800D3274 func_800D32D4 func_800D3328 func_800D3348 func_800D3384 func_800D3398 func_800D33B8 func_800D33E0
|
||||
REAL matches: DsMix func_800CEDFC func_800CEE40 func_800CEE84 func_800CEF04 func_800CEF34 func_800CEF5C func_800CEFB0 func_800CF104 func_800CF238 func_800CF370 func_800CF398 func_800CF3B8 func_800CF47C func_800CF4D4 func_800CF510 func_800CF584 func_800CF5D4 func_800CF628 func_800CF714 func_800CF764 func_800CF7A4 func_800CF804 func_800CF818 func_800CF82C func_800CF840 func_800CF854 func_800CF864 func_800CF8B4 func_800CF8CC func_800CF8E4 func_800CF94C func_800CF990 func_800CFBBC func_800CFBCC func_800CFBE8 func_800CFBF8 func_800CFC5C func_800CFD68 func_800CFDA4 func_800CFDE8 func_800D02C0 func_800D0588 func_800D05E8 func_800D0630 func_800D065C func_800D0694 func_800D06CC func_800D0C48 func_800D0C74 func_800D0CA0 func_800D0CE0 func_800D0EC4 func_800D0F0C func_800D0F4C func_800D0F8C func_800D0FE0 func_800D1000 func_800D1028 func_800D1054 func_800D1078 func_800D109C func_800D10C8 func_800D10EC func_800D11F0 func_800D1714 func_800D1724 func_800D1734 func_800D1744 func_800D1754 func_800D17B8 func_800D185C func_800D18DC func_800D1938 func_800D19DC func_800D19F0 func_800D1B10 func_800D1BF8 func_800D1D24 func_800D1D94 func_800D1DB0 func_800D1EBC func_800D1F58 func_800D1F90 func_800D20C0 func_800D21C4 func_800D222C func_800D2294 func_800D22E4 func_800D2318 func_800D23D0 func_800D2468 func_800D25FC func_800D2624 func_800D2CA8 func_800D2DAC func_800D2DFC func_800D2E20 func_800D2E6C func_800D2EE8 func_800D2F0C func_800D2F48 func_800D2F8C func_800D2FB0 func_800D2FEC func_800D302C func_800D30A8 func_800D30C8 func_800D3104 func_800D3120 func_800D319C func_800D31C0 func_800D31FC func_800D3238 func_800D3274 func_800D32D4 func_800D3328 func_800D3348 func_800D3384 func_800D3398 func_800D33B8 func_800D33E0
|
||||
NON_MATCHING:
|
||||
|
||||
build SHA1: 8e17e02ff8954d07c979449198f7e1645046b353 (byte-identical)
|
||||
|
||||
+36
-2
@@ -430,6 +430,24 @@ def classify():
|
||||
m = re.search(r'INCLUDE_ASM\("[^"]+",\s*(\w+)\)', '\n'.join(blk))
|
||||
if m: nonmatching.append(m.group(1))
|
||||
continue
|
||||
# `#if 0` — DEAD CODE, not a match (Phase-28 T5). The scanner knew `#ifdef NON_MATCHING`
|
||||
# but not this, so a `#if 0`-preserved analysis body was read as a live definition AND its
|
||||
# real INCLUDE_ASM stub was counted separately => the SAME function landed in both `real`
|
||||
# and `stubs`. Live case: src/resident/resident.c:868-925 wraps a full
|
||||
# `void func_800D00E4(s32){...}` in `#if 0` (its jtbl dossier) and re-declares the stub at
|
||||
# :926 — inflating resident REAL by 1 and the denominator by 1 (reported 123/146 = 85.62%;
|
||||
# honest 122/145 = 85.5%). Skip the block entirely: dead code is neither matched nor stubbed.
|
||||
if re.match(r'#\s*if\s+0\b', s):
|
||||
depth = 1
|
||||
i += 1
|
||||
while i < n and depth:
|
||||
t = lines[i].strip()
|
||||
if re.match(r'#\s*if', t):
|
||||
depth += 1
|
||||
elif t.startswith('#endif'):
|
||||
depth -= 1
|
||||
i += 1
|
||||
continue
|
||||
m = re.match(r'INCLUDE_ASM\("([^"]+)",\s*(\w+)\)', s)
|
||||
if m:
|
||||
seg, fn = m.group(1).rstrip('/').rsplit('/', 1)[-1], m.group(2)
|
||||
@@ -509,8 +527,24 @@ def report(binary, audit=False, write=True):
|
||||
# catch a miscount). Report it LOUDLY rather than silently under-reporting progress.
|
||||
placed = set(real) | set(empty) | set(nonmatching) | set(stubs) | set(blobs) | set(linked)
|
||||
unplaced = sorted(set(_S_INDEX) - placed)
|
||||
matchable = len(real) + len(empty) + len(nonmatching) + len(stubs) + len(linked)
|
||||
byteident = len(real) + len(linked) + len(empty) # all byte-identical in the build
|
||||
|
||||
# OVER-coverage is the DUAL defect, and the assertion above is blind to it (Phase-28 T5). `placed`
|
||||
# is a set union, so it catches a function in NO bucket — but `matchable` below summed len()s, so a
|
||||
# function in TWO buckets was counted twice and nothing complained. Not hypothetical: the `#if 0`
|
||||
# hole (fixed above) put func_800D00E4 in BOTH `real` and `stubs`, reporting the resident as
|
||||
# 123/146 = 85.62% when the truth is 122/145 = 85.5% — and the flag-plant target is that very
|
||||
# denominator. R32 means assert coverage in BOTH directions: nothing missing, nothing counted twice.
|
||||
_buckets = {"real": real, "empty": empty, "nonmatching": nonmatching, "stubs": stubs, "linked": linked}
|
||||
_seen = {}
|
||||
for _name, _b in _buckets.items():
|
||||
for _fn in _b:
|
||||
_seen.setdefault(_fn, []).append(_name)
|
||||
_multi = {f: bs for f, bs in _seen.items() if len(bs) > 1}
|
||||
assert not _multi, ("progress.py: %d function(s) landed in MULTIPLE buckets — a MISCOUNT, not a "
|
||||
"no-op (R32): %s" % (len(_multi), dict(list(_multi.items())[:5])))
|
||||
|
||||
matchable = len(set(real) | set(empty) | set(nonmatching) | set(stubs) | set(linked)) # SET, not a len() sum
|
||||
byteident = len(set(real) | set(linked) | set(empty)) # all byte-identical in the build
|
||||
|
||||
out = []
|
||||
out.append("# BFM matching progress (generated by tools/progress.py — authoritative)")
|
||||
|
||||
Reference in New Issue
Block a user