import ghidra.app.script.GhidraScript;
import ghidra.app.decompiler.DecompInterface;
import ghidra.app.decompiler.DecompileResults;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionManager;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolIterator;
import ghidra.util.task.ConsoleTaskMonitor;
import java.io.PrintWriter;
import java.io.FileWriter;

public class DumpDecompile extends GhidraScript {
    @Override
    public void run() throws Exception {
        String outPath = "/Users/stevethrobsdev/Desktop/" + currentProgram.getName().replace(".efi", "") + "_decompiled.txt";
        PrintWriter out = new PrintWriter(new FileWriter(outPath));

        out.println("Program: " + currentProgram.getName());
        out.println("Language: " + currentProgram.getLanguage().getLanguageID());
        out.println("Image base: " + currentProgram.getImageBase());
        out.println();

        out.println("==== Defined strings ====");
        for (ghidra.program.model.listing.Data d : currentProgram.getListing().getDefinedData(true)) {
            if (d.hasStringValue()) {
                out.println(d.getAddress() + "  " + d.getValue());
            }
        }

        out.println();
        out.println("==== Symbols/Exports ====");
        SymbolTable st = currentProgram.getSymbolTable();
        SymbolIterator symIter = st.getAllSymbols(false);
        while (symIter.hasNext()) {
            Symbol s = symIter.next();
            if (s.isExternalEntryPoint() || s.isGlobal()) {
                out.println(s.getAddress() + "  " + s.getName() + "  (" + s.getSymbolType() + ")");
            }
        }

        FunctionManager fm = currentProgram.getFunctionManager();
        out.println();
        out.println("Function count: " + fm.getFunctionCount());
        out.println("=====================================");

        DecompInterface decomp = new DecompInterface();
        decomp.openProgram(currentProgram);

        for (Function f : fm.getFunctions(true)) {
            out.println();
            out.println("---- Function: " + f.getName() + " @ " + f.getEntryPoint() + " ----");
            DecompileResults res = decomp.decompileFunction(f, 60, new ConsoleTaskMonitor());
            if (res != null && res.decompileCompleted()) {
                out.println(res.getDecompiledFunction().getC());
            } else {
                out.println("(decompile failed: " + (res != null ? res.getErrorMessage() : "null result") + ")");
            }
        }
        out.close();
        println("Wrote decompilation to " + outPath);
    }
}
