// Map the pointer table at 0x800A1220 to functions that use each entry.
//@category Analysis

import java.util.ArrayList;
import java.util.List;
import ghidra.app.script.GhidraScript;
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.Listing;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.ReferenceIterator;
import ghidra.program.model.symbol.ReferenceManager;

public class MapPointerTable 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();
        Listing listing = currentProgram.getListing();
        Memory mem = currentProgram.getMemory();
        ReferenceManager refMgr = currentProgram.getReferenceManager();
        FunctionManager fm = currentProgram.getFunctionManager();

        println("================================================================");
        println("POINTER TABLE ANALYSIS: 0x800A1220..0x800A1280");
        println("================================================================");

        // Dump the pointer table and find functions that reference each slot
        for (long slot = 0x800A1220L; slot < 0x800A1280L; slot += 4) {
            Address slotAddr = af.getAddress(Long.toHexString(slot));
            // Read pointer value (4 bytes LE)
            byte[] buf = new byte[4];
            try { mem.getBytes(slotAddr, buf); } catch (Exception e) { continue; }
            long ptr = (((long)(buf[0] & 0xFF))) |
                       (((long)(buf[1] & 0xFF)) << 8) |
                       (((long)(buf[2] & 0xFF)) << 16) |
                       (((long)(buf[3] & 0xFF)) << 24);

            // Find xrefs TO this slot
            List<Reference> refs = collect(refMgr, slotAddr);

            println(String.format("\nslot 0x%08X -> 0x%08X  (%d xrefs from code)",
                                  slot, ptr, refs.size()));
            for (Reference r : refs) {
                Address from = r.getFromAddress();
                Function func = fm.getFunctionContaining(from);
                String fname = (func != null) ? func.getName() : "<no-func>";
                String fent = (func != null) ? func.getEntryPoint().toString() : "n/a";
                Instruction ins = listing.getInstructionAt(from);
                String insStr = (ins != null) ? ins.toString() : "<no-ins>";
                println(String.format("    from 0x%s in func [%s @ 0x%s]  type=%s",
                        from, fname, fent, r.getReferenceType().getName()));
                println(String.format("      insn: %s", insStr));
            }
        }

        // Also: find xrefs TO the whole table base 0x800A1220 — that's where the loop indexes from
        println("\n=== xrefs TO table base 0x800A1220 ===");
        Address tbl = af.getAddress("800a1220");
        List<Reference> rb = collect(refMgr, tbl);
        for (Reference r : rb) {
            Address from = r.getFromAddress();
            Function func = fm.getFunctionContaining(from);
            String fname = (func != null) ? func.getName() : "<no-func>";
            String fent = (func != null) ? func.getEntryPoint().toString() : "n/a";
            Instruction ins = listing.getInstructionAt(from);
            String insStr = (ins != null) ? ins.toString() : "<no-ins>";
            println(String.format("  from 0x%s in func [%s @ 0x%s]  type=%s  insn=%s",
                    from, fname, fent, r.getReferenceType().getName(), insStr));
        }

        println("\n================================================================");
        println("DONE");
    }
}
