// Deep inspect FUN_800540AA — likely cruise routine
//@category Analysis

import java.util.ArrayList;
import java.util.List;
import ghidra.app.script.GhidraScript;
import ghidra.app.decompiler.DecompInterface;
import ghidra.app.decompiler.DecompileResults;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionManager;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.listing.InstructionIterator;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.ReferenceIterator;
import ghidra.program.model.symbol.ReferenceManager;

public class InspectFunc2 extends GhidraScript {

    private List<Reference> collect(ReferenceManager refMgr, Address a) {
        List<Reference> list = new ArrayList<>();
        ReferenceIterator it = refMgr.getReferencesTo(a);
        while (it.hasNext()) list.add(it.next());
        return list;
    }

    @Override
    public void run() throws Exception {
        AddressFactory af = currentProgram.getAddressFactory();
        FunctionManager fm = currentProgram.getFunctionManager();
        Listing listing = currentProgram.getListing();
        ReferenceManager refMgr = currentProgram.getReferenceManager();

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

        Address fAddr = af.getAddress("800540aa");
        Function func = fm.getFunctionAt(fAddr);
        if (func == null) {
            println("Function 0x800540AA not found, looking for function CONTAINING that address...");
            Address ctx = af.getAddress("80054118");
            func = fm.getFunctionContaining(ctx);
        }
        if (func == null) { println("Still nothing"); return; }

        println("================================================================");
        println(String.format("FUNCTION %s at 0x%s  body=0x%X",
                func.getName(), func.getEntryPoint(), func.getBody().getNumAddresses()));
        println("================================================================");

        // Full instruction listing
        println("--- ALL INSTRUCTIONS ---");
        InstructionIterator it = listing.getInstructions(func.getBody(), true);
        while (it.hasNext()) {
            Instruction ins = it.next();
            String s = ins.toString();
            // Highlight relevant instructions
            String marker = "";
            if (s.contains("#0x1e") || s.contains("#0x1E")) marker = "  ← CRUISE BYTE READ!";
            if (s.contains("#0x2") && !s.contains("#0x20") && !s.contains("#0x21") && !s.contains("#0x22") &&
                !s.contains("#0x23") && !s.contains("#0x24") && !s.contains("#0x25") && !s.contains("#0x26") &&
                !s.contains("#0x27") && !s.contains("#0x28") && !s.contains("#0x29")) {
                // catch #0x2c etc
            }
            println(String.format("  0x%s: %s%s", ins.getAddress(), s, marker));
        }

        // Decompile
        println("\n--- DECOMPILED ---");
        DecompileResults res = decomp.decompileFunction(func, 90, monitor);
        if (res.decompileCompleted()) {
            println(res.getDecompiledFunction().getC());
        } else {
            println("Decompile failed: " + res.getErrorMessage());
        }

        // Callers
        println("--- CALLERS ---");
        List<Reference> callers = collect(refMgr, func.getEntryPoint());
        for (Reference r : callers) {
            Address from = r.getFromAddress();
            Function caller = fm.getFunctionContaining(from);
            String cname = (caller != null) ? caller.getName() : "<no-func>";
            String cent = (caller != null) ? caller.getEntryPoint().toString() : "n/a";
            Instruction ins = listing.getInstructionAt(from);
            String insStr = (ins != null) ? ins.toString() : "<no-ins>";
            println(String.format("  caller 0x%s in [%s @ 0x%s]  insn=%s",
                    from, cname, cent, insStr));
        }

        decomp.dispose();
        println("\nDONE");
    }
}
