diff --git a/docs/SETUP.md b/docs/SETUP.md index 91fca1630..3e4d05f05 100644 --- a/docs/SETUP.md +++ b/docs/SETUP.md @@ -774,6 +774,7 @@ Every script under `tools/` (plus the two report make-targets), grouped by purpo | | `tools/jtbl_carve.py` — per-table `sltiu` bound | **(P31 S75, cookbook §446)** Two silent defects that made a byte-identical `.text` gate DIFF for five sessions across four 279-ins siblings. (a) **The over-span clamp disabled itself on the functions that needed it.** spimdisasm runs an island's LAST `jtbl_` dlabel one word into the following NON-ZERO data (string bytes), so the zero-word trim cannot see it; the clamp that would have caught it was guarded by `len(sltiu_bounds)==1`, and `sltiu` is ALSO how gcc emits an unsigned range check (`(u32)(x-lo) < n`, I1) — the four siblings carry five distinct `sltiu` immediates, so the guard stood down. A 0x28 table got 0x2C reserved: image 4 bytes short, ~850 `%lo` shifted, whole-binary DIFF. Fixed with `_table_bound()` — gcc-2.7.2's dispatch is a fixed idiom, so the `sltiu` nearest ABOVE that table's own `%hi(jtbl_X)` is unambiguous per table. (b) **A carve span whose `JTBL_PADS` line has no `tables=` comment** (written by `jtbl_pads_fix`) fell through both merge branches and lost its existing table's start, refusing with "table starts do not fit the span" — which `harvest_verify` then 'repaired' with a needless `jr_isolate_all` that walked back into (a); the merge now seeds from the span start unconditionally, per the invariant the validator already asserts (every carve span begins with a table). NC over every other open table-bearing stub fleet-wide: 11 tables, 10 unchanged, 1 changed — a FIFTH latent victim (`ov_SC06_022:func_80185B80`). All five banked byte-identical. | | | `tools/dedup_propagate.py` — `_split_masked` memo | **(P31 S75)** `find_site` re-ran `cdecl._mask` (4 regex passes, one `re.S`) + two `splitlines()` over the ENTIRE concatenated source on EVERY call, though the mask is a pure function of the text and the caller loops over every function in the binary. Measured on `ov_SC01_005` (2.50 MB, 2,503 fns): 6.5 + 38.9 + 4.6 = **54 ms per call before any searching**. Memoized via `lru_cache(maxsize=8)` — callers already hold one text object per binary and CPython caches a str's hash, so a repeat lookup is a pointer compare. **2x on that loop (58.3 -> 33.0 ms/call), NC identical results on 120 addresses.** Honest scope: that loop is only ~2.4 min of a 30-min run; the profiler puts 43% of `--check-only` in `family_remap._alias_decl_for` (107 s / 1,312 calls), which is the real target and is NOT fixed here. | | | `tools/main_diff_locate.py` — `classify()` | **(P31 S75, cookbook §447)** The `TABLE REJECT` class was **unreachable for main** and demanded purity. (a) It summed bytes whose object string contains `(.rodata)`, but main's `section_order` is `[.rodata, .text, .data, .bss]` — its rodata sits BELOW `.text` and its jump tables live in `.data` objects, so the test could never fire on the one binary with the most jump-table functions left. Now matches `(.data)` OR `(.rodata)`. (b) It required `ro == outside`, so a few bytes of perturbed code dropped the verdict through to `PLUMBING REJECT` and its §376 declaration advice. Now **dominance-based** (≥60%), reporting the split and naming which part is the table problem and which the declaration problem. Measured on `SaveLoadRoutine` (1,165 ins, the §434 wall): body BYTE-IDENTICAL, 3,787 of 3,989 differing bytes (94.9%) in `.data` jump tables, 202 (5.1%) in `.text`, built image 4 bytes SHORT — verdict moved `PLUMBING REJECT` → `TABLE REJECT (MIXED)`. The §376 chain had been run on it twice and fixed nothing, because it addresses the 5%. NC over all five pre-existing verdict shapes: 5 of 6 unchanged. | +| | **`tools/asm_in_c.py`** (NEW) | **(P31 S75, cookbook §448)** Finds every function that is **assembly posing as C** — a §265 file-scope `__asm__` body (class A) or a C function whose body is only asm statements (class B) — while correctly EXCLUDING the §3a cross-jump barrier, which is what `__asm__` means in 3,182 of the 4,224 sources. Measured: **199 functions, 154 of them GAME CODE, 171 in main**, largest `SaveLoadRoutine` (1,165 ins). These were in NO `progress.py` bucket, so main's REAL% was overstated (45.88% → **42.15%** once counted; `progress.py` gained a `VERBATIM __asm__ bodies` line that counts them byte-identical but NEVER as REAL). Design is the point: **three independent detectors that must agree**, disagreement reported as a defect (it caught `jtbl_*` being claimed as functions); **SDK-ness derived from the 14 shipped PsyQ archives via `nm`** (2,227 symbols), not a hand list (which had mis-classified `VectorNormalSS`/`SquareRoot12`/`OuterProduct12` as game code); coverage asserted; and **`--selftest`** with a known-true case of EVERY spelling — hand counts went 116→112→108→178→199 because the sources use both `".ent\tNAME\n"` and `".ent NAME\n"`, and a bare `".ent\t"` fragment yields a phantom function called `t`. Run `--selftest` before believing the number. | | | `tools/jr_isolate_all.py` — boundary derivation | **(P31 S74, cookbook §441)** `_region_emit_start()`: the yaml offset for a region is derived from the region's **CONTENT** — min of item addresses and of every `.globl`/`.ent` its text names that resolves inside the object — and taken as `min(cut, emit)`, so a boundary can only move DOWN. Reason: **a §265 verbatim `__asm__` body is not one of `parse_overlay_c`'s four addressed-anchor forms, so it attaches to the NEXT anchor as PREAMBLE — and preamble is assumed byte-neutral when it emits bytes.** A cut at `func_800D0268` would have moved 0x168 bytes of three other functions into the new object while the yaml claimed the region started higher. Where no verbatim asm is in play it equals the cut, so every existing isolate is unchanged. Also: an item-less CLOSING region used to emit a duplicate `- [off, c, …]` line (the empty-region skip covered only region 0, and `_partition`'s empty `footer` made the closing region look non-empty). | | | `tools/jtbl_rodata_pads.py --derive` | **(Phase 31 S62 T3a, cookbook §303)** Module path of the §8e pads filter: the Makefile runs `--derive $(BINARY) --tu ` for every `md_*` object **and for `main` (P31 S72)** — jump-table pads derived at build time from the retail island + the emission stream (trailing pads `0t1`, table-aware, const data passes through). No stored spec; an anchor miss fails the build with the offset. **S72:** `--derive` now serves main too — `_file0_vram` returns the code segment's `vram - start` (the PS-X EXE's 0x800 header), which makes both `raw[a - vram]` and `vram + ` correct for the EXE and leaves flat overlays byte-identical; `_splat_yaml` resolves main to `splat.us.exe.yaml`. | | | `config/wave_exclude.txt` | **(P31 S72)** THE canonical wave exclude list — **tracked**, and **regenerated, never hand-edited**: `tools/exclude_audit.py config/wave_exclude.txt --write `. Consumed as `draw_waves --exclude-file config/wave_exclude.txt`, which AUDITS it as a PREREQUISITE and refuses to draw on a stale one (`--exclude-stale-ok` overrides, loudly). Two classes: **CARVE-BLOCKED** (derived from `split_indicator`; disappears when the subseg is split — **EMPTY since P31 S74**, all four overlays split) and **WALL** (curated, cannot be re-derived — the `# WALL:` annotation is a PIN that survives regeneration, and its note is the refutation list to beat before reopening the entry). It replaces the nine `.run/S*_exclude.txt` snapshots and seven walls ledgers, none of which was authoritative; measured on its predecessor, 88 of 107 entries were stale one day after it was written, 46 of them open drawable work totalling 12,750 instructions. | diff --git a/docs/cookbook-index.md b/docs/cookbook-index.md index bdf3b560f..74c39a20f 100644 --- a/docs/cookbook-index.md +++ b/docs/cookbook-index.md @@ -2,7 +2,7 @@ > **Generated by `tools/cookbook_index.py` — do not hand-edit** (R33). Regenerate after adding a cookbook section. > -> `docs/matching-cookbook.md` is ~716 KB / 1116 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses. +> `docs/matching-cookbook.md` is ~716 KB / 1117 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses. **How to use:** name what you SEE in the diff (a stolen delay slot, an extra `la`, a swapped register pair, a `conflicting types` error), find that symptom below, read those sections first. If nothing fits, THEN grind — and add a section when you win. @@ -1385,7 +1385,7 @@ - **§430** — ★★★ — A GOTO INTO A LOOP IS FINE; HAND-HOIST THE CONSTANTS IT COSTS YOU (P31 S73 — **this section previously said the OPPOSITE and was wrong; the refutation is kept below**) L34073 - **§439** — ★★ — LEVER SET FROM THE S74 WAVE (each entry is one measured crack, not a hypothesis) L34555 -### (unbucketed — title matched no symptom vocabulary) (331) +### (unbucketed — title matched no symptom vocabulary) (332) - **§3-How** — to use this L30 - **§1** — Idiom catalog (asm pattern → C that produces it) L39 @@ -1718,6 +1718,7 @@ - **§441** — ★★ — THREE MORE INSTRUMENT DEFECTS FROM THE SAME SESSION, ALL OF WHICH BLAME THE SUBJECT (P31 S74) L34617 - **§443** — ★★ — A DERIVED DEPENDENCY MUST BE PROVISIONED BY *EVERY* PROVISIONER, AND WE HAVE TWO (P31 S69 → S74, the same defect twice) L34702 - **§445** — ★★ — `make clean BINARY=` IS FLEET-WIDE: THE VARIABLE IS ACCEPTED AND IGNORED (P31 S75) L34778 +- **§448** — ★★★ — ASSEMBLY POSING AS C: 154 GAME FUNCTIONS THE REPORTS COUNTED AS DONE (P31 S75) L34898 ## All sections, in order @@ -2838,6 +2839,7 @@ - **§445** — ★★ — `make clean BINARY=` IS FLEET-WIDE: THE VARIABLE IS ACCEPTED AND IGNORED (P31 S75) L34778 - **§446** — ★★★ — "RELOC-ONLY REMAP GATED DIFF" IS A CARVE VERDICT, NOT A CODEGEN VERDICT, UNTIL YOU DIFF THE `.text` (P31 S75; 4 siblings + 1 latent, ~1,300 ins) L34807 - **§447** — ★★★ — THE BIGGEST FUNCTION LEFT IS A CARVE, AND THE VERDICT TOOL SAID "DECLARATIONS" (P31 S75; SaveLoadRoutine, 1,165 ins) L34854 +- **§448** — ★★★ — ASSEMBLY POSING AS C: 154 GAME FUNCTIONS THE REPORTS COUNTED AS DONE (P31 S75) L34898 --- @@ -3966,3 +3968,4 @@ Notes routinely quote that as a section id. This table resolves it. Grep bait: ` | L34778 | §445 | ★★ — `make clean BINARY=` IS FLEET-WIDE: THE VARIABLE IS ACCEPTED AND IGNORED (P31 S75) | | L34807 | §446 | ★★★ — "RELOC-ONLY REMAP GATED DIFF" IS A CARVE VERDICT, NOT A CODEGEN VERDICT, UNTIL YOU D | | L34854 | §447 | ★★★ — THE BIGGEST FUNCTION LEFT IS A CARVE, AND THE VERDICT TOOL SAID "DECLARATIONS" (P31 | +| L34898 | §448 | ★★★ — ASSEMBLY POSING AS C: 154 GAME FUNCTIONS THE REPORTS COUNTED AS DONE (P31 S75) | diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md index 85ce9df6f..44cff2c80 100644 --- a/docs/matching-cookbook.md +++ b/docs/matching-cookbook.md @@ -34894,3 +34894,46 @@ class that does not exist: it converts "I don't know" into confident, specific, verdict tool names a subsystem, check that the named subsystem owns the MAJORITY OF THE BYTES before you act on it. Here 95% of the evidence pointed one way and the recommendation pointed the other, and nothing in the pipeline compared the two. + +## §448 ★★★ — ASSEMBLY POSING AS C: 154 GAME FUNCTIONS THE REPORTS COUNTED AS DONE (P31 S75) + +A `.c` file in `src/` looks decompiled. **199 functions in this tree are not**: they are the target +assembly pasted into a C string literal (§265), byte-identical BY CONSTRUCTION and completely +unexplained. 45 are PsyQ/CRT routines where that is defensible; **154 are game code**, 171 of the 199 +in `main` alone, the largest being `SaveLoadRoutine` at 1,165 instructions. + +They were invisible because `progress.py`'s `classify()` matched `INCLUDE_ASM`, `INCLUDE_RODATA` and +C definitions — and a file-scope `__asm__` block is none of those, so each one landed in NO bucket: +either swallowed by a surrounding construct or surfacing as the single `UNPLACED (parse hole)` line. +Main's headline moved **45.88% → 42.15%** once they were counted; nothing regressed, the denominator +had simply been missing 173 functions that are real work. + +**THE COUNTING LESSON, WHICH IS THE REUSABLE PART.** Counting them by hand went +**116 → 112 → 108 → 178 → 199** across five attempts in one session, every intermediate number +reported with confidence. Every error was the same shape — a pattern narrower than the claim it +supported: + +* the sources use **BOTH** `".ent\tNAME\n"` (escaped tab) **and** `".ent NAME\n"` (literal space); + a pattern anchored on either one silently drops every instance of the other; +* a bare fragment `".ent\t"` also occurs, and an optional-`\t` pattern captured the literal name + **`t`** from it, six times, which is the only reason the error was noticed at all; +* `__asm__` appears in **3,182 files**, almost all of it the §3a zero-byte cross-jump barrier, so + counting files — or counting `__asm__` — measures nothing; +* a `.globl NAME` + `NAME:` pair proves the symbol is **EXPORTED, not CODE**: the first real run + reported `jtbl_80072ED4/EEC/F0C/F24` as four "functions", when they are jump tables sitting in the + same block; +* a hand-written SDK name list reported 170 game functions because it did not know `VectorNormalSS`, + `SquareRoot12` and `OuterProduct12` are libgte — an incomplete list inflates exactly the number + that matters. + +`tools/asm_in_c.py` is the answer to all five, and its design is the lesson: **three independent +detectors that must AGREE, with disagreement reported as a defect** (R34 — that is what caught the +jump tables); **SDK-ness derived from the 14 shipped PsyQ archives via `nm`** (2,227 symbols) rather +than a list (R33); **coverage asserted**, so a definition-shaped block no detector claims fails loudly +(R32/R43); and a **`--selftest` carrying a known-true case of every spelling plus the phantom `t` and +the jump-table regression**, so the next spelling change fails loudly instead of quietly returning a +smaller number. + +**The law: when a count comes from a text pattern, the pattern has a denominator too.** Validate it +against one known-true case of every FORM the corpus contains before quoting the number — and if you +cannot enumerate the forms, you do not yet know what you are counting. diff --git a/docs/progress.fleet.md b/docs/progress.fleet.md index e6370715f..0df226bde 100644 --- a/docs/progress.fleet.md +++ b/docs/progress.fleet.md @@ -4,24 +4,24 @@ # cross-binary collapsible-byte leverage: docs/duplicates.cross.md. # THREE progress metrics (all matter — see the labels): -FLEET fn-count byte-ident: 362891 / 362959 = 99.98% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay) -FLEET instr-weighted : 13484569 / 13523865 = 99.7% (shipped .text across main + resident + 211 overlays; the decomp.dev-DISPLAY number) -FLEET distinct-code(uniq): 5813098 / 5851972 = 99.3% (90902/90929 unique fns; the DISTINCT-RE number) -MAIN game-code weighted : 44903 / 79510 = 56.5% (INCLUDED in the fleet numbers above since 2026-07-22 — roadmap §1 metrics contract; LINKED-excluding Ghidra sig dated 2026-08-05; caveat is R34: no independent second oracle for a PS-X EXE, NOT drift) +FLEET fn-count byte-ident: 363002 / 363068 = 99.98% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay) +FLEET instr-weighted : 13484747 / 13523865 = 99.7% (shipped .text across main + resident + 211 overlays; the decomp.dev-DISPLAY number) +FLEET distinct-code(uniq): 5813276 / 5851972 = 99.3% (90902/90929 unique fns; the DISTINCT-RE number) +MAIN game-code weighted : 45081 / 79510 = 56.7% (INCLUDED in the fleet numbers above since 2026-07-22 — roadmap §1 metrics contract; LINKED-excluding Ghidra sig dated 2026-08-05; caveat is R34: no independent second oracle for a PS-X EXE, NOT drift) (fleet EXCLUDING main, for continuity with pre-2026-07-22 readings: 13439666 / 13444355 = 100.0%) -FLEET REAL substantive : 360721 (of which dedup-shared 255632 via 2220 groups / 255708 instances) +FLEET REAL substantive : 360722 (of which dedup-shared 255632 via 2220 groups / 255708 instances) FLEET LINKED PsyQ objs : 959 FLEET NON_MATCHING : 0 (0 in any default build — G4) -FLEET INCLUDE_ASM stubs : 68 -FLEET matchable : 362959 +FLEET INCLUDE_ASM stubs : 66 +FLEET matchable : 363068 | binary | REAL | shared | LINKED | byte-ident | matchable | byte-ident % | |---|---:|---:|---:|---:|---:|---:| -| main | 880 | 2 | 959 | 1882 | 1918 | 98.1% | +| main | 881 | 2 | 959 | 1991 | 2025 | 98.3% | | resident | 141 | 0 | 0 | 143 | 145 | 98.6% | | md_MAIN_001 | 11 | 0 | 0 | 11 | 11 | 100.0% | -| md_MAIN_003 | 46 | 0 | 0 | 46 | 47 | 97.9% | +| md_MAIN_003 | 46 | 0 | 0 | 47 | 48 | 97.9% | | md_MAIN_008 | 6 | 0 | 0 | 6 | 6 | 100.0% | | md_MAIN_011 | 20 | 0 | 0 | 21 | 21 | 100.0% | | md_MAIN_013 | 16 | 0 | 0 | 16 | 16 | 100.0% | @@ -193,7 +193,7 @@ FLEET matchable : 362959 | ov_SC05_002 | 2439 | 1811 | 0 | 2442 | 2442 | 100.0% | | ov_SC05_003 | 2479 | 1811 | 0 | 2480 | 2481 | 100.0% | | ov_SC05_004 | 2462 | 1811 | 0 | 2464 | 2464 | 100.0% | -| ov_SC05_005 | 2489 | 1825 | 0 | 2490 | 2490 | 100.0% | +| ov_SC05_005 | 2489 | 1825 | 0 | 2491 | 2491 | 100.0% | | ov_SC05_006 | 2430 | 1813 | 0 | 2430 | 2430 | 100.0% | | ov_SC05_007 | 2477 | 1812 | 0 | 2482 | 2482 | 100.0% | | ov_SC05_008 | 2541 | 1812 | 0 | 2543 | 2543 | 100.0% | diff --git a/docs/progress.md b/docs/progress.md index fa895b6ff..85cd34b5b 100644 --- a/docs/progress.md +++ b/docs/progress.md @@ -1,19 +1,20 @@ # BFM matching progress (generated by tools/progress.py — authoritative) -REAL substantive matches : 880 <- the Gen1-exit >=25 bar counts THIS +REAL substantive matches : 881 <- the Gen1-exit >=25 bar counts THIS (of which dedup-shared : 2 one body -> N sites, config/dedup.us.yaml) LINKED real PsyQ objects : 959 <- byte-identical via linked SDK objects +VERBATIM __asm__ bodies : 173 <- §265: BYTES, NOT A DECOMPILE (byte-identical by construction, unexplained; NOT counted in REAL) NON_MATCHING (near-miss) : 0 splat-auto empty no-ops : 43 -INCLUDE_ASM stubs : 36 +INCLUDE_ASM stubs : 34 data blobs (excluded) : 1 ---------------------------------------- -matchable functions : 1918 -REAL / matchable : 880 / 1918 = 45.88% -byte-identical/ matchable: 1882 / 1918 = 98.12% (REAL+LINKED+empties) +matchable functions : 2090 +REAL / matchable : 881 / 2090 = 42.15% +byte-identical/ matchable: 2056 / 2090 = 98.37% (REAL+LINKED+empties+VERBATIM) LINKED subsegs: apicard1 apicard2 apicard3 apicard4 libc2_1 libc2_2 libcd1 libcd2 libetc libgpu libgs1 libgs2 libgs3 libgs4 libgs5 libgs6 libgte1 libgte10 libgte11 libgte12 libgte13 libgte14 libgte15 libgte16 libgte17 libgte18 libgte19 libgte2 libgte20 libgte21 libgte22 libgte3 libgte4 libgte5 libgte6 libgte7 libgte8 libgte9 libmcrd1 libmcrd2 snd1 snd2 snd3 snd4 snd5 snd6 snd7 snd8 snd9 (959 fns) -REAL matches: AverageZ3 CdQueueBusy CdReadRequest CdReadSectorReadyCB CdReadStateMachine ClearImage2 ClearOTag DebugMenuHandler DpqColor3 DpqColorLight DrawOTagEnv DrawPrim DsDataCallback DsReadyCallback DsSyncCallback GameModeDispatch GetDispEnv GetDrawEnv GetGraphDebug GetGraphType GetODE GetRCnt GsInitGraph2_body GsTMDfastF3GL GsTMDfastF3GNL GsTMDfastF4GL GsTMDfastF4GNL GsTMDfastG3GL GsTMDfastG3GNL GsTMDfastG4GL GsTMDfastG4GNL Intpl LightColor LoaderInitFileTable LoaderResetReadState LzssDecodeSector MoveImage ResetRCnt ResourceGetCdLoc ResourceLoadStateMachine SYS_OBJ_191C SYS_OBJ_19D8 SYS_OBJ_1AA4 SYS_OBJ_1AF0 SYS_OBJ_1B78 SetDQA SetDQB SetData32 SetDrawArea SetDrawOffset SetGraphQueue SetIR0 SetIR123 SetMAC123 SetPriority SetRCnt SetRGBfifo SetRii SetSXSYfifo SetSZfifo4 SetTexWindow SetVertex0 SetVertex1 SetVertex2 SetVertexTri SpuWrite Square0 Square12 SsGetMute SsUtReverbOff StartRCnt StoreImage StreamLoadStateMachine VM_NO1_OBJ_4A4 VM_NOWON_OBJ_44C _SsSndPlay _addque _cwb _getctl _status aF800301A4 func_8001096C func_8001099C func_80010A08 func_80010A98 func_80010AE0 func_80010B10 func_80010BB4 func_80010C7C func_80010CEC func_80010D60 func_80010DA0 func_80010DE0 func_80010E14 func_80010E48 func_80010E7C func_80010ED4 func_80010F80 func_800110CC func_800111BC func_80011220 func_8001125C func_800112C8 func_80011320 func_80011350 func_80011680 func_800116E0 func_80011778 func_80011818 func_800118AC func_80011928 func_80011998 func_800119F0 func_80011A3C func_80011ADC func_80011B7C func_80011C10 func_80011C8C func_80011CFC func_80011D54 func_80011DA0 func_80011DCC func_80011DF4 func_80011E24 func_80011E84 func_80011EB4 func_800120DC func_8001212C func_800123F0 func_80012558 func_800126C4 func_8001282C func_800128B4 func_800128EC func_800129CC func_80012A60 func_80012AB0 func_80012ABC func_80012B04 func_80012B58 func_80012C6C func_80012CB8 func_80012D0C func_80012DBC func_80012E0C func_80012E6C func_80012F74 func_80012FC8 func_80013028 func_800130D0 func_8001311C func_80013200 func_80013228 func_80013294 func_800132BC func_80013328 func_80013350 func_800133BC func_800133E4 func_80013450 func_80013478 func_800134FC func_80013694 func_8001382C func_800139C8 func_80013B64 func_80013CFC func_80013E94 func_80013ED0 func_80013F3C func_80013F68 func_80013F98 func_80013FBC func_80013FE0 func_80014004 func_80014028 func_8001404C func_80014070 func_80014094 func_800140B8 func_80014128 func_80014148 func_80014168 func_800141AC func_800141F0 func_80014238 func_800142C8 func_80014338 func_80014390 func_800143AC func_80014444 func_800144D4 func_80014564 func_80014588 func_800145EC func_800146B0 func_80014774 func_800147B8 func_80014928 func_80014960 func_80014998 func_800149E0 func_80014B10 func_80014BFC func_80014C28 func_80014C54 func_80014CAC func_80014CF8 func_80014D30 func_80014D68 func_80014D94 func_80014DC0 func_80014DEC func_80014E24 func_80014E80 func_80014ED4 func_80015018 func_80015118 func_80015144 func_80015208 func_800152F4 func_80015310 func_8001534C func_800153A4 func_800153CC func_80015424 func_8001544C func_80015498 func_80015908 func_80015954 func_80015978 func_8001599C func_800159C0 func_800159E4 func_80015A08 func_80015A2C func_80015A50 func_80015A74 func_80015AD0 func_80015D4C func_80015F04 func_80016110 func_80016224 func_80016450 func_80016638 func_800166E8 func_80016714 func_800167B8 func_800167F0 func_800168B4 func_800168C4 func_80016940 func_80016978 func_80016A3C func_80016A5C func_80016A7C func_80016B60 func_80016C28 func_80016D78 func_80016EB0 func_80016ED4 func_80016EF8 func_80016F18 func_80017168 func_80017254 func_80017274 func_80017294 func_8001739C func_800173BC func_800173DC func_800174DC func_800174FC func_8001751C func_800176F0 func_80017714 func_80017738 func_80017758 func_80017778 func_800178C8 func_800178EC func_80017910 func_80017930 func_80017B98 func_80017D98 func_80017DC4 func_80017DF8 func_80017E30 func_80017E68 func_80017E8C func_80017F14 func_80018094 func_80018194 func_8001820C func_80018384 func_800183E0 func_80018450 func_800184F0 func_80018918 func_800189A8 func_80018A20 func_80018C64 func_80018CE8 func_80018E78 func_80018E9C func_80018F20 func_80018F88 func_80018FC8 func_80019018 func_80019028 func_8001903C func_80019064 func_800190AC func_80019198 func_800191A8 func_800191BC func_800191D4 func_8001923C func_8001931C func_80019378 func_80019388 func_80019398 func_800193A8 func_800193B8 func_80019930 func_80019A10 func_8001A0FC func_8001A114 func_8001A9D8 func_8001A9F8 func_8001AA78 func_8001AA88 func_8001AAA0 func_8001AAD0 func_8001ABBC func_8001ACF0 func_8001AE90 func_8001AF04 func_8001AF34 func_8001B0D4 func_8001B22C func_8001B23C func_8001B26C func_8001B324 func_8001B34C func_8001B374 func_8001B384 func_8001B394 func_8001B710 func_8001B7C4 func_8001B85C func_8001B86C func_8001BA84 func_8001BADC func_8001BB60 func_8001BBBC func_8001BDA0 func_8001BE20 func_8001BE30 func_8001BFA0 func_8001BFB0 func_8001BFD0 func_8001BFE8 func_8001BFF8 func_8001C00C func_8001C044 func_8001C0C8 func_8001C14C func_8001C1E4 func_8001C214 func_8001C2C4 func_8001C320 func_8001C448 func_8001C4A4 func_8001C558 func_8001C5B8 func_8001C6E4 func_8001C744 func_8001C7B0 func_8001C810 func_8001C8C4 func_8001C924 func_8001C97C func_8001C9D0 func_8001CA1C func_8001CA88 func_8001CB00 func_8001CB6C func_8001CBDC func_8001CC3C func_8001CCA0 func_8001CD04 func_8001CD50 func_8001CD9C func_8001CDE8 func_8001CE28 func_8001CE68 func_8001CEC0 func_8001CF00 func_8001CF30 func_8001CF48 func_8001CFB8 func_8001CFDC_impl func_8001D050 func_8001D074_impl func_8001D0E8 func_8001D0F4 func_8001D130 func_8001D150 func_8001D16C func_8001D1C4 func_8001D388 func_8001D3FC func_8001D70C func_8001D8C4 func_8001DA34 func_8001E094 func_8001E378 func_8001E668 func_8001E7E0 func_8001F730 func_8001F97C func_8001F9F8 func_8001FB8C func_80020248 func_80020598 func_80020A28 func_80020F34 func_80021008 func_80021050 func_8002109C func_80021120 func_80021284 func_80021D38 func_800221A8 func_80023138 func_800233CC func_800234E4 func_80023570 func_8002374C func_800241C0 func_800242D0 func_800243EC func_80024448 func_800249F0 func_80024BC0 func_80024DE8 func_80025000 func_8002528C func_80025504 func_80025818 func_80025A30 func_80025CBC func_80025EB8 func_80026128 func_800262D8 func_80026514 func_800268D0 func_80026D64 func_80027058 func_80027200 func_800273F4 func_800275BC func_800277DC func_800279AC func_80027BF0 func_80027C10 func_80027D20 func_80027F4C func_80028200 func_8002823C func_80028304 func_80028394 func_80028428 func_80028488 func_80028558 func_800285CC func_80028620 func_80028694 func_80028A48 func_80028C50 func_80028D58 func_80028D78 func_80028D9C func_80028DBC func_80028DE0 func_80028E00 func_80028E24 func_80028E44 func_80028E68 func_80028E88 func_80028EAC func_80028ECC func_80028EF0 func_80028F10 func_80028F34 func_80028F54 func_80028F78 func_80028F98 func_80028FBC func_80028FDC func_80029000 func_80029020 func_80029044 func_8002906C func_80029094 func_800290BC func_800290E0 func_80029104 func_80029124 func_80029178 func_800291A0 func_800291B4 func_800291C8 func_800291DC func_800291F0 func_80029204 func_80029218 func_80029240 func_80029254 func_80029264 func_80029274 func_8002931C func_80029344 func_8002941C func_80029444 func_80029504 func_80029514 func_80029524 func_8002953C func_8002954C func_8002955C func_8002957C func_8002958C func_8002959C func_800295D4 func_80029664 func_80029690 func_800296F8 func_80029774 func_800298BC func_8002992C func_80029A58 func_80029A94 func_80029AAC func_80029AF4 func_80029B4C func_80029BC8 func_80029C44 func_80029CD4 func_80029D3C func_80029DB4 func_80029E30 func_80029E94 func_80029EC0 func_80029ED4 func_80029FD4 func_80029FE4 func_8002A04C func_8002A088 func_8002A108 func_8002A1B4 func_8002A200 func_8002A234 func_8002A26C func_8002A27C func_8002A28C func_8002A2B0 func_8002A2D4 func_8002A354 func_8002A400 func_8002A44C func_8002A480 func_8002A4B8 func_8002A4C8 func_8002A4D8 func_8002A4FC func_8002A520 func_8002A544 func_8002A5C4 func_8002A670 func_8002A6BC func_8002A6F0 func_8002A728 func_8002A738 func_8002A748 func_8002A76C func_8002A790 func_8002A7B4 func_8002A834 func_8002A8E0 func_8002A92C func_8002A960 func_8002A998 func_8002A9A8 func_8002A9B8 func_8002A9DC func_8002AA00 func_8002AA3C func_8002AAB4 func_8002AB64 func_8002AC00 func_8002AE60 func_8002AED0 func_8002AEE4 func_8002AEF8 func_8002AF08 func_8002AF18 func_8002AF48 func_8002AF60 func_8002AF70 func_8002B00C func_8002B064 func_8002B08C func_8002C320 func_8002C3B0 func_8002C8BC func_8002C8F4 func_8002CC4C func_8002CCB4 func_8002CCD8 func_8002CDD8 func_8002CFE4 func_8002D034 func_8002D1F0 func_8002D240 func_8002D29C func_8002D320 func_8002D4B8 func_8002D4C8 func_8002D59C func_8002D678 func_8002D6D8 func_8002D7FC func_8002D80C func_8002D834 func_8002D844 func_8002D858 func_8002D8A8 func_8002D8D4 func_8002D904 func_8002DC68 func_8002DF80 func_8002E138 func_8002E5BC func_8002E5F8 func_8002E638 func_8002E700 func_8002E79C func_8002E818 func_8002E8DC func_8002E94C func_8002EA10 func_8002EAB0 func_8002EB10 func_8002EBAC func_8002EC10 func_8002ED90 func_8002EDE4 func_8002EE64 func_8002EE90 func_8002EEB8 func_8002EED8 func_8002EFD0 func_8002EFF8 func_8002F064 func_8002F0D0 func_8002F0F4 func_8002F12C func_8002F150 func_8002F1CC func_8002F248 func_8002F4E4 func_8002F5C8 func_8002F620 func_8002F648 func_8002F658 func_8002F67C func_8002F714 func_8002F80C func_8002FA3C func_8002FAE0 func_8002FB08 func_8002FC64 func_8002FD14 func_8002FDC8 func_80030470 func_800304C8 func_80030538 func_80030634 func_80030730 func_80030A14 func_80030CA4 func_80030D80 func_80030F80 func_800314DC func_800316F8 func_80031988 func_80031A98 func_80031B7C func_80031BE0 func_80031CC8 func_80031D70 func_80031DEC func_80031E94 func_80031F14 func_80031FC8 func_80032048 func_800322A8 func_800324A4 func_80032774 func_8003310C func_800331D4 func_8003324C func_80033324 func_80033398 func_8003350C func_800335B8 func_800336A8 func_8003388C func_800342E8 func_80034314 func_80034650 func_800346D0 func_800347C8 func_80034844 func_800348A8 func_8003491C func_80034A54 func_80034A9C func_80034AE0 func_80034B0C func_80034B3C func_80034C24 func_80034CF0 func_80034DFC func_8003500C func_800351E8 func_80035210 func_80035270 func_800359B0 func_80035C4C func_8003602C func_80036130 func_800361CC func_8003621C func_80036260 func_80036AF8 func_80036D24 func_80036D58 func_80036EB4 func_80036EE8 func_80036F18 func_80036F98 func_80036FB0 func_80037004 func_80037028 func_80037144 func_80037334 func_80037358 func_80037368 func_800373D0 func_800374CC func_8003750C func_8003775C func_800377D8 func_80037CC8 func_80037CD8 func_80037D74 func_80037D98 func_80037EA0 func_80037F3C func_80037FC4 func_8003819C func_800381E4 func_80038210 func_80038308 func_8003834C func_8003836C func_800383A4 func_800384A8 func_800385C0 func_80038638 func_80038668 func_800387C0 func_80038838 func_800388E8 func_80038908 func_80038958 func_80038A00 func_80038A58 func_80038FC4 func_80038FFC func_8003916C func_80039C5C func_80039C70 func_80039F14 func_80039F50 func_8003A098 func_8003A0D0 func_8003A0E4 func_8003A234 func_8003A3D8 func_8003A404 func_8003A424 func_8003D424 func_8003D630 func_8003DC90 func_8003DF8C func_8003FA54 func_8003FA64 func_80041354 func_800413B8 func_80041400 func_80041448 func_800525DC func_80052654 func_8005283C func_800538BC func_80053AD8 func_800594CC func_80059658 func_800596F4 func_80059888 func_800599B8 func_80059BFC func_80059CF4 func_80059D68 func_8005A600 func_8005AE80 func_8005B684 func_8005B710 func_8005B75C func_8005B7B0 func_8005BA90 func_8005C020 func_8005C29C func_8005CF08 func_8005CF18 func_8005D0D8 func_8005D0F8 func_8005D118 func_8005D138 func_8005D184 func_8005D244 func_8005D6A0 func_8005D6CC func_8005D980 func_8005DBD8 func_8005E0AC func_8005E188 func_8005E194 func_8005E1A4 func_8005E374 func_8005E480 func_8005E528 func_8005E804 func_8005E820 func_8005E980 func_8005E9D4 func_8005EA34 func_8005EA54 func_8005EA68 func_8005EA88 func_8005EAA8 func_8005F228 func_8005F384 func_8005F394 func_8005F6CC func_8005F704 func_8005F75C func_8005FB70 func_8005FBC8 func_80061FA8 func_80062394 func_800624C4 func_800624F4 func_800625A4 func_800625DC func_80062644 gteMIMefunc +REAL matches: AverageZ3 CdQueueBusy CdReadRequest CdReadSectorReadyCB CdReadStateMachine ClearImage2 ClearOTag DebugMenuHandler DpqColor3 DpqColorLight DrawOTagEnv DrawPrim DsDataCallback DsReadyCallback DsSyncCallback GameModeDispatch GetDispEnv GetDrawEnv GetGraphDebug GetGraphType GetODE GetRCnt GsInitGraph2_body GsTMDfastF3GL GsTMDfastF3GNL GsTMDfastF4GL GsTMDfastF4GNL GsTMDfastG3GL GsTMDfastG3GNL GsTMDfastG4GL GsTMDfastG4GNL Intpl LightColor LoaderInitFileTable LoaderResetReadState LzssDecodeSector MoveImage ResetRCnt ResourceGetCdLoc ResourceLoadStateMachine SYS_OBJ_191C SYS_OBJ_19D8 SYS_OBJ_1AA4 SYS_OBJ_1AF0 SYS_OBJ_1B78 SetDQA SetDQB SetData32 SetDrawArea SetDrawOffset SetGraphQueue SetIR0 SetIR123 SetMAC123 SetPriority SetRCnt SetRGBfifo SetRii SetSXSYfifo SetSZfifo4 SetTexWindow SetVertex0 SetVertex1 SetVertex2 SetVertexTri SpuWrite Square0 Square12 SsGetMute SsUtReverbOff StartRCnt StoreImage StreamLoadStateMachine VM_NO1_OBJ_4A4 VM_NOWON_OBJ_44C _SsSndPlay _addque _cwb _getctl _status aF800301A4 func_8001096C func_8001099C func_80010A08 func_80010A98 func_80010AE0 func_80010B10 func_80010BB4 func_80010C7C func_80010CEC func_80010D60 func_80010DA0 func_80010DE0 func_80010E14 func_80010E48 func_80010E7C func_80010ED4 func_80010F80 func_800110CC func_800111BC func_80011220 func_8001125C func_800112C8 func_80011320 func_80011350 func_80011680 func_800116E0 func_80011778 func_80011818 func_800118AC func_80011928 func_80011998 func_800119F0 func_80011A3C func_80011ADC func_80011B7C func_80011C10 func_80011C8C func_80011CFC func_80011D54 func_80011DA0 func_80011DCC func_80011DF4 func_80011E24 func_80011E84 func_80011EB4 func_800120DC func_8001212C func_800123F0 func_80012558 func_800126C4 func_8001282C func_800128B4 func_800128EC func_800129CC func_80012A60 func_80012AB0 func_80012ABC func_80012B04 func_80012B58 func_80012C6C func_80012CB8 func_80012D0C func_80012DBC func_80012E0C func_80012E6C func_80012F74 func_80012FC8 func_80013028 func_800130D0 func_8001311C func_80013200 func_80013228 func_80013294 func_800132BC func_80013328 func_80013350 func_800133BC func_800133E4 func_80013450 func_80013478 func_800134FC func_80013694 func_8001382C func_800139C8 func_80013B64 func_80013CFC func_80013E94 func_80013ED0 func_80013F3C func_80013F68 func_80013F98 func_80013FBC func_80013FE0 func_80014004 func_80014028 func_8001404C func_80014070 func_80014094 func_800140B8 func_80014128 func_80014148 func_80014168 func_800141AC func_800141F0 func_80014238 func_800142C8 func_80014338 func_80014390 func_800143AC func_80014444 func_800144D4 func_80014564 func_80014588 func_800145EC func_800146B0 func_80014774 func_800147B8 func_80014928 func_80014960 func_80014998 func_800149E0 func_80014B10 func_80014BFC func_80014C28 func_80014C54 func_80014CAC func_80014CF8 func_80014D30 func_80014D68 func_80014D94 func_80014DC0 func_80014DEC func_80014E24 func_80014E80 func_80014ED4 func_80015018 func_80015118 func_80015144 func_80015208 func_800152F4 func_80015310 func_8001534C func_800153A4 func_800153CC func_80015424 func_8001544C func_80015498 func_80015908 func_80015954 func_80015978 func_8001599C func_800159C0 func_800159E4 func_80015A08 func_80015A2C func_80015A50 func_80015A74 func_80015AD0 func_80015D4C func_80015F04 func_80016110 func_80016224 func_80016450 func_80016638 func_800166E8 func_80016714 func_800167B8 func_800167F0 func_800168B4 func_800168C4 func_80016940 func_80016978 func_80016A3C func_80016A5C func_80016A7C func_80016B60 func_80016C28 func_80016D78 func_80016EB0 func_80016ED4 func_80016EF8 func_80016F18 func_80017168 func_80017254 func_80017274 func_80017294 func_8001739C func_800173BC func_800173DC func_800174DC func_800174FC func_8001751C func_800176F0 func_80017714 func_80017738 func_80017758 func_80017778 func_800178C8 func_800178EC func_80017910 func_80017930 func_80017B98 func_80017D98 func_80017DC4 func_80017DF8 func_80017E30 func_80017E68 func_80017E8C func_80017F14 func_80018094 func_80018194 func_8001820C func_80018384 func_800183E0 func_80018450 func_800184F0 func_80018918 func_800189A8 func_80018A20 func_80018C64 func_80018CE8 func_80018E78 func_80018E9C func_80018F20 func_80018F88 func_80018FC8 func_80019018 func_80019028 func_8001903C func_80019064 func_800190AC func_80019198 func_800191A8 func_800191BC func_800191D4 func_8001923C func_8001931C func_80019378 func_80019388 func_80019398 func_800193A8 func_800193B8 func_80019930 func_80019A10 func_8001A0FC func_8001A114 func_8001A9D8 func_8001A9F8 func_8001AA78 func_8001AA88 func_8001AAA0 func_8001AAD0 func_8001ABBC func_8001ACF0 func_8001AE90 func_8001AF04 func_8001AF34 func_8001B0D4 func_8001B22C func_8001B23C func_8001B26C func_8001B324 func_8001B34C func_8001B374 func_8001B384 func_8001B394 func_8001B710 func_8001B7C4 func_8001B85C func_8001B86C func_8001BA84 func_8001BADC func_8001BB60 func_8001BBBC func_8001BDA0 func_8001BE20 func_8001BE30 func_8001BFA0 func_8001BFB0 func_8001BFD0 func_8001BFE8 func_8001BFF8 func_8001C00C func_8001C044 func_8001C0C8 func_8001C14C func_8001C1E4 func_8001C214 func_8001C2C4 func_8001C320 func_8001C448 func_8001C4A4 func_8001C558 func_8001C5B8 func_8001C6E4 func_8001C744 func_8001C7B0 func_8001C810 func_8001C8C4 func_8001C924 func_8001C97C func_8001C9D0 func_8001CA1C func_8001CA88 func_8001CB00 func_8001CB6C func_8001CBDC func_8001CC3C func_8001CCA0 func_8001CD04 func_8001CD50 func_8001CD9C func_8001CDE8 func_8001CE28 func_8001CE68 func_8001CEC0 func_8001CF00 func_8001CF30 func_8001CF48 func_8001CFB8 func_8001CFDC_impl func_8001D050 func_8001D074_impl func_8001D0E8 func_8001D0F4 func_8001D130 func_8001D150 func_8001D16C func_8001D1C4 func_8001D388 func_8001D3FC func_8001D70C func_8001D8C4 func_8001DA34 func_8001E094 func_8001E378 func_8001E668 func_8001E7E0 func_8001F730 func_8001F97C func_8001F9F8 func_8001FB8C func_80020248 func_80020598 func_80020A28 func_80020F34 func_80021008 func_80021050 func_8002109C func_80021120 func_80021284 func_80021D38 func_800221A8 func_80023138 func_800233CC func_800234E4 func_80023570 func_8002374C func_800241C0 func_800242D0 func_800243EC func_80024448 func_800249F0 func_80024BC0 func_80024DE8 func_80025000 func_8002528C func_80025504 func_80025818 func_80025A30 func_80025CBC func_80025EB8 func_80026128 func_800262D8 func_80026514 func_800268D0 func_80026D64 func_80027058 func_80027200 func_800273F4 func_800275BC func_800277DC func_800279AC func_80027BF0 func_80027C10 func_80027D20 func_80027F4C func_80028200 func_8002823C func_80028304 func_80028394 func_80028428 func_80028488 func_80028558 func_800285CC func_80028620 func_80028694 func_80028A48 func_80028C50 func_80028D58 func_80028D78 func_80028D9C func_80028DBC func_80028DE0 func_80028E00 func_80028E24 func_80028E44 func_80028E68 func_80028E88 func_80028EAC func_80028ECC func_80028EF0 func_80028F10 func_80028F34 func_80028F54 func_80028F78 func_80028F98 func_80028FBC func_80028FDC func_80029000 func_80029020 func_80029044 func_8002906C func_80029094 func_800290BC func_800290E0 func_80029104 func_80029124 func_80029178 func_800291A0 func_800291B4 func_800291C8 func_800291DC func_800291F0 func_80029204 func_80029218 func_80029240 func_80029254 func_80029264 func_80029274 func_8002931C func_80029344 func_8002941C func_80029444 func_80029504 func_80029514 func_80029524 func_8002953C func_8002954C func_8002955C func_8002957C func_8002958C func_8002959C func_800295D4 func_80029664 func_80029690 func_800296F8 func_80029774 func_800298BC func_8002992C func_80029A58 func_80029A94 func_80029AAC func_80029AF4 func_80029B4C func_80029BC8 func_80029C44 func_80029CD4 func_80029D3C func_80029DB4 func_80029E30 func_80029E94 func_80029EC0 func_80029ED4 func_80029FD4 func_80029FE4 func_8002A04C func_8002A088 func_8002A108 func_8002A1B4 func_8002A200 func_8002A234 func_8002A26C func_8002A27C func_8002A28C func_8002A2B0 func_8002A2D4 func_8002A354 func_8002A400 func_8002A44C func_8002A480 func_8002A4B8 func_8002A4C8 func_8002A4D8 func_8002A4FC func_8002A520 func_8002A544 func_8002A5C4 func_8002A670 func_8002A6BC func_8002A6F0 func_8002A728 func_8002A738 func_8002A748 func_8002A76C func_8002A790 func_8002A7B4 func_8002A834 func_8002A8E0 func_8002A92C func_8002A960 func_8002A998 func_8002A9A8 func_8002A9B8 func_8002A9DC func_8002AA00 func_8002AA3C func_8002AAB4 func_8002AB64 func_8002AC00 func_8002AE60 func_8002AED0 func_8002AEE4 func_8002AEF8 func_8002AF08 func_8002AF18 func_8002AF48 func_8002AF60 func_8002AF70 func_8002B00C func_8002B064 func_8002B08C func_8002C320 func_8002C3B0 func_8002C8BC func_8002C8F4 func_8002CC4C func_8002CCB4 func_8002CCD8 func_8002CDD8 func_8002CFE4 func_8002D034 func_8002D1F0 func_8002D240 func_8002D29C func_8002D320 func_8002D4B8 func_8002D4C8 func_8002D59C func_8002D678 func_8002D6D8 func_8002D7FC func_8002D80C func_8002D834 func_8002D844 func_8002D858 func_8002D8A8 func_8002D8D4 func_8002D904 func_8002DC68 func_8002DF80 func_8002E138 func_8002E5BC func_8002E5F8 func_8002E638 func_8002E700 func_8002E79C func_8002E818 func_8002E8DC func_8002E94C func_8002EA10 func_8002EAB0 func_8002EB10 func_8002EBAC func_8002EC10 func_8002ED90 func_8002EDE4 func_8002EE64 func_8002EE90 func_8002EEB8 func_8002EED8 func_8002EFD0 func_8002EFF8 func_8002F064 func_8002F0D0 func_8002F0F4 func_8002F12C func_8002F150 func_8002F1CC func_8002F248 func_8002F4E4 func_8002F5C8 func_8002F620 func_8002F648 func_8002F658 func_8002F67C func_8002F714 func_8002F80C func_8002FA3C func_8002FAE0 func_8002FB08 func_8002FC64 func_8002FD14 func_8002FDC8 func_80030470 func_800304C8 func_80030538 func_80030634 func_80030730 func_80030A14 func_80030CA4 func_80030D80 func_80030F80 func_800314DC func_800316F8 func_80031988 func_80031A98 func_80031B7C func_80031BE0 func_80031CC8 func_80031D70 func_80031DEC func_80031E94 func_80031F14 func_80031FC8 func_80032048 func_800322A8 func_800324A4 func_80032774 func_8003310C func_800331D4 func_8003324C func_80033324 func_80033398 func_8003350C func_800335B8 func_800336A8 func_8003388C func_800342E8 func_80034314 func_80034650 func_800346D0 func_800347C8 func_80034844 func_800348A8 func_8003491C func_80034A54 func_80034A9C func_80034AE0 func_80034B0C func_80034B3C func_80034C24 func_80034CF0 func_80034DFC func_8003500C func_800351E8 func_80035210 func_80035270 func_800359B0 func_80035C4C func_8003602C func_80036130 func_800361CC func_8003621C func_80036260 func_80036AF8 func_80036D24 func_80036D58 func_80036EB4 func_80036EE8 func_80036F18 func_80036F98 func_80036FB0 func_80037004 func_80037028 func_80037144 func_80037334 func_80037358 func_80037368 func_800373D0 func_800374CC func_8003750C func_8003775C func_800377D8 func_80037CC8 func_80037CD8 func_80037D74 func_80037D98 func_80037EA0 func_80037F3C func_80037FC4 func_8003819C func_800381E4 func_80038210 func_80038308 func_8003834C func_8003836C func_800383A4 func_800384A8 func_800385C0 func_80038638 func_80038668 func_800387C0 func_80038838 func_800388E8 func_80038908 func_80038958 func_80038A00 func_80038A58 func_80038FC4 func_80038FFC func_8003916C func_80039C5C func_80039C70 func_80039F14 func_80039F50 func_8003A098 func_8003A0D0 func_8003A0E4 func_8003A234 func_8003A3D8 func_8003A404 func_8003A424 func_8003D424 func_8003D630 func_8003DC90 func_8003DF8C func_8003FA54 func_8003FA64 func_80041354 func_800413B8 func_80041400 func_80041448 func_800525DC func_80052654 func_8005283C func_800538BC func_80053AD8 func_800594CC func_80059658 func_800596F4 func_80059888 func_800599B8 func_80059BFC func_80059CF4 func_80059D68 func_8005A600 func_8005AE80 func_8005B684 func_8005B710 func_8005B75C func_8005B7B0 func_8005BA90 func_8005C020 func_8005C29C func_8005CF08 func_8005CF18 func_8005D0D8 func_8005D0F8 func_8005D118 func_8005D138 func_8005D184 func_8005D244 func_8005D6A0 func_8005D6CC func_8005D980 func_8005DBD8 func_8005DCA0 func_8005E0AC func_8005E188 func_8005E194 func_8005E1A4 func_8005E374 func_8005E480 func_8005E528 func_8005E804 func_8005E820 func_8005E980 func_8005E9D4 func_8005EA34 func_8005EA54 func_8005EA68 func_8005EA88 func_8005EAA8 func_8005F228 func_8005F384 func_8005F394 func_8005F6CC func_8005F704 func_8005F75C func_8005FB70 func_8005FBC8 func_80061FA8 func_80062394 func_800624C4 func_800624F4 func_800625A4 func_800625DC func_80062644 gteMIMefunc NON_MATCHING: build SHA1: 143dbb89f34491258bbc27810d0a12ec8b43a8dd (byte-identical) diff --git a/tools/asm_in_c.py b/tools/asm_in_c.py new file mode 100644 index 000000000..67cf72c6b --- /dev/null +++ b/tools/asm_in_c.py @@ -0,0 +1,382 @@ +#!/usr/bin/env python3 +"""asm_in_c.py — find every function that is ASSEMBLY POSING AS C. + +WHY THIS EXISTS (P31 S75). A `.c` file in `src/` looks decompiled. Some of it is not: a §265 +verbatim body is the target assembly pasted into a C string literal, byte-identical BY CONSTRUCTION +and completely unexplained. Those functions are real work still to do, and until now nothing counted +them — `progress.py`'s `classify()` matched `INCLUDE_ASM`, `INCLUDE_RODATA` and C definitions, and a +file-scope `__asm__` block matched none of them, so it fell into the `UNPLACED (parse hole)` line or +was swallowed by a surrounding construct. + +THE MEASUREMENT THIS TOOL EXISTS TO GET RIGHT. Counting them by hand went 116 -> 112 -> 108 -> 178 +across four attempts in one session, every number confidently reported, because: + + * the sources use BOTH `".ent\\tNAME\\n"` (tab) and `".ent NAME\\n"` (space) — a pattern anchored + on one silently drops every instance of the other; + * a bare fragment `".ent\\t"` also occurs, and an optional-`\\t` pattern captured the literal name + `t` from it, six times; + * `__asm__` appears in 3,182 files, almost all of it the §3a zero-byte cross-jump barrier + (`__asm__ __volatile__("" ::: "memory")`) — counting files, or counting `__asm__`, is meaningless. + +So this tool does NOT trust one regex. It runs THREE independent detectors and makes them ARGUE +(R34): a disagreement is reported as a DEFECT, not silently resolved. It asserts its own coverage +(R32): every `__asm__` block is classified as function-defining or not, and an unclassifiable one +fails loudly. And `--selftest` checks it against known-true cases of EACH spelling before you are +allowed to believe its number. + +THREE CLASSES, and only the first two are "posing": + + A FILE-SCOPE VERBATIM — a file-scope `__asm__("...")` that DEFINES a function + (`.ent NAME` / `.globl NAME` + `NAME:` / `.type NAME, @function`). + No C at all. This is §265. + B ASM-BODIED C — a C function whose body contains nothing but asm statements. It has a + real signature and prototype, so it reads as decompiled in every report, + and it is not. + C LEGITIMATE INLINE — a C function with real C plus some inline asm (the §3a barrier, register + pins from §17). NOT posing, NOT reported. Excluding these correctly is + most of the tool's value: they outnumber the real hits by ~20x. + +Usage: + tools/asm_in_c.py # report, all binaries + tools/asm_in_c.py --binary main # one binary + tools/asm_in_c.py --json out.json # machine-readable + tools/asm_in_c.py --selftest # prove the detectors on known-true cases (DO THIS FIRST) + tools/asm_in_c.py --list # bare "binary function" lines, for piping +""" +import argparse +import collections +import json +import os +import re +import sys + +REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# PsyQ library subsegs: their stubs are byte-identical via LINKED SDK objects, not our source. +LINKED_SEGS = set( + 'apicard1 apicard2 apicard3 apicard4 libc2_1 libc2_2 libcd1 libcd2 libetc libgpu libgs1 libgs2 ' + 'libgs3 libgs4 libgs5 libgs6 libgte1 libgte10 libgte11 libgte12 libgte13 libgte14 libgte15 ' + 'libgte16 libgte17 libgte18 libgte19 libgte2 libgte20 libgte21 libgte22 libgte3 libgte4 libgte5 ' + 'libgte6 libgte7 libgte8 libgte9 libmcrd1 libmcrd2 snd1 snd2 snd3 snd4 snd5 snd6 snd7 snd8 ' + 'snd9'.split()) + +# SDK vs GAME CODE — DERIVED FROM THE ACTUAL PsyQ ARCHIVES, not a hand-written list (R33). +# +# The first cut used a hardcoded set of ~35 names and reported "170 game code". Wrong: the run +# immediately surfaced `VectorNormalSS`, `SquareRoot12`, `OuterProduct12`, `OuterProduct0` as +# "game code" when every one is a libgte routine that simply was not on my list. A hand list cannot +# be complete and its incompleteness silently INFLATES the number that matters most here (how much +# real decompilation work is hiding). We ship the SDK archives, so ask them. +# +# Falls back to a small literal set only if the archives or `nm` are unavailable, and SAYS SO in the +# report rather than pretending the classification is authoritative. +_PSYQ_DIR = os.path.join(REPO, 'tools/psyq/lib40_elf') +_NM = 'mipsel-linux-gnu-nm' +_FALLBACK = set('DisableEvent WaitEvent ReturnFromException SysDeqIntRP GsSortBg GsSortClear ' + 'MatrixNormal VectorNormal __main start _clr _drs _dws'.split()) + + +def sdk_names(): + """Every function symbol DEFINED by the shipped PsyQ archives -> (set, provenance string).""" + import subprocess + if not os.path.isdir(_PSYQ_DIR): + return _FALLBACK, 'FALLBACK literal list (no tools/psyq/lib40_elf) — classification is INDICATIVE' + archives = sorted(f for f in os.listdir(_PSYQ_DIR) if f.lower().endswith('.a')) + if not archives: + return _FALLBACK, 'FALLBACK literal list (no archives found) — classification is INDICATIVE' + names = set() + for a in archives: + try: + r = subprocess.run([_NM, '--defined-only', os.path.join(_PSYQ_DIR, a)], + capture_output=True, text=True, timeout=120) + except (OSError, subprocess.SubprocessError): + return _FALLBACK, f'FALLBACK literal list ({_NM} unavailable) — classification is INDICATIVE' + for ln in r.stdout.splitlines(): + parts = ln.split() + if len(parts) >= 3 and parts[1] in ('T', 't', 'W'): + names.add(parts[2]) + if not names: + return _FALLBACK, 'FALLBACK literal list (archives defined no T symbols) — INDICATIVE' + return names, f'derived from {len(archives)} PsyQ archive(s) in tools/psyq/lib40_elf ({len(names)} symbols)' + + +SDK_NAMES, SDK_PROVENANCE = sdk_names() + +# --- the three detectors ------------------------------------------------------------------------- +# Each takes ONE __asm__ block's text and returns the set of function names it believes are DEFINED. +# They are deliberately different shapes so that agreement is evidence and disagreement is a defect. +# +# NOTE the `(?:\\t|\s)+` in every one: the sources use BOTH the escaped tab and a literal space, and +# requiring the `\n` terminator is what stops a bare `".ent\t"` fragment from yielding the name `t`. +RE_ENT = re.compile(r'\.ent(?:\\t|[ \t])+(\w+)\\n') +RE_TYPE = re.compile(r'\.type(?:\\t|[ \t])+(\w+)\s*,\s*@function') +RE_GLOBL = re.compile(r'\.globl(?:\\t|[ \t])+(\w+)\\n') +RE_LABEL = re.compile(r'"(\w+):\\n"') + + +def detect_ent(txt): + """`.ent NAME` — the MIPS function-start directive. The most direct evidence.""" + return set(RE_ENT.findall(txt)) + + +def detect_type(txt): + """`.type NAME, @function` — the ELF symbol-type directive.""" + return set(RE_TYPE.findall(txt)) + + +# DATA-SHAPED NAMES. A `.globl NAME` + `NAME:` pair proves the symbol is EXPORTED, not that it is +# CODE — and jump tables and data blobs are exported too. Caught on the tool's first real run: +# `jtbl_80072ED4/EEC/F0C/F24` were reported as four "functions posing as C" when they are +# SaveLoadRoutine's jump tables sitting in the same §265 block. `.ent` and `.type @function` are +# code-specific and need no such filter; only the weakest detector does (R34 — the disagreement +# between detectors is what exposed this, which is the whole point of running three). +RE_DATA_NAME = re.compile(r'^(?:jtbl_|D_|_?LC?\d|\$L)') + + +def detect_globl_label(txt): + """`.globl NAME` AND a `NAME:` label — a definition without the directives. + + Exported-DATA names are excluded (see RE_DATA_NAME): this detector proves export, not code.""" + both = set(RE_GLOBL.findall(txt)) & set(RE_LABEL.findall(txt)) + return {n for n in both if not RE_DATA_NAME.match(n)} + + +DETECTORS = (('ent', detect_ent), ('type', detect_type), ('globl+label', detect_globl_label)) + +# A block with any of these and NO definition is inline asm inside a function, not a definition. +RE_BARRIER = re.compile(r'__asm__\s+__volatile__\s*\(\s*""') + + +def asm_blocks(text): + """[(start_line, end_line, block_text, is_file_scope)] for every __asm__/asm statement. + + Brace-depth tracking decides file scope, so a block INSIDE a C function (class B or C) is + distinguished from a file-scope one (class A) without guessing from indentation.""" + lines = text.split('\n') + out, depth, i, n = [], 0, 0, len(lines) + while i < n: + raw = lines[i] + code = re.sub(r'//.*$', '', raw) + if re.match(r'\s*(__asm__|asm)\b', code) or re.search(r'\b(__asm__|asm)\s*\(', code): + start, d2, opened = i, 0, False + while i < n: + c = re.sub(r'//.*$', '', lines[i]) + d2 += c.count('(') - c.count(')') + if '(' in c: + opened = True + i += 1 + if opened and d2 <= 0: + break + blk = '\n'.join(lines[start:i]) + out.append((start + 1, i, blk, depth == 0)) + # a statement inside a function still moves brace depth + depth += blk.count('{') - blk.count('}') + continue + depth += code.count('{') - code.count('}') + i += 1 + return out + + +C_SIG = re.compile(r'^[A-Za-z_][\w \*]*\b(\w+)\s*\([^;]*\)\s*\{?\s*$') + + +def c_functions(text): + """[(name, start, end, body)] for each C function DEFINITION, by brace matching.""" + lines = text.split('\n') + out, i, n = [], 0, len(lines) + while i < n: + m = C_SIG.match(re.sub(r'//.*$', '', lines[i]).rstrip()) + if m and '(' in lines[i] and not lines[i].lstrip().startswith(('return', 'if', 'while', 'for', 'switch')): + j, kind = i, None + while j < n: + c = re.sub(r'//.*$', '', lines[j]) + br, sm = c.find('{'), c.find(';') + if br != -1 and (sm == -1 or br < sm): + kind = 'def' + break + if sm != -1: + kind = 'decl' + break + j += 1 + if kind == 'def': + start, depth, opened, k = i, 0, False, j + while k < n: + c = re.sub(r'//.*$', '', lines[k]) + depth += c.count('{') - c.count('}') + if '{' in c: + opened = True + k += 1 + if opened and depth <= 0: + break + out.append((m.group(1), start + 1, k, '\n'.join(lines[start:k]))) + i = k + continue + i += 1 + return out + + +def strip_comments_and_strings(s): + """Blank comments and string literals so a body can be tested for REAL C content.""" + s = re.sub(r'/\*.*?\*/', ' ', s, flags=re.S) + s = re.sub(r'//[^\n]*', ' ', s) + s = re.sub(r'"(?:\\.|[^"\\])*"', '""', s) + return s + + +def scan_file(path, binary): + """-> (rows, defects). rows are the POSING functions; defects are coverage failures.""" + text = open(path, errors='ignore').read() + rows, defects = [], [] + if '__asm__' not in text and 'asm(' not in text: + return rows, defects + + blocks = asm_blocks(text) + cfuncs = c_functions(text) + + for (ln0, ln1, blk, file_scope) in blocks: + votes = {name: fn(blk) for name, fn in DETECTORS} + union = set().union(*votes.values()) + + if file_scope and union: + # CLASS A — a file-scope block that defines functions. Detectors must agree. + disagree = {n: sorted(v) for n, v in votes.items() if v and v != union} + for fname in sorted(union): + agreeing = [n for n, v in votes.items() if fname in v] + rows.append(dict(binary=binary, fn=fname, cls='A-FILE-SCOPE-VERBATIM', + path=os.path.relpath(path, REPO), line=ln0, + detectors=agreeing, lines=blk.count('\n') + 1)) + if disagree: + defects.append(f"{os.path.relpath(path, REPO)}:{ln0}: detectors DISAGREE on which " + f"functions this block defines: {votes} — resolve before trusting the count") + elif file_scope and not union: + # A file-scope asm block that defines nothing is data or a directive island. Only a + # defect if it looks like it MEANT to define something (R32: never skip silently). + if re.search(r'\.(ent|globl|type)\b', blk) or RE_LABEL.search(blk): + defects.append(f"{os.path.relpath(path, REPO)}:{ln0}: file-scope __asm__ carries " + f"definition-shaped directives but NO detector claimed a function — " + f"a spelling this tool does not know (R43). Inspect it.") + + # CLASS B — a C function whose body is ONLY asm statements. + for (fname, s0, s1, body) in cfuncs: + inner = body[body.find('{') + 1:body.rfind('}')] + has_asm = re.search(r'\b(__asm__|asm)\s*\(', inner) + if not has_asm: + continue + # remove every asm statement, then ask whether any C remains + rest = re.sub(r'\b(?:__asm__|asm)\b(?:\s+__volatile__)?\s*\([^;]*\)\s*;', ' ', + inner, flags=re.S) + rest = strip_comments_and_strings(rest) + # declarations alone are not "real C content" for this purpose; a return of a constant is. + meaningful = re.sub(r'\b(register|volatile|const|static|unsigned|signed|struct|union|' + r'char|short|int|long|float|double|void|[su](?:8|16|32|64)|f32)\b', ' ', rest) + meaningful = re.sub(r'[\s;{}()\[\],*]|(? " lines') + ap.add_argument('--selftest', action='store_true') + ap.add_argument('--strict', action='store_true', help='exit non-zero if any coverage defect') + a = ap.parse_args() + + if a.selftest: + sys.exit(selftest()) + + rows, defects, files = [], [], 0 + for path, b in sources(a.binary): + r, d = scan_file(path, b) + rows += r + defects += d + files += 1 + + if a.list: + for r in sorted(rows, key=lambda x: (x['binary'], x['fn'])): + print(f"{r['binary']} {r['fn']}") + sys.exit(0) + + by_cls = collections.Counter(r['cls'] for r in rows) + by_bin = collections.Counter(r['binary'] for r in rows) + sdk = [r for r in rows if r['fn'] in SDK_NAMES] + game = [r for r in rows if r['fn'] not in SDK_NAMES] + + print(f"ASSEMBLY POSING AS C — {len(rows)} function(s) across {len(by_bin)} binaries " + f"({files} sources scanned)\n") + for c, n in sorted(by_cls.items()): + print(f" {c:24s} {n:5d}") + print(f"\n PsyQ/CRT SDK routines : {len(sdk):5d} [{SDK_PROVENANCE}]") + print(f" GAME CODE — real decompilation work remaining : {len(game):5d}") + print(f"\n by binary:") + for b, n in by_bin.most_common(): + print(f" {b:16s} {n:5d}") + + # every row carries WHICH detectors claimed it — a row claimed by only one is weaker evidence + weak = [r for r in rows if len(r['detectors']) == 1 and r['cls'] == 'A-FILE-SCOPE-VERBATIM'] + if weak: + print(f"\n {len(weak)} row(s) claimed by a SINGLE detector (weaker evidence — spot-check these):") + for r in weak[:8]: + print(f" {r['binary']:14s} {r['fn']:24s} {r['detectors']} {r['path']}:{r['line']}") + + if defects: + print(f"\n!! {len(defects)} COVERAGE DEFECT(S) — a silent skip is a defect, not a no-op (R32):") + for d in defects[:12]: + print(f" {d}") + else: + print(f"\n coverage: every file-scope __asm__ block classified; 0 defects.") + + if a.json: + json.dump(rows, open(a.json, 'w'), indent=1) + print(f"\n-> {a.json}") + if a.strict and defects: + sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/tools/progress.py b/tools/progress.py index b3420546e..ac80187c6 100644 --- a/tools/progress.py +++ b/tools/progress.py @@ -588,7 +588,7 @@ SIG = re.compile(r'^\s*[A-Za-z_][\w \t\*]*\b([A-Za-z_]\w*)\s*\(') KR_PARAM = re.compile(r'^\s*[A-Za-z_][\w \t\*]*\s+\**\w+\s*(?:\[[^\]]*\])?\s*;\s*$') def classify(): - real, empty, nonmatching, stubs, blobs, linked = [], [], [], [], [], [] + real, empty, nonmatching, stubs, blobs, linked, verbatim = [], [], [], [], [], [], [] for src in SRCS: lines = src.read_text().split('\n') n = len(lines); i = 0 @@ -662,6 +662,42 @@ def classify(): if m: blobs.append(m.group(1)) i += 1; continue + # §265 VERBATIM-ASM BODY — bytes, NOT a decompile, and it needs its OWN bucket (P31 S75). + # + # A file-scope `__asm__("...")` block that DEFINES a function (`.ent NAME` / `.globl NAME` + # + `NAME:`) matches none of the patterns above, so it landed in NO bucket and surfaced as + # `UNPLACED (parse hole)` — which is R32 doing its job, but leaves the operator with an + # error instead of a number. Counting it REAL would be worse: it is the assembly pasted + # into a C string, byte-identical BY CONSTRUCTION and completely unexplained. + # + # Measured fleet-wide at introduction: 116 such bodies (114 main, 1 md_MAIN_003, + # 1 ov_SC05_005), the largest being SaveLoadRoutine at 1,165 instructions. Several main + # ones are PsyQ library routines where verbatim is defensible; the point of the bucket is + # that the GAP between "byte-identical binary" and "decompiled source" is now visible in + # the headline instead of hiding inside REAL or inside a parse hole. + if s.startswith('__asm__') and '(' in s: + blk, j, depth, opened = [], i, 0, False + while j < n: + c = lines[j] + blk.append(c) + depth += c.count('(') - c.count(')') + if '(' in c: opened = True + j += 1 + if opened and depth <= 0: break + txt = '\n'.join(blk) + # BOTH SPELLINGS, AND REQUIRE THE `\n` TERMINATOR (P31 S75, second cut). + # The sources use `".ent\tNAME\n"` AND `".ent NAME\n"`, and a bare fragment + # `".ent\t"` also occurs. A pattern with an OPTIONAL `\t` and no terminator matched + # the fragment and captured the literal name `t`, while a pattern requiring `\t` + # missed every space-spelled block: three of my own counts (116 / 112 / 108) were + # all wrong before this was validated against one known-true case of EACH spelling + # (SaveLoadRoutine = tab, func_80047D3C = space). True count: 178. + names = set(re.findall(r'\.ent(?:\\t|\s)+(\w+)\\n', txt)) + if not names: + g = set(re.findall(r'\.globl(?:\\t|\s)+(\w+)\\n', txt)) + names = g & set(re.findall(r'"(\w+):\\n"', txt)) + verbatim.extend(sorted(names)) + i = j; continue fm = SIG.match(lines[i]) if fm and '(' in lines[i]: # Definition ({ ... }) vs forward declaration (ends ;)? Scan to the first { or ;. @@ -702,13 +738,13 @@ def classify(): (real if strip_comments(body[a+1:b]).strip() else empty).append(fm.group(1)) continue i += 1 - return real, empty, nonmatching, stubs, blobs, linked + return real, empty, nonmatching, stubs, blobs, linked, verbatim def report(binary, audit=False, write=True): """Classify one binary; write docs/progress..md (if write) + print; return a stats dict (for --fleet aggregation). Single-binary output is byte-for-byte the legacy format.""" set_binary(binary) - real, empty, nonmatching, stubs, blobs, linked = classify() + real, empty, nonmatching, stubs, blobs, linked, verbatim = classify() # Code-shared functions (dedup.us.yaml) are REAL byte-identical matches whose macro-instantiated # form classify() doesn't parse — fold them in (dedup-safe) so the count stays honest (P9). # @@ -727,7 +763,8 @@ def report(binary, audit=False, write=True): # how the K&R blindness above hid ~190k banked instructions for 26 phases while the byte-gate stayed # green (the gate compiles; this tool only reads text — they share no code, so the gate can never # 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) + placed = (set(real) | set(empty) | set(nonmatching) | set(stubs) | set(blobs) + | set(linked) | set(verbatim)) unplaced = sorted(set(_S_INDEX) - placed) # OVER-coverage is the DUAL defect, and the assertion above is blind to it (Phase-28 T5). `placed` @@ -736,7 +773,8 @@ def report(binary, audit=False, write=True): # 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} + _buckets = {"real": real, "empty": empty, "nonmatching": nonmatching, "stubs": stubs, + "linked": linked, "verbatim": verbatim} _seen = {} for _name, _b in _buckets.items(): for _fn in _b: @@ -745,8 +783,10 @@ def report(binary, audit=False, write=True): 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 + matchable = len(set(real) | set(empty) | set(nonmatching) | set(stubs) | set(linked) + | set(verbatim)) # SET, not a len() sum + # VERBATIM counts as byte-identical (it is, by construction) but NEVER as REAL. + byteident = len(set(real) | set(linked) | set(empty) | set(verbatim)) out = [] out.append("# BFM matching progress (generated by tools/progress.py — authoritative)") @@ -755,6 +795,9 @@ def report(binary, audit=False, write=True): if shared: out.append(f" (of which dedup-shared : {len(shared):5d} one body -> N sites, config/dedup.us.yaml)") out.append(f"LINKED real PsyQ objects : {len(linked):5d} <- byte-identical via linked SDK objects") + if verbatim: + out.append(f"VERBATIM __asm__ bodies : {len(verbatim):5d} <- §265: BYTES, NOT A DECOMPILE " + f"(byte-identical by construction, unexplained; NOT counted in REAL)") out.append(f"NON_MATCHING (near-miss) : {len(nonmatching):5d}") out.append(f"splat-auto empty no-ops : {len(empty):5d}") out.append(f"INCLUDE_ASM stubs : {len(stubs):5d}") @@ -767,7 +810,7 @@ def report(binary, audit=False, write=True): out.append("-" * 40) out.append(f"matchable functions : {matchable:5d}") out.append(f"REAL / matchable : {len(real)} / {matchable} = {100*len(real)/matchable:.2f}%") - out.append(f"byte-identical/ matchable: {byteident} / {matchable} = {100*byteident/matchable:.2f}% (REAL+LINKED+empties)") + out.append(f"byte-identical/ matchable: {byteident} / {matchable} = {100*byteident/matchable:.2f}% (REAL+LINKED+empties+VERBATIM)") out.append("") out.append("LINKED subsegs: " + " ".join(sorted(LINKED_SEGS)) + f" ({len(linked)} fns)") out.append("REAL matches: " + " ".join(sorted(real)))