Files
tdkpin/original/tools/recover_win16_imports.py
ddidderr 8b99e9607c feat(reconstruction): complete binary-backed C recovery
Replace the partial mechanics transcriptions with a separate, readable C11
reconstruction of the complete Win16 image while preserving the original raw
Ghidra export as immutable evidence. Cover all ordinary and overlapping entry
points, Borland runtime behavior, Win16 imports, segmented data, callbacks,
resources, indirect control flow, physics, rendering, persistence, and
startup/shutdown lifecycles.

Add deterministic extraction and audit tooling plus address-linked ledgers for
functions, imports, DGROUP ranges and objects, relocations, resources, and
callbacks. The final gate records zero raw, partial, restored, unknown,
blocked, or unclassified required units. Keep the semantic-fidelity boundary
explicit: the portable C is not claimed to reproduce a byte-identical Borland
NE build.

Add strict focused harnesses for every reconstructed C unit, exact resource
round-trip checks, and a 16-bit Borland Real48 reference probe. No Rust source
or Cargo metadata is changed in this phase.

Test Plan:
- `bash original/tools/test_reconstructed_c.sh` -- passed
- `bash original/tools/probe_real48_reference.sh` -- passed bit-for-bit
- `python3 original/tools/audit_reconstruction.py --require-complete` -- passed
- `git diff --cached --check` -- passed
- `git diff HEAD -- '*.rs' Cargo.toml Cargo.lock` -- empty
2026-08-23 16:41:17 +02:00

197 lines
7.1 KiB
Python
Executable File

