"""BATCH 8: the two GUID-returning stubs are undefined functions. Read them as raw
instructions and find the vtable that holds them. CONTROL: both stubs must decode to
'mov eax, <guid>; ret' -- if they do not, my reading of them as interface-id getters
is wrong and I say so."""
import traceback, struct
OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/cards/adv2/q8_raw.txt"
try:
    f = open(OUT, "w")
    def P(*a): f.write(" ".join(str(x) for x in a) + "\n")
    for lo, hi in ((0x1800E1650, 0x1800E1690), (0x180113F40, 0x180113F80)):
        P("### raw %#x..%#x" % (lo, hi))
        P("   bytes:", read_bytes(lo, hi - lo).hex())
        it = listing.getInstructions(addr(lo), True)
        while it.hasNext():
            i = it.next()
            a = int(i.getAddress().getOffset())
            if a >= hi: break
            P("   %#x  %s" % (a, i))
        P()
    for cand in (0x1800E1660, 0x180113F50, 0x180113F4C, 0x180113F40):
        hits = find_all(struct.pack("<Q", cand), blocks=(".rdata", ".data"))
        P("ptr8 to %#x : %s" % (cand, [hex(h) for h in hits]))
        for h in hits:
            start = h
            while True:
                try: v = qword(start - 8)
                except Exception: break
                if not (0x180001000 <= v < 0x1801E5000): break
                start -= 8
            base = start
            while qword(base) == 0x1801C577A: base += 8
            P("   run %#x, first non-stub %#x, this at +%#x from non-stub" % (start, base, h - base))
            for i in range(0, 100):
                v = qword(base + i * 8)
                if not (0x180001000 <= v < 0x1801E5000): break
                fn = fm.getFunctionAt(addr(v))
                if i*8 in (0x40, 0x270, 0x308, 0x290, 0x2b0, 0x148, 0xd0, 0x20):
                    P("      +%#05x %#x %s" % (i*8, v, fn.getName() if fn else ""))
            P("      table length: %#x" % (i*8))
    f.close(); print("WROTE", OUT)
except Exception:
    traceback.print_exc()
