Files
BFM-decomp/tools/ghidra_scripts/ExportSymbols.java
T

61 lines
3.5 KiB
Java

// ExportSymbols.java — headless, read-only: export all USER_DEFINED symbols (our manual RE work) to
// a committable text file, so the annotations are version-controlled / re-importable independent of the
// gitignored Ghidra .rep. This is the durable, diffable record of the symbols (sotn model; Phase-5 splat
// will consume/refine config/symbols.us.txt).
//
// analyzeHeadless ~/bfm-decomp/ghidra bfm -process SLUS_007.26 -noanalysis -readOnly \
// -scriptPath ~/bfm-decomp/tools/ghidra_scripts -postScript ExportSymbols.java
import ghidra.app.script.GhidraScript;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.SymbolType;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
public class ExportSymbols extends GhidraScript {
public void run() throws Exception {
SymbolTable st = currentProgram.getSymbolTable();
ArrayList<long[]> keys = new ArrayList<>(); // [addr]
ArrayList<String> lines = new ArrayList<>();
java.util.TreeMap<Long,String> rows = new java.util.TreeMap<>();
int n = 0;
for (Symbol s : st.getAllSymbols(true)) {
if (s.getSource() != SourceType.USER_DEFINED) continue;
if (s.isExternal()) continue;
long a = s.getAddress().getOffset();
// only KSEG0 program space (skip GTE/register-space user labels if any)
String kind = (s.getSymbolType() == SymbolType.FUNCTION) ? "func" : "data";
rows.put((a << 4) | (kind.equals("func") ? 0 : 1),
String.format("%-32s = 0x%08X; // %s", s.getName(), a, kind));
n++;
}
StringBuilder sb = new StringBuilder();
sb.append("// config/symbols.us.txt — USER_DEFINED symbols exported from the Ghidra project.\n");
sb.append("// Auto-generated by tools/ghidra_scripts/ExportSymbols.java; re-run to refresh.\n");
sb.append("// Durable text record of manual RE work (the .rep is gitignored). Phase-5 splat refines this.\n");
sb.append("// count=").append(n).append("\n\n");
for (String v : rows.values()) sb.append(v).append("\n");
// P33 B5 (rule R15): NEVER overwrite the curated config/symbols.us.txt — re-exporting is a reviewed
// re-merge. Arg 1 = output path (default .run/ghidra_export/<program>.symbols.txt under the CWD);
// an existing output is refused unless arg 2 is the literal `overwrite`.
String[] args = getScriptArgs();
java.nio.file.Path out = (args != null && args.length > 0) ? Paths.get(args[0])
: Paths.get(".run", "ghidra_export", currentProgram.getName() + ".symbols.txt");
boolean overwrite = args != null && args.length > 1 && "overwrite".equals(args[1]);
if (Files.exists(out) && !overwrite) {
println("BFMSYM REFUSED: " + out + " exists (pass `overwrite` as the 2nd arg; config/symbols*.txt is merged by hand, R15)");
return;
}
if (out.toAbsolutePath().normalize().toString().contains("/config/")) {
println("BFMSYM REFUSED: will not write into config/ (R15 — merge the export by hand): " + out);
return;
}
Files.createDirectories(out.toAbsolutePath().getParent());
Files.write(out, sb.toString().getBytes());
println("BFMSYM exported " + n + " USER_DEFINED symbols -> " + out);
}
}