From e69c0d7aa8520d399fb062d081abfde14def9bbf Mon Sep 17 00:00:00 2001 From: Joe DiPrima Date: Thu, 6 Aug 2026 10:34:02 -0500 Subject: [PATCH] #60 GAP CENSUS: the export dark-region inventory (tool + report + KB) tools/gapcensus.py (deterministic): index-vs-.text interval math, export cross-check, function-start discovery inside dark regions (E8 call targets + data-section code pointers), pad exclusion, TU attribution, repo-citation flags. Output: reference/decomp/GAP_CENSUS.md + gap_census.tsv. Headline: .text 892KB, index covers 87.3%; 428 dark regions = 90KB REAL code (indexed-but-unexported = 0 -- the gap class is purely 'never indexed'). Game-side dark ~54KB: 66 regions visited by past digs, 159 NEVER TOUCHED. Validation: all six historically-bitten dark addresses (VehicleDead, ToggleLamp, death tail, master-perf, myomer integrator, duck consumer) land inside census regions; the two most-cited regions are the two that produced the most reconstructions. Top uncharted leads (spot-checked real code): the ~9KB l4splr|btmssn cluster (dispatch-table state machine -- likely BTMission's unexported heart); the 613B btplayer hole before the ctor (mission-review id-0x18 sender suspect); btl4app tails; heat|mechmppr + mechweap|btplayer boundaries. Full log: phases/phase-04-gap-census.md. Re-export half deferred (no local Ghidra; scripts ready). KB: source-completeness census section + CLAUDE.md lookup row + decomp-reference tools entry; consult the census BEFORE any 'absent from the export' claim (gotcha #20). Co-Authored-By: Claude Fable 5 --- CLAUDE.md | 1 + context/decomp-reference.md | 1 + context/source-completeness.md | 13 + phases/phase-04-gap-census.md | 54 ++++ reference/decomp/GAP_CENSUS.md | 81 ++++++ reference/decomp/gap_census.tsv | 429 ++++++++++++++++++++++++++++++++ tools/gapcensus.py | 302 ++++++++++++++++++++++ 7 files changed, 881 insertions(+) create mode 100644 phases/phase-04-gap-census.md create mode 100644 reference/decomp/GAP_CENSUS.md create mode 100644 reference/decomp/gap_census.tsv create mode 100644 tools/gapcensus.py diff --git a/CLAUDE.md b/CLAUDE.md index c95ad1f..8f14a4a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -61,6 +61,7 @@ precise than anything you can infer. |---|---| | What the project is, engine, platform, goal | `context/project-overview.md` | | Missing BT source, decompilation strategy | `context/source-completeness.md` | +| **Export DARK REGIONS / "is X in the decomp?"** — the gap census | `reference/decomp/GAP_CENSUS.md` (tool: `tools/gapcensus.py`; log: `phases/phase-04-gap-census.md`) | | The 4.10 literal-source manifest (per-TU function/size/address map) | `reference/BT410_SOURCE_MANIFEST.md` (tool: `tools/manifest410.py`; log: `phases/phase-03-bt410-source-manifest.md`) | | The WinTesla Windows port (renderer/audio/HAL) | `context/wintesla-port.md` | | Build / run / debug / repo layout / env gates | `context/build-and-run.md` + `context/decomp-reference.md` §6 | diff --git a/context/decomp-reference.md b/context/decomp-reference.md index 62d049e..b8e5e7d 100644 --- a/context/decomp-reference.md +++ b/context/decomp-reference.md @@ -685,6 +685,7 @@ Respawn SIM path: `DropZoneReply` `FUN_004bffd0` → `Mech::Reset` @0x4009fb74; --- ## 7. Tools +- `tools/gapcensus.py` — the #60 dark-region census: index/export coverage, function-start discovery, TU attribution, repo-citation flags → `reference/decomp/GAP_CENSUS.md` + `gap_census.tsv`. Consult BEFORE any "absent from the export" claim (gotcha §20). - `tools/disas2.py [len]` — capstone disassembly of BTL4OPT.EXE at a VA (recovers x87 math Ghidra drops; folds known call targets + float constants). THE tool for any `FUN_` the diff --git a/context/source-completeness.md b/context/source-completeness.md index 06dd5e0..30295d2 100644 --- a/context/source-completeness.md +++ b/context/source-completeness.md @@ -94,6 +94,19 @@ its recorded line 400 exactly. [T1/T3 per the sidecar] Plus `BTL4OPT.EXE` as a behavioral **oracle** (run under cdb / read the decomp). Result = behavior-equivalent **reconstruction**, NOT original source. [T2] +## THE GAP CENSUS (2026-08-06, #60) — the dark-region inventory [T1] +`tools/gapcensus.py` → `reference/decomp/GAP_CENSUS.md` + `gap_census.tsv` (regenerate after +any re-export). Headline: .text 892 KB; the index covers 87.3%; **428 dark regions = 90 KB of +real code Ghidra never made into functions** (indexed-but-unexported = 0 — the gap class is +purely "not indexed"). Game-side (bt/ + bt_l4/ + boundary) dark ≈ 54 KB: 66 regions already +visited by past digs, **159 never touched**. Validation: all six historically-bitten dark +addresses (VehicleDead, ToggleLamp, death tail, master-perf, myomer integrator, duck consumer) +land inside census regions. Top uncharted leads + method: `phases/phase-04-gap-census.md`. +**RULE (gotcha §20):** consult the census BEFORE any "absent from the export/binary" claim — +if the address falls in a dark region, the claim needs byte-scan evidence, not export silence. +Second half still open: a Ghidra re-export (scripts ready in `reference/ghidra_scripts/`; no +local install) forcing disassembly at the 332 discovered starts would convert most of it. + ## Key Relationships - Feeds: [[reconstruction-method]] (the loop that fills the gap), [[decomp-reference]]. - Route A closed 2026-07-19 (Nick holds nothing further); gated now only on reconstruction labor + the engine-closure backfill. diff --git a/phases/phase-04-gap-census.md b/phases/phase-04-gap-census.md new file mode 100644 index 0000000..cdcf19a --- /dev/null +++ b/phases/phase-04-gap-census.md @@ -0,0 +1,54 @@ +# Phase 04 — The Export Gap Census (#60) + +**Date:** 2026-08-06 · **Trigger:** export-gap blindness caused 4 wrong conclusions +(reconstruction-gotchas §20), 2 falsely [T1]. **Goal:** turn "we trip over gaps when we +arrive at them" into a known inventory. + +## Method +`tools/gapcensus.py` (deterministic; re-run after any re-export): +1. **Index coverage** — `functions_index.tsv` (6,267 functions with sizes) interval-merged + against the PE `.text` extent → raw dark regions (bytes belonging to NO indexed function). +2. **Export coverage** — `/* @ADDR */` headers in `all/part_*.c` vs the index. +3. **Discovery** — function starts inside dark regions from E8 call targets + data-section + code pointers (vtables/handler tables/Performance pointers), with caller counts. +4. **Annotation** — pad-byte exclusion (CC/90/00), nearest TU attribution from `file=` tags, + and `visited` flags (address cited anywhere in game/ context/ docs/). + +## Headline results +- `.text` = 892 KB. Index covers **87.3%**. Dark: **428 regions, 105 KB raw / 90 KB real code**. +- **Indexed-but-unexported = 0** — the entire gap class is "Ghidra never made it a function" + (consistent with #60's original find: VehicleDead was missing from the *index*, not filtered + from the export). +- 332 function starts discovered inside dark regions (call-graph + data-pointer evidence). +- **By TU family (real code):** munga/ 28.5 KB (engine — source in repo, LOW priority), + **bt/ 24.0 KB + bt_l4/ 14.9 KB + boundary 15.6 KB = ~54 KB of GAME-side dark**, munga_l4/ 9.5 KB. +- **Game-side dark regions: 66 already visited by past digs, 159 never touched.** + +## Validation +All six known dark celebrities land inside census regions: the VehicleDead handler +(`0x4c05c4`), Searchlight ToggleLamp (`0x4b838c`), the TakeDamage death tail (`0x4a07b8`, +inside the famous `0x49ffc8-0x4a1232` stretch — 89 repo citations), the master-perf region +(`0x4a9b5a-0x4ab188` — 69 citations; crouch/myomers/posture all came from here), the myomer +integrator (`0x4b8be3`), the duck consumer (`0x4aa011`). The two most-cited dark regions are +exactly the two that produced the most reconstructions — the census finds the right things. + +## Top uncharted leads (zero citations, real code, spot-checked) +1. **`0x480a2a-0x487ca0` cluster (~9 KB across 6 regions), l4splr|btmssn boundary** — head + spot-check @0x486467: real `enter 0x3c` function driven by a global-index dispatch table + (`[0x4fef88]` → table `0x501588`) — mission-state-machine flavored. Likely the un-exported + heart of **BTMission** (round lifecycle / mode carousel). +2. **`0x4c08fc-0x4c0bc8` (613 B), btplayer, immediately before the BTPlayer ctor** — real + function reading `player+0x24c`; prime suspect for the deferred **mission-review post + (id 0x18)** sender and/or death-cycle siblings. +3. **`0x4d41ae-0x4ddc7c` btl4app regions (~2.6 KB)** — app/session plumbing (attract/config?). +4. **`0x4af691-0x4af9cf` (707 B), heat|mechmppr boundary** — heat-family tail or mapper head. +5. **`0x4bdd7b-0x4be078` (673 B), mechweap|btplayer boundary** — weapon-family virtuals. + +## Systemic fix status +- The inventory (`reference/decomp/GAP_CENSUS.md` + `gap_census.tsv`) is now the FIRST stop + before any "absent from the binary/export" claim — see gotcha §20's checklist. +- **Ghidra re-export** remains the second half: no local Ghidra install on this machine; + `reference/ghidra_scripts/` (ExportAll.java etc.) are ready when one is available (or on + Nick's machine). A re-export with current auto-analysis + forced disassembly of the 332 + discovered starts would convert most of the 90 KB to pseudocode. Until then: raw disasm + per region, as practiced. diff --git a/reference/decomp/GAP_CENSUS.md b/reference/decomp/GAP_CENSUS.md new file mode 100644 index 0000000..fe2595b --- /dev/null +++ b/reference/decomp/GAP_CENSUS.md @@ -0,0 +1,81 @@ +# GAP CENSUS -- the export dark-region inventory (#60) + +Generated by `tools/gapcensus.py` (deterministic; re-run after any re-export). +Machine-readable twin: `gap_census.tsv`. + +## Headline +| Metric | Value | +|---|---| +| Code section (.text) | `0x401000`-`0x4e0000` (892 KB) | +| Indexed functions (functions_index.tsv) | 6267, covering 778 KB (87.3%) | +| **RAW DARK (no indexed function at all)** | **428 regions >= 16B, 105 KB (11.9%) -- 90 KB REAL CODE after padding** | +| Exported pseudocode functions (part_*.c) | 6267 | +| **Indexed but NOT exported** (Ghidra knew it; no pseudocode) | **0 functions, 0 KB** | +| Function starts discovered inside dark regions | 332 (call-graph + data-pointer evidence) | + +Reading the tables: `visited` = the address is already cited somewhere in +game/ context/ docs/ (a prior dig reached it); everything else is UNCHARTED. +`tu` = nearest file-tagged export neighbors (`before|after` when they disagree). + +## Dark code by suspected TU family + +| Family | Regions | Real code bytes | +|---|---|---| +| munga/ (engine core -- source in repo) | 150 | 28540 | +| bt/ (GAME -- reconstruction target) | 87 | 23954 | +| BOUNDARY/mixed | 59 | 15581 | +| bt_l4/ (GAME video/glue -- reconstruction target) | 80 | 14916 | +| munga_l4/ (engine L4 -- source in repo) | 52 | 9529 | + +## Top 40 dark regions by REAL CODE bytes (padding excluded) + +| # | Range | Code bytes | Fn starts | Call-ins | Visited | Suspected TU | +|---|---|---|---|---|---|---| +| 1 | `0x412e41`-`0x4146dc` | 5936 | 6 | 0 | - | munga/boxsolid.cpp|munga/iterator.cpp | +| 2 | `0x4a9b5a`-`0x4ab188` | 4957 | 1 | 0 | 69: `4a9b5a` `4a9b5c` `4a9b6c` `4a9bff`... | bt/mech2.cpp|bt/heat.cpp | +| 3 | `0x486467`-`0x487788` | 4265 | 0 | 0 | - | munga_l4/l4splr.cpp|bt/btmssn.cpp | +| 4 | `0x49ffc8`-`0x4a1232` | 4116 | 5 | 2 | 89: `49ffc8` `49ffcc` `49ffde` `49ffff`... | bt/btmssn.cpp|bt/mech.cpp | +| 5 | `0x4cdce5`-`0x4ceecc` | 3831 | 1 | 0 | 18: `4cdcf0` `4cdd75` `4cdd9d` `4cddc1`... | bt_l4/btl4vid.cpp | +| 6 | `0x4a68ce`-`0x4a71f4` | 1822 | 2 | 0 | 44: `4a6928` `4a6989` `4a69aa` `4a69d6`... | bt/mech2.cpp | +| 7 | `0x4596ab`-`0x459eb8` | 1795 | 0 | 0 | 1: `4599ae` | munga_l4/l4vidrnd.cpp|munga_l4/l4video.cpp | +| 8 | `0x480a2a`-`0x48116d` | 1521 | 0 | 0 | - | munga_l4/l4splr.cpp|bt/btmssn.cpp | +| 9 | `0x42f3fe`-`0x42f9bc` | 1341 | 1 | 0 | - | munga/player.cpp|munga/explode.cpp | +| 10 | `0x40c82a`-`0x40cdb4` | 1322 | 0 | 0 | - | munga/scalar.cpp|munga/boxsolid.cpp | +| 11 | `0x464bf6`-`0x4651ac` | 1312 | 2 | 0 | - | munga_l4/l4audio.cpp|munga_l4/l4audlvl.cpp | +| 12 | `0x40b68c`-`0x40bbe8` | 1293 | 0 | 0 | - | munga/scalar.cpp|munga/boxsolid.cpp | +| 13 | `0x481f77`-`0x48255c` | 1267 | 0 | 0 | - | munga_l4/l4splr.cpp|bt/btmssn.cpp | +| 14 | `0x47ae1b`-`0x47b2ec` | 1060 | 0 | 0 | - | munga_l4/l4ctrl.cpp|munga_l4/l4app.cpp | +| 15 | `0x4dd80a`-`0x4ddc7c` | 1030 | 0 | 0 | - | bt_l4/btl4app.cpp|? | +| 16 | `0x405b1e`-`0x405f44` | 972 | 0 | 0 | - | munga/filestrm.hpp|munga/scalar.cpp | +| 17 | `0x427fd0`-`0x4283b8` | 931 | 0 | 0 | - | munga/network.cpp|munga/watcher.cpp | +| 18 | `0x4cba73`-`0x4cbea0` | 904 | 1 | 0 | 1: `4cbaf0` | bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp | +| 19 | `0x4be3cf`-`0x4be7c4` | 897 | 1 | 0 | 1: `4be474` | bt/mechweap.hpp|bt/btplayer.cpp | +| 20 | `0x4b297b`-`0x4b2d8c` | 894 | 1 | 1 | 30: `4b2980` `4b298c` `4b299e` `4b29bd`... | bt/powersub.cpp|bt/mechweap.cpp | +| 21 | `0x4da08f`-`0x4da44c` | 866 | 4 | 0 | - | bt_l4/btl4app.cpp|? | +| 22 | `0x4147f9`-`0x414b60` | 789 | 4 | 0 | - | munga/boxsolid.cpp|munga/iterator.cpp | +| 23 | `0x4d41ae`-`0x4d45b0` | 765 | 0 | 0 | - | bt_l4/btl4app.cpp|? | +| 24 | `0x412940`-`0x412c78` | 760 | 4 | 0 | - | munga/boxsolid.cpp|munga/iterator.cpp | +| 25 | `0x4af691`-`0x4af9cf` | 707 | 0 | 0 | - | bt/heat.cpp|bt/mechmppr.cpp | +| 26 | `0x4bc0fd`-`0x4bc3fc` | 693 | 1 | 0 | 6: `4bc100` `4bc104` `4bc136` `4bc194`... | bt/mechweap.hpp|bt/btplayer.cpp | +| 27 | `0x4829ab`-`0x482c9f` | 687 | 0 | 0 | - | munga_l4/l4splr.cpp|bt/btmssn.cpp | +| 28 | `0x4bdd7b`-`0x4be078` | 673 | 4 | 0 | - | bt/mechweap.hpp|bt/btplayer.cpp | +| 29 | `0x4105ff`-`0x4108b4` | 635 | 4 | 0 | - | munga/boxsolid.cpp|munga/iterator.cpp | +| 30 | `0x487a27`-`0x487ca0` | 632 | 0 | 0 | - | munga_l4/l4splr.cpp|bt/btmssn.cpp | +| 31 | `0x4221b9`-`0x42249c` | 631 | 2 | 0 | - | munga/network.cpp|munga/watcher.cpp | +| 32 | `0x4c08fc`-`0x4c0bc8` | 613 | 1 | 0 | - | bt/btplayer.cpp|bt_l4/btl4rdr.cpp | +| 33 | `0x4bbcfd`-`0x4bbfcc` | 607 | 2 | 0 | 41: `4bbd04` `4bbd12` `4bbd1b` `4bbd28`... | bt/mechweap.hpp|bt/btplayer.cpp | +| 34 | `0x4c05be`-`0x4c083c` | 552 | 1 | 0 | 22: `4c05c0` `4c05c4` `4c05df` `4c0611`... | bt/btplayer.cpp|bt_l4/btl4rdr.cpp | +| 35 | `0x4bfca1`-`0x4bfee0` | 535 | 1 | 0 | 1: `4bfcac` | bt/mechweap.hpp|bt/btplayer.cpp | +| 36 | `0x483b9b`-`0x483df0` | 520 | 0 | 0 | - | munga_l4/l4splr.cpp|bt/btmssn.cpp | +| 37 | `0x4b8837`-`0x4b8a8c` | 509 | 3 | 0 | 6: `4b8837` `4b8a48` `4b8a50` `4b8a5b`... | bt/powersub.cpp|bt/mechweap.cpp | +| 38 | `0x4c11b3`-`0x4c1408` | 499 | 4 | 0 | 3: `4c11b3` `4c1230` `4c13d4` | bt/btplayer.cpp|bt_l4/btl4rdr.cpp | +| 39 | `0x47b8e2`-`0x47bb20` | 488 | 1 | 0 | - | munga_l4/l4app.cpp|munga_l4/l4splr.cpp | +| 40 | `0x4d95b6`-`0x4d9800` | 487 | 0 | 0 | - | bt_l4/btl4app.cpp|? | + +## Indexed-but-unexported functions (first 60 by address) + +These have index rows (address + size) but no pseudocode in `all/part_*.c` -- +decompile them individually (raw disasm or a targeted re-export) when a dig arrives. + +| Addr | Size | Index name | Cited in repo | +|---|---|---|---| diff --git a/reference/decomp/gap_census.tsv b/reference/decomp/gap_census.tsv new file mode 100644 index 0000000..03e94ce --- /dev/null +++ b/reference/decomp/gap_census.tsv @@ -0,0 +1,429 @@ +lo hi size code starts call_in visited tu +412e41 4146dc 6299 5936 412e6c,4142e8,4143ac,414418,4144b0,4146c4 0 munga/boxsolid.cpp|munga/iterator.cpp +4a9b5a 4ab188 5678 4957 4a9b5c 0 4a9b5a,4a9b5c,4a9b6c,4a9bff,4a9cb6,4a9cf0,4a9cf2,4a9d00,4a9d20,4a9d39,4a9d63,4a9d89,4a9d9e,4a9da4,4a9e80,4a9eb6,4a9f61,4a9f70,4aa007,4aa011,4aa0a9,4aa0af,4aa158,4aa254,4aa288,4aa2eb,4aa342,4aa388,4aa399,4aa3d3,4aa4ff,4aa505,4aa588,4aa5c6,4aa5e1,4aa5e6,4aa630,4aa633,4aa685,4aa6cf,4aa716,4aa741,4aa76c,4aa7ce,4aa81e,4aa86c,4aa89f,4aa8e2,4aa8f3,4aa984,4aaae2,4aab2f,4aab3a,4aab75,4aab9c,4aac2b,4aac6c,4aac88,4aad35,4aad3d,4aaf14,4aaf18,4aaf74,4aaf83,4aaf89,4aafab,4ab16c,4ab178,4ab184 bt/mech2.cpp|bt/heat.cpp +486467 487788 4897 4265 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +49ffc8 4a1232 4714 4116 49ffcc,4a0164,4a0230,4a0c2c,4a122c 2 49ffc8,49ffcc,49ffde,49ffff,4a0027,4a0030,4a003c,4a0051,4a0065,4a006b,4a007d,4a0092,4a00b2,4a00d2,4a00f2,4a010a,4a0117,4a0121,4a0124,4a0148,4a0154,4a015c,4a0164,4a0208,4a0210,4a0218,4a0228,4a0230,4a0264,4a02f4,4a02fb,4a0300,4a0303,4a033c,4a034f,4a0358,4a0361,4a0368,4a036d,4a0375,4a037a,4a038c,4a0396,4a0423,4a0439,4a0450,4a0461,4a0473,4a0488,4a04b9,4a04cc,4a04d8,4a04da,4a0506,4a052b,4a05ce,4a05d9,4a06c0,4a06d2,4a07b2,4a07b5,4a07b8,4a07c0,4a07d4,4a07f6,4a0856,4a0887,4a0890,4a08bd,4a0aa8,4a0ac8,4a0ace,4a0ad6,4a0aef,4a0b21,4a0b33,4a0bda,4a0c2c,4a0c79,4a0d84,4a0e5b,4a0e9e,4a0fab,4a104d,4a10ff,4a117f,4a11cb,4a11d9,4a122c bt/btmssn.cpp|bt/mech.cpp +4cdce5 4ceecc 4583 3831 4cdcf0 0 4cdcf0,4cdd75,4cdd9d,4cddc1,4cde59,4cdede,4cdf6f,4ce2c2,4ce3e2,4ce6e0,4ce7e5,4ceb16,4cebf9,4cec12,4cec47,4cec98,4ced87,4cee64 bt_l4/btl4vid.cpp +4a68ce 4a71f4 2342 1822 4a6928,4a6d8c 0 4a6928,4a6989,4a69aa,4a69d6,4a6a06,4a6a38,4a6a6f,4a6aad,4a6ae2,4a6b21,4a6b37,4a6b4d,4a6b63,4a6b9d,4a6bdb,4a6c17,4a6c6e,4a6cc4,4a6d3d,4a6d6e,4a6d7f,4a6d8c,4a6de9,4a6e0a,4a6e36,4a6e66,4a6e9a,4a6ecc,4a6ed1,4a6f11,4a6f46,4a6f7b,4a6f85,4a6f9b,4a6fb1,4a6fc7,4a6ffc,4a7001,4a7041,4a7076,4a707d,4a712c,4a71d8,4a71e9 bt/mech2.cpp +4596ab 459eb8 2061 1795 0 4599ae munga_l4/l4vidrnd.cpp|munga_l4/l4video.cpp +480a2a 48116d 1859 1521 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +42f3fe 42f9bc 1470 1341 42f404 0 munga/player.cpp|munga/explode.cpp +40c82a 40cdb4 1418 1322 0 munga/scalar.cpp|munga/boxsolid.cpp +464bf6 4651ac 1462 1312 464bfc,465140 0 munga_l4/l4audio.cpp|munga_l4/l4audlvl.cpp +40b68c 40bbe8 1372 1293 0 munga/scalar.cpp|munga/boxsolid.cpp +481f77 48255c 1509 1267 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +47ae1b 47b2ec 1233 1060 0 munga_l4/l4ctrl.cpp|munga_l4/l4app.cpp +4dd80a 4ddc7c 1138 1030 0 bt_l4/btl4app.cpp|? +405b1e 405f44 1062 972 0 munga/filestrm.hpp|munga/scalar.cpp +427fd0 4283b8 1000 931 0 munga/network.cpp|munga/watcher.cpp +4cba73 4cbea0 1069 904 4cbaf0 0 4cbaf0 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +4be3cf 4be7c4 1013 897 4be474 0 4be474 bt/mechweap.hpp|bt/btplayer.cpp +4b297b 4b2d8c 1041 894 4b2980 1 4b2980,4b298c,4b299e,4b29bd,4b29d7,4b2a0d,4b2a43,4b2a4a,4b2a62,4b2a67,4b2aa8,4b2ac2,4b2ac7,4b2aed,4b2afd,4b2b10,4b2b3d,4b2b8a,4b2be3,4b2c2d,4b2c75,4b2d00,4b2d23,4b2d2b,4b2d4b,4b2d6e,4b2d80,4b2d84,4b2d88,4b2d8b bt/powersub.cpp|bt/mechweap.cpp +4da08f 4da44c 957 866 4da090,4da108,4da208,4da300 0 bt_l4/btl4app.cpp|? +4147f9 414b60 871 789 414800,41486c,414904,414b18 0 munga/boxsolid.cpp|munga/iterator.cpp +4d41ae 4d45b0 1026 765 0 bt_l4/btl4app.cpp|? +412940 412c78 824 760 412944,4129b0,412a48,412c60 0 munga/boxsolid.cpp|munga/iterator.cpp +4af691 4af9cf 830 707 0 bt/heat.cpp|bt/mechmppr.cpp +4bc0fd 4bc3fc 767 693 4bc104 0 4bc100,4bc104,4bc136,4bc194,4bc3f4,4bc3f8 bt/mechweap.hpp|bt/btplayer.cpp +4829ab 482c9f 756 687 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4bdd7b 4be078 765 673 4bdd7c,4bddbc,4bddec,4be058 0 bt/mechweap.hpp|bt/btplayer.cpp +4105ff 4108b4 693 635 410604,410688,410754,4108a0 0 munga/boxsolid.cpp|munga/iterator.cpp +487a27 487ca0 633 632 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4221b9 42249c 739 631 4221c0,422360 0 munga/network.cpp|munga/watcher.cpp +4c08fc 4c0bc8 716 613 4c0904 0 bt/btplayer.cpp|bt_l4/btl4rdr.cpp +4bbcfd 4bbfcc 719 607 4bbd04,4bbf88 0 4bbd04,4bbd12,4bbd1b,4bbd28,4bbd36,4bbd71,4bbd80,4bbda9,4bbdcd,4bbdd2,4bbdd9,4bbdea,4bbdf5,4bbe04,4bbe0c,4bbe1d,4bbe25,4bbe30,4bbe44,4bbe4d,4bbe54,4bbe65,4bbe76,4bbe85,4bbe8e,4bbe95,4bbea6,4bbeb1,4bbec2,4bbee6,4bbef4,4bbf05,4bbf0d,4bbf11,4bbf2a,4bbf34,4bbf41,4bbf4c,4bbf51,4bbf5f,4bbf88 bt/mechweap.hpp|bt/btplayer.cpp +4c05be 4c083c 638 552 4c05c4 0 4c05c0,4c05c4,4c05df,4c0611,4c062b,4c0632,4c0641,4c064d,4c0668,4c0670,4c0674,4c067a,4c06a4,4c06da,4c06dd,4c06e3,4c06e9,4c0701,4c072b,4c07cd,4c0828,4c0830 bt/btplayer.cpp|bt_l4/btl4rdr.cpp +4bfca1 4bfee0 575 535 4bfcac 0 4bfcac bt/mechweap.hpp|bt/btplayer.cpp +483b9b 483df0 597 520 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4b8837 4b8a8c 597 509 4b8838,4b8974,4b8a48 0 4b8837,4b8a48,4b8a50,4b8a5b,4b8a68,4b8a6f bt/powersub.cpp|bt/mechweap.cpp +4c11b3 4c1408 597 499 4c11b4,4c1200,4c1230,4c13d4 0 4c11b3,4c1230,4c13d4 bt/btplayer.cpp|bt_l4/btl4rdr.cpp +47b8e2 47bb20 574 488 47b8ec 0 munga_l4/l4app.cpp|munga_l4/l4splr.cpp +4d95b6 4d9800 586 487 0 bt_l4/btl4app.cpp|? +423202 423414 530 460 0 munga/network.cpp|munga/watcher.cpp +45472a 454924 506 451 0 munga_l4/l4vidrnd.cpp +4dc096 4dc260 458 432 4dc098,4dc0b8,4dc1d8,4dc1e0 0 bt_l4/btl4app.cpp|? +4c6482 4c668d 523 426 4c6488 0 4c6488 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +474671 474855 484 421 0 munga_l4/l4gauge.cpp|munga_l4/l4ctrl.cpp +4d2813 4d29fc 489 414 4d2814 0 bt_l4/btl4vid.cpp|bt_l4/btl4mssn.cpp +4816b2 48186d 443 404 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4be903 4beae4 481 396 4be904,4be960,4be9a0 0 4be9a0 bt/mechweap.hpp|bt/btplayer.cpp +45fa03 45fbf4 497 394 45fa08 0 45fb14 munga_l4/l4video.cpp +42ddc4 42df8c 456 391 42ddcc 0 munga/player.cpp|munga/explode.cpp +4551b8 4553ac 500 389 4551c0,455355 0 4551b8 munga_l4/l4vidrnd.cpp +49f84f 49fa00 433 381 49f854 0 49f854,49f88e,49f8cf bt/btmssn.cpp|bt/mech.cpp +443cf5 443e94 415 380 0 munga/watcher.hpp|munga/gauge.cpp +4df975 4dfb04 399 357 4df97c 0 bt_l4/btl4app.cpp|? +4c0f43 4c10dc 409 356 4c1008,4c1011,4c1044 0 bt/btplayer.cpp|bt_l4/btl4rdr.cpp +4109e2 410b5c 378 347 4109e8,410a94 0 munga/boxsolid.cpp|munga/iterator.cpp +4bb947 4bbae0 409 332 4bb948,4bb988,4bb9b8 0 4bb9b8,4bb9d0,4bba29,4bbabe,4bbacf bt/mechweap.hpp|bt/btplayer.cpp +4d993f 4d9c38 761 321 4d9940,4d997d,4d99c5,4d9a15,4d9a55,4d9a6b,4d9a8c,4d9aad,4d9ac5,4d9b2d,4d9b95,4d9be5 0 bt_l4/btl4app.cpp|? +4deec5 4df048 387 321 0 bt_l4/btl4app.cpp|? +4ab9c8 4abb40 376 318 4ab9d8 0 4ab9d8,4aba86,4abab9 bt/mech2.cpp|bt/heat.cpp +409c41 409d9c 347 312 0 munga/scalar.cpp|munga/boxsolid.cpp +4c8ded 4c8f54 359 311 4c8df4 1 4c8df4 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +4b1a3b 4b1bb1 374 308 4b1a40 0 4b1a40 bt/powersub.cpp|bt/mechweap.cpp +484ed6 485020 330 307 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +43223f 4323a8 361 306 0 munga/explode.cpp|munga/registry.cpp +4b8b92 4b8d18 390 305 4b8b9c 0 4b8b9a,4b8b9c,4b8bab,4b8bb9,4b8be3,4b8bf0,4b8c0f,4b8c16,4b8c1b,4b8c1e,4b8c5a,4b8ce8,4b8ceb,4b8d0d bt/powersub.cpp|bt/mechweap.cpp +47bc11 47bd48 311 284 47bc14,47bccc 0 munga_l4/l4app.cpp|munga_l4/l4splr.cpp +40f6a7 40f7d8 305 283 0 munga/boxsolid.cpp|munga/iterator.cpp +410070 4101a0 304 279 41007c,410180 0 munga/boxsolid.cpp|munga/iterator.cpp +4310c3 431200 317 267 4310c4,431170,4311dc 0 munga/explode.cpp|munga/registry.cpp +4b1e33 4b1f7c 329 258 4b1e34,4b1e90,4b1ed0 0 4b1ed0 bt/powersub.cpp|bt/mechweap.cpp +481565 481675 272 247 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +44e5a2 44e6c0 286 246 44e5a8 0 munga/app.cpp +4cd7f4 4cd918 292 244 4cd804 0 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +45888e 4589a0 274 241 0 munga_l4/l4vidrnd.cpp +4d2016 4d2150 314 241 0 bt_l4/btl4vid.cpp|bt_l4/btl4mssn.cpp +466ac2 466bc4 258 235 0 munga_l4/l4audwtr.cpp|munga_l4/l4audres.cpp +466702 466804 258 234 0 munga_l4/l4audwtr.cpp|munga_l4/l4audres.cpp +484076 48416d 247 229 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +480899 4809ba 289 222 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +483e86 483f75 239 213 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4b76c3 4b77bc 249 201 4b7780 0 4b7780 bt/powersub.cpp|bt/mechweap.cpp +4c452c 4c462c 256 201 4c4534 0 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +4bac04 4bace8 228 199 4bac0c 0 4bac0c bt/mechweap.hpp|bt/btplayer.cpp +42e630 42e718 232 198 42e650,42e6cc 0 munga/player.cpp|munga/explode.cpp +4b9470 4b9550 224 193 0 bt/powersub.cpp|bt/mechweap.cpp +41d9ec 41dac6 218 192 41da5c 0 munga/network.cpp|munga/watcher.cpp +4b257f 4b2660 225 192 0 bt/powersub.cpp|bt/mechweap.cpp +4ba379 4ba45c 227 192 4ba39c,4ba410 0 bt/mechweap.cpp|bt/mechweap.hpp +4036af 403798 233 190 0 munga/filestrm.hpp|munga/scalar.cpp +4bb796 4bb878 226 190 0 bt/mechweap.hpp|bt/btplayer.cpp +42c936 42ca20 234 188 42c93c 0 munga/cammgr.cpp|munga/player.cpp +4825f5 4826d1 220 187 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4063ee 4064bc 206 186 0 munga/filestrm.hpp|munga/scalar.cpp +40cee4 40cfb8 212 186 0 munga/scalar.cpp|munga/boxsolid.cpp +40a66e 40a738 202 185 40a67c 1 munga/scalar.cpp|munga/boxsolid.cpp +4424e9 4425af 198 185 4424ef 0 munga/watcher.hpp|munga/gauge.cpp +468476 46853c 198 185 46847c 0 munga_l4/l4audrnd.cpp|munga_l4/l4gauge.cpp +470c15 470cfc 231 184 470c1c 0 munga_l4/l4audrnd.cpp|munga_l4/l4gauge.cpp +4bfb43 4bfc20 221 184 4bfb44,4bfba8,4bfbe8 0 4bfbe8 bt/mechweap.hpp|bt/btplayer.cpp +4851da 4852b1 215 183 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4328f7 4329d4 221 179 4328f8,432944,432974 0 munga/explode.cpp|munga/registry.cpp +4b5b1e 4b5bf8 218 178 4b5b44,4b5ba0,4b5be0 0 4b5be0 bt/powersub.cpp|bt/mechweap.cpp +481e2b 481eff 212 174 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4d8725 4d87e8 195 174 4d87d4 0 bt_l4/btl4app.cpp|? +4a4c97 4a4d60 201 173 4a4c98,4a4d14 0 bt/mech.cpp|bt/mech2.cpp +4c60ef 4c61c8 217 173 4c60f4 0 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +42a087 42a150 201 172 42a088,42a104 0 munga/hostmgr.cpp|munga/caminst.cpp +42d1f7 42d2c0 201 172 0 munga/cammgr.cpp|munga/player.cpp +420d90 420e58 200 171 420d90 0 munga/network.cpp|munga/watcher.cpp +433153 433220 205 170 0 munga/explode.cpp|munga/registry.cpp +4c1b45 4c1c24 223 170 4c1b4c 0 bt/btplayer.cpp|bt_l4/btl4rdr.cpp +40793f 4079fc 189 165 0 munga/filestrm.hpp|munga/scalar.cpp +42d53f 42d600 193 165 42d540,42d5b4 0 munga/cammgr.cpp|munga/player.cpp +4bcaed 4bcbb0 195 165 0 bt/mechweap.hpp|bt/btplayer.cpp +41a2be 41a37f 193 164 41a324 0 munga/hash.cpp|munga/event.cpp +4b08db 4b099c 193 164 4b08dc,4b0950 0 bt/mechmppr.cpp|bt/powersub.cpp +44475e 444818 186 163 444764 0 munga/gauge.cpp|munga/lamp.cpp +4bd1fb 4bd2c0 197 163 4bd1fc,4bd23c,4bd26c 0 4bd26c,4bd271 bt/mechweap.hpp|bt/btplayer.cpp +4bee8b 4bef4c 193 163 4bef28 0 bt/mechweap.hpp|bt/btplayer.cpp +409145 4091f4 175 160 0 munga/scalar.cpp|munga/boxsolid.cpp +409747 4097f4 173 160 0 munga/scalar.cpp|munga/boxsolid.cpp +4acee9 4acfa9 192 159 0 4acf10 bt/mech2.cpp|bt/heat.cpp +495fbe 496078 186 157 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +47f761 47f807 166 156 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +405f51 406018 199 155 0 munga/filestrm.hpp|munga/scalar.cpp +4d7fcb 4d8080 181 155 0 bt_l4/btl4app.cpp|? +41c378 41c42c 180 153 41c378 0 munga/cmpnnt.cpp|munga/network.cpp +4a2cae 4a2d48 154 147 0 4a2d44 bt/mech.cpp|bt/mech2.cpp +43d723 43d7bc 153 146 43d730 0 munga/audseq.cpp|munga/audwthr.cpp +422f35 422fe0 171 145 422f44 0 munga/network.cpp|munga/watcher.cpp +44de75 44df10 155 144 44de78,44de8c,44dea0,44deb8,44ded0,44dee8,44defc 0 munga/controls.cpp|munga/app.cpp +4bdbff 4bdcb4 181 142 4bdca4 0 4bdca4 bt/mechweap.hpp|bt/btplayer.cpp +4c5ac4 4c5b7c 184 141 4c5ad4 0 4c5ac8 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +42c58b 42c630 165 139 42c58c 0 42c611 munga/cammgr.cpp|munga/player.cpp +4d68ba 4d6958 158 139 0 bt_l4/btl4app.cpp|? +47a999 47aa48 175 138 47a9bc 0 munga_l4/l4ctrl.cpp|munga_l4/l4app.cpp +423ce3 423d88 165 137 0 munga/network.cpp|munga/watcher.cpp +42855f 428601 162 137 428560,4285c4 0 munga/network.cpp|munga/watcher.cpp +42f07f 42f121 162 136 0 munga/player.cpp|munga/explode.cpp +411950 4119dc 140 133 411958 0 munga/boxsolid.cpp|munga/iterator.cpp +411b54 411be0 140 133 411b5c 0 munga/boxsolid.cpp|munga/iterator.cpp +42f9d7 42fa79 162 133 42f9d8,42fa3c 0 munga/player.cpp|munga/explode.cpp +41215a 4121e8 142 132 412164 0 munga/boxsolid.cpp|munga/iterator.cpp +412367 4123f4 141 132 412370 0 munga/boxsolid.cpp|munga/iterator.cpp +41256e 4125fc 142 132 412578 0 munga/boxsolid.cpp|munga/iterator.cpp +411178 411200 136 131 41117c 0 munga/boxsolid.cpp|munga/iterator.cpp +41136c 4113f4 136 131 411370 0 munga/boxsolid.cpp|munga/iterator.cpp +411d4d 411ddc 143 131 411d58 0 munga/boxsolid.cpp|munga/iterator.cpp +411f52 411fe0 142 131 411f5c 0 munga/boxsolid.cpp|munga/iterator.cpp +41277b 412808 141 131 412784 0 munga/boxsolid.cpp|munga/iterator.cpp +46d5ec 46d694 168 131 0 munga_l4/l4audrnd.cpp|munga_l4/l4gauge.cpp +41155e 4115e8 138 129 411564 0 munga/boxsolid.cpp|munga/iterator.cpp +41174d 4117d8 139 129 411754 0 munga/boxsolid.cpp|munga/iterator.cpp +422b1d 422bac 143 126 0 munga/network.cpp|munga/watcher.cpp +4ad57f 4ad619 154 126 4ad580,4ad5dc 0 bt/mech2.cpp|bt/heat.cpp +44df5b 44dfe0 133 124 0 munga/controls.cpp|munga/app.cpp +479aee 479b78 138 123 0 munga_l4/l4ctrl.cpp|munga_l4/l4app.cpp +4d160b 4d168c 129 119 0 bt_l4/btl4vid.cpp|bt_l4/btl4mssn.cpp +481202 481286 132 118 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +42943c 4294c1 133 115 0 munga/hostmgr.cpp|munga/caminst.cpp +433895 433920 139 115 433898,4338e0 0 munga/registry.cpp|munga/intorgn.cpp +4366e1 436769 136 115 0 munga/renderer.cpp|munga/audio.cpp +436ecc 436f51 133 115 436ecc,436f14 0 munga/audio.cpp|munga/audlvl.cpp +43c096 43c11d 135 115 0 munga/audsrc.cpp|munga/audmidi.cpp +44f050 44f0d5 133 115 44f050,44f098 0 munga/app.cpp|munga/appmgr.cpp +452996 452a1d 135 115 452998,4529e0 0 munga_l4/l4net.cpp|munga_l4/l4vidrnd.cpp +47c760 47c7e8 136 115 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4d3ae9 4d3b74 139 115 4d3b34 0 bt_l4/btl4app.cpp|? +4d40f3 4d4179 134 115 4d40f4 0 bt_l4/btl4app.cpp|? +4db2ed 4db428 315 115 4db2ed,4db34d,4db3a5,4db411,4db41b 0 bt_l4/btl4app.cpp|? +4dc3a6 4dc41c 118 115 4dc3a8 0 bt_l4/btl4app.cpp|? +4352f0 435375 133 114 0 munga/interest.cpp|munga/renderer.cpp +47d528 47d5a2 122 113 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +463b3b 463bbc 129 111 463b60 0 munga_l4/l4audio.cpp +474542 4745e0 158 111 474550 0 munga_l4/l4gauge.cpp|munga_l4/l4ctrl.cpp +48128b 48130d 130 110 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +40a742 40a7c0 126 109 40a744 0 munga/scalar.cpp|munga/boxsolid.cpp +437360 4373e8 136 107 0 munga/audio.cpp|munga/audlvl.cpp +4b2140 4b21d0 144 105 4b215c 0 4b2154,4b2158,4b215c,4b2164,4b2194,4b219f bt/powersub.cpp|bt/mechweap.cpp +4d769d 4d771c 127 104 0 bt_l4/btl4app.cpp|? +4d9dad 4d9e28 123 104 4d9db0 3 bt_l4/btl4app.cpp|? +47f5a7 47f629 130 103 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +49e80e 49e880 114 103 49e814 0 49e814 bt/btmssn.cpp|bt/mech.cpp +49f367 49f3d5 110 102 49f36d 0 bt/btmssn.cpp|bt/mech.cpp +42d913 42d990 125 101 0 munga/cammgr.cpp|munga/player.cpp +4c14cb 4c1548 125 101 0 bt/btplayer.cpp|bt_l4/btl4rdr.cpp +4308cf 43094a 123 100 0 munga/explode.cpp|munga/registry.cpp +46416b 4641e0 117 100 464178 0 munga_l4/l4audio.cpp +47d390 47d3fd 109 99 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4c4aff 4c4b84 133 95 4c4b08 0 4c4b08 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +41ca44 41cab2 110 93 41ca84 0 munga/cmpnnt.cpp|munga/network.cpp +4ae45e 4ae4d8 122 93 4ae464 0 4ae464,4ae497,4ae499,4ae4a5,4ae4b1,4ae4bd bt/heat.cpp|bt/mechmppr.cpp +41d27b 41d2ea 111 92 41d27c 0 munga/cmpnnt.cpp|munga/network.cpp +464818 46487c 100 92 464824 0 munga_l4/l4audio.cpp +4ca194 4ca208 116 92 4ca1a0 0 4ca194 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +49bf6f 49bfde 111 90 0 bt/btmssn.cpp|bt/mech.cpp +4da822 4da914 242 90 4da822,4da88a,4da894,4da89e,4da8a8 0 bt_l4/btl4app.cpp|? +4de3b9 4de420 103 86 0 bt_l4/btl4app.cpp|? +4d7c7d 4d7cd8 91 84 0 bt_l4/btl4app.cpp|? +4dc625 4dc680 91 84 4dc628,4dc660 0 bt_l4/btl4app.cpp|? +4b6a11 4b6a78 103 82 4b6a1c 0 4b6a1c bt/powersub.cpp|bt/mechweap.cpp +4dc779 4dc7d4 91 81 4dc77c 2 bt_l4/btl4app.cpp|? +4bafb6 4bb014 94 80 4bafc8 0 4bafbc,4bafc8 bt/mechweap.hpp|bt/btplayer.cpp +41b8fb 41b956 91 79 41b928 0 munga/cmpnnt.cpp|munga/network.cpp +450004 45005e 90 79 0 munga/icom.cpp|munga_l4/l4net.cpp +47d002 47d062 96 79 47d008,47d034 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +491bd6 491c2c 86 79 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4dbdfb 4dbe58 93 79 4dbdfc 0 bt_l4/btl4app.cpp|? +477a31 477a8e 93 78 477a34,477a60 0 munga_l4/l4ctrl.cpp|munga_l4/l4app.cpp +40a8de 40a938 90 77 0 munga/scalar.cpp|munga/boxsolid.cpp +42134f 4213aa 91 77 421350,42137c 0 munga/network.cpp|munga/watcher.cpp +4bcbfb 4bcc60 101 77 4bcbfc,4bcc3c 0 4bcc3c,4bcc4e bt/mechweap.hpp|bt/btplayer.cpp +4bbc18 4bbc78 96 76 4bbc20 0 4bbc20 bt/mechweap.hpp|bt/btplayer.cpp +4bb425 4bb478 83 74 4bb42c 0 4bb428,4bb42c bt/mechweap.hpp|bt/btplayer.cpp +40a482 40a4d8 86 73 0 munga/scalar.cpp|munga/boxsolid.cpp +40f2ac 40f2f8 76 72 0 munga/scalar.cpp|munga/boxsolid.cpp +4a7ef6 4a7f50 90 71 0 bt/mech2.cpp|bt/heat.cpp +4d6621 4d66b8 151 69 4d6670 0 bt_l4/btl4app.cpp|? +4dc836 4dc888 82 69 4dc838,4dc880 3 bt_l4/btl4app.cpp|? +40aa51 40aaa0 79 68 0 munga/scalar.cpp|munga/boxsolid.cpp +4c19ae 4c19fc 78 68 4c19b0 0 bt/btplayer.cpp|bt_l4/btl4rdr.cpp +4dd4ed 4dd53c 79 67 0 bt_l4/btl4app.cpp|? +40a1e3 40a22c 73 66 0 munga/scalar.cpp|munga/boxsolid.cpp +4ad6f5 4ad748 83 65 4ad6f8 0 4ad6f8,4ad700,4ad70d,4ad714,4ad722,4ad728,4ad731 bt/mech2.cpp|bt/heat.cpp +44c6ba 44c6fc 66 63 44c6bc 0 munga/controls.cpp|munga/app.cpp +488c3d 488c80 67 63 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4d706f 4d70b0 65 62 4d7070 4 bt_l4/btl4app.cpp|? +40c129 40c170 71 61 0 munga/scalar.cpp|munga/boxsolid.cpp +44ca29 44ca72 73 61 0 munga/controls.cpp|munga/app.cpp +47d4c8 47d517 79 61 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4a5bad 4a5bf8 75 61 0 bt/mech2.cpp +4a62f8 4a6344 76 61 0 bt/mech2.cpp +4af518 4af564 76 60 4af524 0 bt/heat.cpp|bt/mechmppr.cpp +4d0735 4d0774 63 60 0 bt_l4/btl4vid.cpp +408b51 408b98 71 59 408b54 0 munga/scalar.cpp|munga/boxsolid.cpp +4a562f 4a5678 73 59 0 bt/mech2.cpp +4a7924 4a7970 76 59 0 4a7924 bt/mech2.cpp|bt/heat.cpp +4082d7 40831c 69 58 0 munga/scalar.cpp|munga/boxsolid.cpp +4ae971 4ae9c0 79 58 4ae980 0 bt/heat.cpp|bt/mechmppr.cpp +409f1b 409f58 61 57 0 munga/scalar.cpp|munga/boxsolid.cpp +4aee28 4aee70 72 57 4aee2c 0 4aee2c bt/heat.cpp|bt/mechmppr.cpp +40edc5 40ee00 59 54 0 munga/scalar.cpp|munga/boxsolid.cpp +47f864 47f8a2 62 54 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4890c4 4890fc 56 54 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +492110 492150 64 54 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +43dfc8 43e004 60 53 43dfcc 0 munga/audwthr.cpp +43e2a8 43e2e4 60 53 43e2ac 0 munga/audwthr.cpp +4d9c83 4d9cc4 65 52 0 bt_l4/btl4app.cpp|? +4d5603 4d563c 57 51 4d5603 6 bt_l4/btl4app.cpp|? +4b025f 4b029c 61 48 4b0280 0 4b0280 bt/heat.cpp|bt/mechmppr.cpp +4da6d3 4da754 129 48 4da6d3,4da73f,4da749 0 bt_l4/btl4app.cpp|? +4db06c 4db0ec 128 48 4db06c,4db0d8,4db0e2 0 bt_l4/btl4app.cpp|? +40df2d 40df68 59 47 0 munga/scalar.cpp|munga/boxsolid.cpp +47a48f 47a4cc 61 47 0 munga_l4/l4ctrl.cpp|munga_l4/l4app.cpp +47edac 47eddd 49 47 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4adcfa 4add30 54 47 4add00 0 4add00 bt/mech2.cpp|bt/heat.cpp +4b6fb8 4b6fec 52 47 4b6fc0 0 4b6fc0 bt/powersub.cpp|bt/mechweap.cpp +4ded5f 4deda4 69 47 4ded60 0 bt_l4/btl4app.cpp|? +458688 4586bc 52 46 458690 0 munga_l4/l4vidrnd.cpp +45d397 45d3cc 53 46 0 munga_l4/l4video.cpp +4be8b7 4be8e8 49 46 4be8bc 0 4be8b8,4be8bc bt/mechweap.hpp|bt/btplayer.cpp +42eb06 42eb38 50 45 42eb08 0 munga/player.cpp|munga/explode.cpp +456526 456558 50 45 45652c 0 munga_l4/l4vidrnd.cpp +4dcdb9 4dcdec 51 45 4dcdbc 1 bt_l4/btl4app.cpp|? +457103 457138 53 44 45710c 0 munga_l4/l4vidrnd.cpp +45773f 457770 49 44 457744 0 munga_l4/l4vidrnd.cpp +49013c 49016c 48 44 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4ae530 4ae568 56 44 4ae534 0 4ae534 bt/heat.cpp|bt/mechmppr.cpp +4b910f 4b9140 49 44 4b9114 0 4b9114 bt/powersub.cpp|bt/mechweap.cpp +4bee3d 4bee70 51 44 4bee44 0 4bee44 bt/mechweap.hpp|bt/btplayer.cpp +4ddcec 4ddd20 52 44 4ddcec 0 bt_l4/btl4app.cpp|? +40ddf3 40de34 65 43 40ddf8,40de28 0 munga/scalar.cpp|munga/boxsolid.cpp +446fa7 446fdc 53 43 0 munga/gaugrend.cpp +4563c9 4563fc 51 43 4563d0 0 munga_l4/l4vidrnd.cpp +4c9b9b 4c9bd0 53 43 4c9b9c 0 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +4cc0b0 4cc0e1 49 43 4cc0b0 0 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +4dc322 4dc35c 58 43 4dc324 0 bt_l4/btl4app.cpp|? +41f56e 41f59c 46 42 41f570 0 munga/network.cpp|munga/watcher.cpp +47d932 47d962 48 42 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4d6997 4d69d0 57 42 4d69a4,4d69bc 0 bt_l4/btl4app.cpp|? +4093ff 40942c 45 41 0 munga/scalar.cpp|munga/boxsolid.cpp +43bcf0 43bd20 48 41 0 munga/audsrc.cpp +465cda 465d08 46 41 465cdc 0 munga_l4/l4audlvl.cpp|munga_l4/l4audwtr.cpp +48c271 48c2a0 47 41 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +49f6f6 49f728 50 41 49f700 0 49f700 bt/btmssn.cpp|bt/mech.cpp +4dd095 4dd0c8 51 41 4dd098 1 bt_l4/btl4app.cpp|? +44425e 444290 50 40 0 munga/gauge.cpp +46055c 460590 52 40 460564 1 munga_l4/l4video.cpp +4941b6 4941e4 46 40 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4b8387 4b83b8 49 40 4b838c 0 4b838c,4b83b0 bt/powersub.cpp|bt/mechweap.cpp +4da4d1 4da538 103 40 4da4d1,4da52d 0 bt_l4/btl4app.cpp|? +4dd461 4dd494 51 40 4dd464 0 bt_l4/btl4app.cpp|? +47c34f 47c380 49 39 47c358 0 munga_l4/l4app.cpp|munga_l4/l4splr.cpp +48c1c0 48c1f0 48 39 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4d3e72 4d3ea0 46 39 4d3e78 0 bt_l4/btl4app.cpp|? +402344 402370 44 38 402344 0 munga/heap.cpp|munga/cstr.cpp +40eb36 40eb64 46 38 40eb38,40eb54 0 munga/scalar.cpp|munga/boxsolid.cpp +40ee0a 40ee38 46 38 0 munga/scalar.cpp|munga/boxsolid.cpp +4360dc 43610c 48 38 4360e4 0 munga/interest.cpp|munga/renderer.cpp +47e58a 47e5c1 55 38 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +496d36 496d68 50 38 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4ae89b 4ae8d0 53 38 4ae8b0 0 4ae8b0 bt/heat.cpp|bt/mechmppr.cpp +4d7ee5 4d7f10 43 38 0 bt_l4/btl4app.cpp|? +417edd 417f0c 47 37 417efc 0 munga/socket.cpp|munga/sfeskt.cpp +41858d 4185bc 47 37 418590 0 munga/srtskt.cpp|munga/vchain.cpp +41b65a 41b688 46 37 41b65c 0 munga/event.cpp|munga/cmpnnt.cpp +497ae7 497b18 49 37 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +417aca 417af8 46 36 417acc 0 munga/socket.cpp|munga/sfeskt.cpp +4423fe 44242c 46 36 442400,44241c 0 munga/watcher.hpp|munga/gauge.cpp +447110 447138 40 36 0 munga/gaugrend.cpp +4472c1 4472ec 43 36 0 munga/gaugrend.cpp|munga/gaugalrm.cpp +47d5e7 47d61b 52 36 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +49ecff 49ed28 41 36 49ed0c 2 49ed0c bt/btmssn.cpp|bt/mech.cpp +4a164a 4a1674 42 36 0 bt/btmssn.cpp|bt/mech.cpp +4c8115 4c8140 43 36 0 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +43597a 4359a8 46 35 43597c,435998 0 munga/interest.cpp|munga/renderer.cpp +447682 4476ac 42 35 0 munga/gaugrend.cpp|munga/gaugalrm.cpp +45435f 454394 53 35 0 munga_l4/l4vidrnd.cpp +460811 460840 47 35 460820 0 munga_l4/l4video.cpp +49463e 494668 42 35 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4c18c4 4c18f4 48 35 4c18cc 1 bt/btplayer.cpp|bt_l4/btl4rdr.cpp +446c11 446c3c 43 34 0 munga/gaugrend.cpp +4713b3 4713e0 45 34 4713b4 0 munga_l4/l4audrnd.cpp|munga_l4/l4gauge.cpp +4cc242 4cc264 34 34 0 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +401073 40109c 41 33 401074 1 ?|munga/heap.cpp +40aab2 40aadc 42 33 40aab4 0 munga/scalar.cpp|munga/boxsolid.cpp +44aa90 44aab0 32 32 0 munga/graph2d.cpp +46b6b4 46b6d4 32 32 0 munga_l4/l4audrnd.cpp|munga_l4/l4gauge.cpp +481501 481528 39 32 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +43f87f 43f8ab 44 31 43f883 0 munga/audwthr.hpp +43fd9e 43fdca 44 31 43fda2 0 munga/audwthr.hpp|munga/watcher.hpp +4d45f8 4d461f 39 31 0 bt_l4/btl4app.cpp|? +408c95 408cbc 39 30 0 munga/scalar.cpp|munga/boxsolid.cpp +410e99 410ec8 47 30 410eb0 0 munga/boxsolid.cpp|munga/iterator.cpp +4d1bcb 4d1bf0 37 30 0 bt_l4/btl4vid.cpp|bt_l4/btl4mssn.cpp +4d6290 4d62b7 39 30 0 bt_l4/btl4app.cpp|? +42e0dc 42e100 36 29 42e0e0 0 munga/player.cpp|munga/explode.cpp +440faf 440fdb 44 29 440fb3 0 munga/audwthr.hpp +472a9a 472ac4 42 29 472aa8 0 munga_l4/l4audrnd.cpp|munga_l4/l4gauge.cpp +446843 446860 29 28 0 munga/gaugrend.cpp +475a31 475a54 35 28 475a38 0 munga_l4/l4ctrl.cpp +4bca9a 4bcabc 34 28 0 bt/mechweap.hpp|bt/btplayer.cpp +4d1abd 4d1ae4 39 28 4d1acc 0 4d1acc bt_l4/btl4vid.cpp|bt_l4/btl4mssn.cpp +4464b4 4464d4 32 27 0 munga/gaugrend.cpp +494de1 494e00 31 27 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4bdb71 4bdb94 35 27 0 bt/mechweap.hpp|bt/btplayer.cpp +4dee51 4dee74 35 27 0 bt_l4/btl4app.cpp|? +41739a 4173b8 30 26 4173a8 0 munga/objstrm.cpp|munga/socket.cpp +41d886 41d8a8 34 26 0 munga/network.cpp +432431 432450 31 26 0 munga/explode.cpp|munga/registry.cpp +4693c0 4693e0 32 26 0 munga_l4/l4audrnd.cpp|munga_l4/l4gauge.cpp +4b9c98 4b9cbc 36 26 4b9c9c 0 4b9c9c bt/mechweap.cpp|bt/mechweap.hpp +4c62d2 4c62fc 42 26 4c62d8 0 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +4d918a 4d91ac 34 26 0 bt_l4/btl4app.cpp|? +429939 42995c 35 25 0 munga/hostmgr.cpp|munga/caminst.cpp +401bc9 401be8 31 24 401bdc 0 ?|munga/heap.cpp +4284ee 428508 26 24 0 munga/network.cpp|munga/watcher.cpp +45e727 45e744 29 24 0 munga_l4/l4video.cpp +45f584 45f59c 24 24 0 munga_l4/l4video.cpp +49f603 49f624 33 24 49f604 0 49f604 bt/btmssn.cpp|bt/mech.cpp +4b177c 4b179c 32 24 4b1780 0 4b1780 bt/powersub.cpp|bt/mechweap.cpp +41cca5 41ccc0 27 23 0 munga/cmpnnt.cpp|munga/network.cpp +43af9a 43afbc 34 23 0 munga/audcmp.cpp|munga/audsrc.cpp +4965e2 496600 30 23 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4ae707 4ae724 29 23 4ae70c 0 bt/heat.cpp|bt/mechmppr.cpp +4afbc2 4afbe0 30 23 4afbc4 0 4afbc4 bt/heat.cpp|bt/mechmppr.cpp +432bfb 432c18 29 22 0 munga/explode.cpp|munga/registry.cpp +47008e 4700ac 30 22 470090 0 munga_l4/l4audrnd.cpp|munga_l4/l4gauge.cpp +47cc87 47cca0 25 22 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +47df60 47df82 34 22 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4c2a02 4c2a1d 27 22 4c2a04 0 bt_l4/btl4rdr.cpp|bt_l4/btl4gaug.cpp +496bff 496c18 25 21 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4aeedc 4aeef8 28 21 4aeee0 0 bt/heat.cpp|bt/mechmppr.cpp +4d5cc7 4d5cdf 24 21 0 bt_l4/btl4app.cpp|? +4d881a 4d8834 26 21 0 bt_l4/btl4app.cpp|? +4657ae 4657c9 27 19 0 munga_l4/l4audio.cpp|munga_l4/l4audlvl.cpp +4b375a 4b3778 30 19 0 bt/powersub.cpp|bt/mechweap.cpp +4bb3ac 4bb3c8 28 19 0 bt/mechweap.hpp|bt/btplayer.cpp +4dd172 4dd188 22 19 4dd174 1 bt_l4/btl4app.cpp|? +40d1f8 40d210 24 18 0 munga/scalar.cpp|munga/boxsolid.cpp +41dd52 41dd68 22 18 0 munga/network.cpp|munga/watcher.cpp +46312b 463148 29 18 0 munga_l4/l4audhdw.cpp|munga_l4/l4audio.cpp +4703df 4703f4 21 18 0 munga_l4/l4audrnd.cpp|munga_l4/l4gauge.cpp +47407a 474094 26 18 0 munga_l4/l4gauge.cpp|munga_l4/l4ctrl.cpp +475233 47524c 25 18 0 munga_l4/l4gauge.cpp|munga_l4/l4ctrl.cpp +403687 4036a0 25 17 0 munga/filestrm.hpp|munga/scalar.cpp +41e37e 41e394 22 17 0 munga/network.cpp|munga/watcher.cpp +42c83a 42c850 22 17 0 munga/cammgr.cpp|munga/player.cpp +48d03c 48d050 20 17 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4913d9 4913f0 23 17 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +49b533 49b54c 25 17 0 munga_l4/l4splr.cpp|bt/btmssn.cpp +4bf593 4bf5b4 33 17 0 4bf594,4bf5b0 bt/mechweap.hpp|bt/btplayer.cpp +4dafc2 4dafd8 22 17 0 bt_l4/btl4app.cpp|? +45a93f 45a954 21 16 0 munga_l4/l4vidrnd.cpp|munga_l4/l4video.cpp +4b1398 4b13ac 20 16 0 bt/powersub.cpp|bt/mechweap.cpp +4b7eb8 4b7ed4 28 16 0 bt/powersub.cpp|bt/mechweap.cpp +4d5d37 4d5d4b 20 16 0 bt_l4/btl4app.cpp|? +42b5bd 42b5d4 23 15 0 munga/caminst.cpp|munga/cammgr.cpp +4c6bce 4c6be4 22 15 0 4c6bd0 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +4080fe 408110 18 14 0 munga/scalar.cpp|munga/boxsolid.cpp +40825f 408270 17 14 0 munga/scalar.cpp|munga/boxsolid.cpp +49e72a 49e740 22 14 0 bt/btmssn.cpp|bt/mech.cpp +4b64f6 4b6510 26 14 0 bt/powersub.cpp|bt/mechweap.cpp +4cc187 4cc1a0 25 14 0 bt_l4/btl4gaug.cpp|bt_l4/btl4vid.cpp +4d5474 4d5488 20 14 0 bt_l4/btl4app.cpp|? +42cd35 42cd48 19 13 0 munga/cammgr.cpp|munga/player.cpp +4da9e0 4da9f4 20 13 4da9e0,4da9ea 0 bt_l4/btl4app.cpp|? +4dec26 4dec40 26 13 0 bt_l4/btl4app.cpp|? +49c509 49c51c 19 12 0 49c514 bt/btmssn.cpp|bt/mech.cpp +4ad870 4ad884 20 12 0 bt/mech2.cpp|bt/heat.cpp +4ba818 4ba838 32 12 0 bt/mechweap.hpp|bt/btplayer.cpp +4d3ba7 4d3bb8 17 12 4d3ba8 0 4d3ba8 bt_l4/btl4app.cpp|? +40dda1 40ddb8 23 11 40ddac 0 munga/scalar.cpp|munga/boxsolid.cpp +40ea57 40ea6c 21 11 0 munga/scalar.cpp|munga/boxsolid.cpp +427d82 427d92 16 11 0 munga/network.cpp|munga/watcher.cpp +43743b 43744c 17 11 43743c,437448 0 munga/audio.cpp|munga/audlvl.cpp +4bc676 4bc688 18 11 0 bt/mechweap.hpp|bt/btplayer.cpp +443ec6 443edc 22 10 0 munga/watcher.hpp|munga/gauge.cpp +448533 448548 21 10 448538 0 munga/gaugrend.cpp|munga/gaugalrm.cpp +47a0d3 47a0e8 21 10 0 munga_l4/l4ctrl.cpp|munga_l4/l4app.cpp +41e57b 41e590 21 9 0 munga/network.cpp|munga/watcher.cpp +476e23 476e34 17 9 0 munga_l4/l4ctrl.cpp +4bec17 4bec34 29 9 0 4bec18,4bec24,4bec28 bt/mechweap.hpp|bt/btplayer.cpp +4de29d 4de2bc 31 9 0 bt_l4/btl4app.cpp|? +479fbf 479fd0 17 7 0 munga_l4/l4ctrl.cpp|munga_l4/l4app.cpp +4af39f 4af3b0 17 4 0 4af3a0 bt/heat.cpp|bt/mechmppr.cpp +4dfeef 4e0000 273 0 0 bt_l4/btl4app.cpp|? diff --git a/tools/gapcensus.py b/tools/gapcensus.py new file mode 100644 index 0000000..23cd3b3 --- /dev/null +++ b/tools/gapcensus.py @@ -0,0 +1,302 @@ +#!/usr/bin/env python3 +"""gapcensus.py -- the #60 export gap census. + +Maps the Ghidra export's coverage of BTL4OPT.EXE's code section and inventories +every DARK region (bytes belonging to no indexed function), so "absence in the +export" claims can be checked against a known inventory instead of tripping +over gaps one dig at a time (reconstruction-gotchas #20). + +Layers: + 1. INDEX coverage -- reference/decomp/functions_index.tsv (addr+size) vs the + PE .text extent -> raw dark regions. + 2. EXPORT coverage -- /* @ADDR */ headers in reference/decomp/all/part_*.c; + indexed-but-unexported = Ghidra knew the function but + the pseudocode is absent (decompile failure/filter). + 3. DISCOVERY -- function starts inside dark regions, from E8 call + targets + data-section code pointers (vtables/handler + tables/performance pointers), with caller counts. + 4. ANNOTATION -- nearest TU attribution (file= tags), and "VISITED" + flags for addresses already cited anywhere in the + port/KB (game/, context/, docs/, CLASSMAP). + +Output: reference/decomp/GAP_CENSUS.md (+ gap_census.tsv, machine-readable). +Deterministic: re-runs diff cleanly. +""" +import glob +import os +import re +import struct +import sys + +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +EXE = os.path.join(ROOT, 'content', 'BTL4OPT.EXE') +IDX = os.path.join(ROOT, 'reference', 'decomp', 'functions_index.tsv') +PARTS = os.path.join(ROOT, 'reference', 'decomp', 'all', 'part_*.c') +OUT_MD = os.path.join(ROOT, 'reference', 'decomp', 'GAP_CENSUS.md') +OUT_TSV = os.path.join(ROOT, 'reference', 'decomp', 'gap_census.tsv') + +MIN_REGION = 16 # ignore alignment slivers below this many bytes +TOP_REGIONS = 40 # detail table size + + +def pe_sections(data): + e_lfanew = struct.unpack_from(' 0] + + # ---- layer 1: the index ------------------------------------------------ + index = {} # addr -> (size, name) + for line in open(IDX, encoding='utf-8', errors='replace'): + f = line.rstrip('\n').split('\t') + if len(f) < 4: + continue + try: + a = int(f[0], 16) + sz = int(f[1]) + except ValueError: + continue + index[a] = (sz, f[3]) + idx_sorted = sorted(index) + + covered = [] # merged [lo,hi) intervals + for a in idx_sorted: + sz = index[a][0] + lo, hi = a, a + max(sz, 1) + if covered and lo <= covered[-1][1]: + covered[-1][1] = max(covered[-1][1], hi) + else: + covered.append([lo, hi]) + + dark = [] # [lo,hi) uncovered in .text + cur = tlo + for lo, hi in covered: + if lo > cur: + dark.append((cur, min(lo, thi))) + cur = max(cur, hi) + if cur >= thi: + break + if cur < thi: + dark.append((cur, thi)) + dark = [(lo, hi) for lo, hi in dark if hi - lo >= MIN_REGION] + + # ---- layer 2: the export ---------------------------------------------- + exported = {} # addr -> file tag + hdr = re.compile(r'/\* @(00[0-9a-f]{6}) file=(\S+) name=') + for p in sorted(glob.glob(PARTS)): + for m in hdr.finditer(open(p, encoding='utf-8', errors='replace').read()): + exported[int(m.group(1), 16)] = m.group(2) + unexported = [a for a in idx_sorted if a not in exported] + + # TU attribution anchors (file= != '?') + tagged = sorted((a, f) for a, f in exported.items() if f != '?') + + def nearest_tu(addr): + before = after = None + for a, f in tagged: + if a <= addr: + before = f + else: + after = f + break + if before and after and before == after: + return before + return '%s|%s' % (before or '?', after or '?') + + # ---- layer 3: discovery ------------------------------------------------ + callers = {} # target -> caller count + b = data + for off in range(t_raw, t_raw + (thi - tlo) - 5): + if b[off] == 0xE8: + rel = struct.unpack_from('= 2 + or va in dptr) + + # ---- layer 4: repo citations ------------------------------------------- + cite = set() + pat = re.compile(r'(?:@|FUN_|0x)0{0,2}(4[0-9a-f]{5})\b', re.I) + for base in ('game', 'context', 'docs'): + for dirpath, _dirs, files in os.walk(os.path.join(ROOT, base)): + for fn in files: + if not fn.lower().endswith(('.cpp', '.hpp', '.h', '.md')): + continue + try: + txt = open(os.path.join(dirpath, fn), encoding='utf-8', + errors='replace').read() + except OSError: + continue + for m in pat.finditer(txt): + cite.add(int(m.group(1), 16)) + + # ---- assemble region records ------------------------------------------- + regions = [] + for lo, hi in dark: + seg = b[va_off(lo):va_off(hi)] + padb = sum(1 for c in seg if c in (0xCC, 0x90, 0x00)) + starts = sorted(set( + [v for v in callers if lo <= v < hi and strong_start(v)] + + [v for v in dptr if lo <= v < hi])) + visited = sorted(v for v in + set(starts) | {a for a in cite if lo <= a < hi} + if lo <= v < hi and v in cite) + regions.append({ + 'lo': lo, 'hi': hi, 'size': hi - lo, 'code': (hi - lo) - padb, + 'starts': starts, + 'call_in': sum(callers.get(v, 0) for v in starts), + 'visited': visited, + 'tu': nearest_tu(lo), + }) + regions.sort(key=lambda r: (-r['code'], r['lo'])) + + text_bytes = thi - tlo + idx_bytes = sum(hi - lo for lo, hi in covered + if lo < thi) - max(0, covered[-1][1] - thi if covered else 0) + dark_bytes = sum(r['size'] for r in regions) + unexp_bytes = sum(index[a][0] for a in unexported) + + # ---- TSV ---------------------------------------------------------------- + with open(OUT_TSV, 'w', encoding='utf-8', newline='\n') as t: + t.write('lo\thi\tsize\tcode\tstarts\tcall_in\tvisited\ttu\n') + for r in regions: + t.write('%06x\t%06x\t%d\t%d\t%s\t%d\t%s\t%s\n' % ( + r['lo'], r['hi'], r['size'], r['code'], + ','.join('%06x' % v for v in r['starts']), + r['call_in'], + ','.join('%06x' % v for v in r['visited']), + r['tu'])) + + # ---- report ------------------------------------------------------------- + L = [] + A = L.append + A('# GAP CENSUS -- the export dark-region inventory (#60)') + A('') + A('Generated by `tools/gapcensus.py` (deterministic; re-run after any re-export).') + A('Machine-readable twin: `gap_census.tsv`.') + A('') + A('## Headline') + A('| Metric | Value |') + A('|---|---|') + A('| Code section (.text) | `0x%06x`-`0x%06x` (%d KB) |' % (tlo, thi, text_bytes // 1024)) + A('| Indexed functions (functions_index.tsv) | %d, covering %d KB (%.1f%%) |' + % (len(index), idx_bytes // 1024, 100.0 * idx_bytes / text_bytes)) + code_bytes = sum(r['code'] for r in regions) + A('| **RAW DARK (no indexed function at all)** | **%d regions >= %dB, %d KB (%.1f%%) -- %d KB REAL CODE after padding** |' + % (len(regions), MIN_REGION, dark_bytes // 1024, 100.0 * dark_bytes / text_bytes, + code_bytes // 1024)) + A('| Exported pseudocode functions (part_*.c) | %d |' % len(exported)) + A('| **Indexed but NOT exported** (Ghidra knew it; no pseudocode) | **%d functions, %d KB** |' + % (len(unexported), unexp_bytes // 1024)) + A('| Function starts discovered inside dark regions | %d (call-graph + data-pointer evidence) |' + % sum(len(r['starts']) for r in regions)) + A('') + A('Reading the tables: `visited` = the address is already cited somewhere in') + A('game/ context/ docs/ (a prior dig reached it); everything else is UNCHARTED.') + A('`tu` = nearest file-tagged export neighbors (`before|after` when they disagree).') + A('') + # dark code by TU family -- engine-source TUs matter less (we compile the + # real MUNGA/WinTesla source); bt/ + bt_l4/ dark is the reconstruction target. + fam = {} + for r in regions: + tus = set(t for t in r['tu'].replace('|', ' ').split() if t != '?') + cats = set() + for t in tus: + if t.startswith('bt/'): + cats.add('bt/ (GAME -- reconstruction target)') + elif t.startswith('bt_l4/'): + cats.add('bt_l4/ (GAME video/glue -- reconstruction target)') + elif t.startswith('munga_l4/'): + cats.add('munga_l4/ (engine L4 -- source in repo)') + elif t.startswith('munga/'): + cats.add('munga/ (engine core -- source in repo)') + else: + cats.add('other/unknown') + key = sorted(cats)[0] if len(cats) == 1 else 'BOUNDARY/mixed' + f = fam.setdefault(key, [0, 0]) + f[0] += 1 + f[1] += r['code'] + A('## Dark code by suspected TU family') + A('') + A('| Family | Regions | Real code bytes |') + A('|---|---|---|') + for k in sorted(fam, key=lambda k: -fam[k][1]): + A('| %s | %d | %d |' % (k, fam[k][0], fam[k][1])) + A('') + A('## Top %d dark regions by REAL CODE bytes (padding excluded)' % TOP_REGIONS) + A('') + A('| # | Range | Code bytes | Fn starts | Call-ins | Visited | Suspected TU |') + A('|---|---|---|---|---|---|---|') + for i, r in enumerate(regions[:TOP_REGIONS], 1): + A('| %d | `0x%06x`-`0x%06x` | %d | %d | %d | %s | %s |' % ( + i, r['lo'], r['hi'], r['code'], len(r['starts']), r['call_in'], + ('%d: ' % len(r['visited'])) + ' '.join('`%x`' % v for v in r['visited'][:4]) + + ('...' if len(r['visited']) > 4 else '') if r['visited'] else '-', + r['tu'])) + A('') + A('## Indexed-but-unexported functions (first 60 by address)') + A('') + A('These have index rows (address + size) but no pseudocode in `all/part_*.c` --') + A('decompile them individually (raw disasm or a targeted re-export) when a dig arrives.') + A('') + A('| Addr | Size | Index name | Cited in repo |') + A('|---|---|---|---|') + for a in unexported[:60]: + sz, nm = index[a] + A('| `0x%06x` | %d | %s | %s |' % (a, sz, nm, 'YES' if a in cite else '-')) + if len(unexported) > 60: + A('') + A('(+%d more -- see gap_census.tsv)' % (len(unexported) - 60)) + A('') + open(OUT_MD, 'w', encoding='utf-8', newline='\n').write('\n'.join(L)) + print('text %dKB indexed %.1f%% dark %d regions/%dKB unexported %d fns/%dKB' + % (text_bytes // 1024, 100.0 * idx_bytes / text_bytes, len(regions), + dark_bytes // 1024, len(unexported), unexp_bytes // 1024)) + print('wrote', OUT_MD) + print('wrote', OUT_TSV) + + +if __name__ == '__main__': + main()