feat(phase-33): B5 Ghidra regenerability PROVEN — the RE work as text (config/ghidra/*.jsonl + ROSTER.md), six programs rebuilt from disc + symbol files + that file with PROOF PASS

- ImportAnnotations.java: the S86 OSGi-bundle blocker was 3 javac errors (Long->int unboxing x2, a nonexistent
  LocalVariableImpl ctor -> VariableStorage); "/undefined" resolves to DataType.DEFAULT (it lives in neither type
  manager — main's first proof passed the cmp with failed=13 because the plate-comment rows had set the same function
  comments); ghidra_rebuild.sh now dies unless the import printed failed=0 (R49), writes .proof markers
- ghidra_annotations_delta.py: analysis drift measured and encoded as three counted classes — Error/Analysis bookmarks;
  auto-named DEFAULT functions the rebuild did not create (29 in main's LINKED regions); auto-named rows lagging the curated
  symbol file (10 sep8 + 5 aug31, R15). Result: main 38 hand-authored rows (13 annotated fns incl. 3 the ELF does not
  define, 22 comments, 3 labels); resident/overlays/protos container rows only; the DB holds no hand-authored types
- controls (R39): mutated block row -> PROOF FAIL; synthetic comment/bookmark/label/signature round-trip -> PROOF PASS
  twice (idempotent); the filter keeps the synthetic rows and a hand-renamed name-only diff; fake failed=2 refused,
  resident re-proven; roster --check controls both ways
- proofs, all PASS failed=0: resident 65s, ov_SC01_077 169s, ov_SC06_018 173s, SLUS_007.26 210s, sep8 202s, aug31 206s
- tools/ghidra_roster.py -> config/ghidra/ROSTER.md (--check in tools-health, ignores the per-machine proof column)
- .claude/settings.json hooks $CLAUDE_PROJECT_DIR-relative; ghidra_mcp_start.sh is a silent exit 0 without Ghidra or
  the project (both controlled); SETUP P33 B5 section + 5 inventory rows + §2.8 (R21); CURRENT_PHASE log + checkpoint
This commit is contained in:
Drew T
2026-09-06 20:32:35 -06:00
parent bc37b257ee
commit 936d7d741c
16 changed files with 454 additions and 144 deletions
+9 -4
View File
@@ -104,7 +104,9 @@ public class ImportAnnotations extends GhidraScript {
}
String suffix = "";
if (cut >= 0) { base = spec.substring(0, cut).trim(); suffix = spec.substring(cut); }
DataType dt = dtm.getDataType(base);
// "/undefined" is Ghidra's DefaultDataType (DataType.DEFAULT) — the default return/param type of every
// analysis-created function; it lives in NEITHER data type manager (S87: 13 of main's 13 func rows failed on it).
DataType dt = (base.equals("/undefined") || base.equals("undefined")) ? DataType.DEFAULT : dtm.getDataType(base);
if (dt == null) dt = BuiltInDataTypeManager.getDataTypeManager().getDataType(base);
if (dt == null && !base.startsWith("/")) dt = dtm.getDataType("/" + base);
if (dt == null) throw new IllegalArgumentException("unresolvable type " + spec);
@@ -202,7 +204,7 @@ public class ImportAnnotations extends GhidraScript {
try {
if (spec.startsWith("Stack[")) {
int j = spec.indexOf(']');
int off = (int) Long.decode(spec.substring(6, j));
int off = Long.decode(spec.substring(6, j)).intValue();
int size = Integer.parseInt(spec.substring(spec.lastIndexOf(':') + 1));
return new VariableStorage(currentProgram, off, size);
}
@@ -277,8 +279,11 @@ public class ImportAnnotations extends GhidraScript {
}
Variable nv;
if (storage.startsWith("Stack[")) {
int off = (int) Long.decode(storage.substring(6, storage.indexOf(']')));
nv = new LocalVariableImpl(s(l, "name"), first, lt, off, currentProgram);
// stack local: "Stack[-0x10]:4" -> VariableStorage(program, offset, size); the (String,int,DataType,int,Program)
// ctor does not exist in Ghidra 12.1 (the S86 OSGi-bundle blocker)
VariableStorage vs = storageOf(storage);
if (vs == null) { skippedStorage++; continue; }
nv = new LocalVariableImpl(s(l, "name"), first, lt, vs, currentProgram);
} else {
String rn = storage.contains(":") ? storage.substring(0, storage.indexOf(':')) : storage;
Register r = currentProgram.getRegister(rn);