#!/usr/bin/env python3
"""Populate the import ledger from Wine 11.15 Win16 specs and target evidence."""
from __future__ import annotations
import csv
import hashlib
import re
import urllib.request
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
LEDGER = ROOT / "IMPORT_RECONSTRUCTION.tsv"
WINE_TAG = "wine-11.15"
WINE_BASE = f"https://gitlab.winehq.org/wine/wine/-/raw/{WINE_TAG}"
SPEC_SOURCES = {
"USER": (
"dlls/user.exe16/user.exe16.spec",
"d873fa88079c4f922cbba2fb3a75f40e2ff23b4d56434b0f4326169397539e32",
),
"GDI": (
"dlls/gdi.exe16/gdi.exe16.spec",
"3bd84b26a9d4b7aa91a9114d0a46dc13e4d6fcd71290120afdd9b7cfaffe76ab",
),
"KERNEL": (
"dlls/krnl386.exe16/krnl386.exe16.spec",
"8d799b701d1cf16d4e882b5e354dc6e357056d4adcd83e629571dc4b33b02075",
),
"MMSYSTEM": (
"dlls/mmsystem.dll16/mmsystem.dll16.spec",
"31e54179db61fa95a1d90a9a230d2ae5afb6013ba37ae54e78990d1795694a73",
),
"KEYBOARD": (
"dlls/keyboard.drv16/keyboard.drv16.spec",
"ca9a9e697e9afe0baf5cff7099ebb442169f36fa05293e78a0bb50fbefaa096d",
),
}
SPEC_FUNCTION = re.compile(
r"^\s*(?P<ordinal>\d+)\s+"
r"(?P<kind>pascal|cdecl|varargs|stub|register)"
r"(?P<flags>(?:\s+-\S+)*)\s+"
r"(?P<name>[A-Za-z0-9_@]+)\((?P<arguments>[^)]*)\)"
)
SPEC_EQUATE = re.compile(
r"^\s*(?P<ordinal>\d+)\s+equate\s+(?P<name>[A-Za-z0-9_@]+)\s+(?P<value>\S+)"
)
def fetch_specs() -> dict[str, tuple[str, list[str]]]:
specs = {}
for library, (path, expected_digest) in SPEC_SOURCES.items():
url = f"{WINE_BASE}/{path}"
with urllib.request.urlopen(url, timeout=30) as response:
payload = response.read()
digest = hashlib.sha256(payload).hexdigest()
if digest != expected_digest:
raise RuntimeError(
f"Wine source drift for {path}: expected {expected_digest}, got {digest}"
)
specs[library] = (url, payload.decode("utf-8").splitlines())
return specs
def parse_specs(
specs: dict[str, tuple[str, list[str]]],
) -> dict[tuple[str, str], dict[str, str]]:
declarations = {}
for library, (url, lines) in specs.items():
for line_number, line in enumerate(lines, 1):
match = SPEC_FUNCTION.match(line)
if match:
name = match.group("name")
flags = match.group("flags").strip()
kind = match.group("kind")
prefix = f"{kind}16"
if flags:
prefix += f" {flags}"
declaration = f"{prefix} {name}({match.group('arguments').strip()})"
declarations[(library, name.upper())] = {
"prototype": declaration,
"evidence": f"Wine {WINE_TAG} {url}#L{line_number}",
"notes": (
f"Wine Win16 ordinal {match.group('ordinal')}; "
"every TDKPIN call site still requires argument-level review."
),
"status": "partial",
"stage": "prototype-sourced",
}
continue
match = SPEC_EQUATE.match(line)
if match:
name = match.group("name")
declarations[(library, name.upper())] = {
"prototype": f"equate16 {name} = {match.group('value')}",
"evidence": f"Wine {WINE_TAG} {url}#L{line_number}",
"notes": (
f"Wine Win16 ordinal {match.group('ordinal')}; this is runtime data, "
"not a callable function."
),
"status": "verified",
"stage": "runtime-data",
}
return declarations
def recover_special_declarations(
declarations: dict[tuple[str, str], dict[str, str]],
) -> None:
keyboard_url = f"{WINE_BASE}/{SPEC_SOURCES['KEYBOARD'][0]}"
declarations[("KEYBOARD", "ORDINAL_5")] = {
"prototype": "pascal16 -ret16 AnsiToOem(str ptr)",
"evidence": f"Wine {WINE_TAG} {keyboard_url}#L5",
"notes": "Imported by ordinal; Wine identifies ordinal 5 as AnsiToOem.",
"status": "partial",
"stage": "prototype-sourced",
}
declarations[("KEYBOARD", "ORDINAL_6")] = {
"prototype": "pascal16 -ret16 OemToAnsi(str ptr)",
"evidence": f"Wine {WINE_TAG} {keyboard_url}#L6",
"notes": "Imported by ordinal; Wine identifies ordinal 6 as OemToAnsi.",
"status": "partial",
"stage": "prototype-sourced",
}
declarations[("MMTIMER", "SYSTEMTIMERMAKE")] = {
"prototype": (
"pascal16 -ret16 SystemTimerMake("
"HWND16 recipient, word delay_ms, word resolution_ms, word one_shot)"
),
"evidence": (
"MMTIMER.DLL 1000:0039 disassembly; export ordinal 1; "
"f1d9ac980c7bfba5dc53eaa9e7cb2c3cd9b82f879ee8962ad40bf863d641bb49"
),
"notes": (
"Binary-reviewed wrapper around timeSetEvent16: it installs MMTIMER 1000:0002, "
"posts message 0x0580 to recipient, and returns the multimedia timer id."
),
"status": "verified",
"stage": "binary-reviewed",
}
def main() -> int:
with LEDGER.open(newline="", encoding="utf-8") as handle:
reader = csv.DictReader(handle, delimiter="\t")
columns = list(reader.fieldnames or ())
rows = list(reader)
if "stage" not in columns:
columns.insert(columns.index("status") + 1, "stage")
declarations = parse_specs(fetch_specs())
recover_special_declarations(declarations)
import_keys = {(row["library"], row["import_name"].upper()) for row in rows}
missing = sorted(import_keys - set(declarations))
if missing:
raise RuntimeError(f"no Win16 declaration for: {missing}")
for row in rows:
recovered = declarations[(row["library"], row["import_name"].upper())]
preserve_review = row.get("stage") not in {
"",
"untyped-import",
"prototype-sourced",
"runtime-data",
"binary-reviewed",
}
preserved = (
{key: row.get(key, "") for key in ("status", "stage", "evidence", "notes")}
if preserve_review
else None
)
row.update(recovered)
if preserved:
row.update(preserved)
temporary = LEDGER.with_suffix(LEDGER.suffix + ".tmp")
with temporary.open("w", newline="", encoding="utf-8") as handle:
writer = csv.DictWriter(
handle, fieldnames=columns, delimiter="\t", lineterminator="\n"
)
writer.writeheader()
writer.writerows(rows)
temporary.replace(LEDGER)
statuses = {}
for row in rows:
statuses[row["status"]] = statuses.get(row["status"], 0) + 1
print(f"updated_import_slots={len(rows)}")
print(
f"unique_declarations={len({(row['library'], row['import_name']) for row in rows})}"
)
print("statuses=" + ",".join(f"{key}:{statuses[key]}" for key in sorted(statuses)))
return 0
if __name__ == "__main__":
raise SystemExit(main())