// Full decompile: every function (sharded), vtable recovery, and assert-based file attribution. // Outputs to decomp/recovered/: all/part_NNN.c, functions_index.tsv, vtables.tsv import ghidra.app.script.GhidraScript; import ghidra.app.decompiler.*; import ghidra.program.model.address.*; import ghidra.program.model.listing.*; import ghidra.program.model.mem.*; import ghidra.program.model.symbol.*; import java.io.*; import java.util.*; public class ExportAll extends GhidraScript { public void run() throws Exception { File outDir = new File("C:\\git\\nick-games\\decomp\\recovered"); outDir.mkdirs(); File allDir = new File(outDir, "all"); allDir.mkdirs(); FunctionManager fm = currentProgram.getFunctionManager(); ReferenceManager rm = currentProgram.getReferenceManager(); Listing listing = currentProgram.getListing(); Memory mem = currentProgram.getMemory(); // 1) attribute functions to source files via embedded assert paths Map funcFile = new HashMap<>(); DataIterator di = listing.getDefinedData(true); while (di.hasNext() && !monitor.isCancelled()) { Data d = di.next(); if (d == null || !d.hasStringValue()) continue; Object v = d.getValue(); if (v == null) continue; String s = v.toString().toLowerCase().replace('/', '\\'); if (!s.contains("\\tesla_bt\\")) continue; if (!(s.endsWith(".cpp") || s.endsWith(".hpp"))) continue; String file = s.substring(s.lastIndexOf('\\') + 1); String dir = s.contains("\\bt_l4\\") ? "bt_l4" : s.contains("\\bt\\") ? "bt" : s.contains("\\munga_l4\\") ? "munga_l4" : "munga"; String tag = dir + "/" + file; for (Reference ref : rm.getReferencesTo(d.getAddress())) { Function f = fm.getFunctionContaining(ref.getFromAddress()); if (f != null) funcFile.put(f.getEntryPoint().getOffset(), tag); } } println("attributed functions: " + funcFile.size()); // 2) vtable recovery: runs of >=3 consecutive pointers to function entries in data memory PrintWriter vt = new PrintWriter(new FileWriter(new File(outDir, "vtables.tsv"))); int vtCount = 0; for (MemoryBlock b : mem.getBlocks()) { if (!b.isInitialized() || b.isExecute()) continue; Address a = b.getStart(), end = b.getEnd(); List run = new ArrayList<>(); Address runStart = null; while (a.compareTo(end) < 0 && !monitor.isCancelled()) { long val; try { val = mem.getInt(a) & 0xffffffffL; } catch (Exception ex) { break; } Function f = null; try { f = fm.getFunctionAt(a.getNewAddress(val)); } catch (Exception ex) {} if (f != null) { if (run.isEmpty()) runStart = a; run.add(val); } else { if (run.size() >= 3) { writeVt(vt, runStart, run); vtCount++; } run.clear(); } a = a.add(4); } if (run.size() >= 3) { writeVt(vt, runStart, run); vtCount++; } } vt.close(); println("vtables recovered: " + vtCount); // 3) decompile ALL functions, sharded 400/file DecompInterface dec = new DecompInterface(); dec.openProgram(currentProgram); PrintWriter idx = new PrintWriter(new FileWriter(new File(outDir, "functions_index.tsv"))); FunctionIterator it = fm.getFunctions(true); int count = 0, shard = 0; PrintWriter out = null; while (it.hasNext() && !monitor.isCancelled()) { Function f = it.next(); if (count % 400 == 0) { if (out != null) out.close(); out = new PrintWriter(new FileWriter(new File(allDir, String.format("part_%03d.c", shard++)))); } count++; long off = f.getEntryPoint().getOffset(); String tag = funcFile.getOrDefault(off, "?"); idx.println(Long.toHexString(off) + "\t" + f.getBody().getNumAddresses() + "\t" + tag + "\t" + f.getName()); try { DecompileResults r = dec.decompileFunction(f, 45, monitor); out.println("/* @" + f.getEntryPoint() + " file=" + tag + " name=" + f.getName() + " */"); if (r != null && r.decompileCompleted() && r.getDecompiledFunction() != null) out.println(r.getDecompiledFunction().getC()); else out.println("// "); out.println(); } catch (Exception ex) { out.println("// \n"); } if (count % 500 == 0) println("decompiled " + count + " ..."); } if (out != null) out.close(); idx.close(); dec.dispose(); println("DONE. total functions: " + count + " (shards: " + shard + ")"); } void writeVt(PrintWriter vt, Address start, List run) { StringBuilder sb = new StringBuilder(start.toString()); for (Long v : run) sb.append("\t").append(Long.toHexString(v)); vt.println(sb.toString()); } }