"""DIMENSION 4, pass 9: three of the manager vtable slots resolved from live
memory land on addresses Ghidra never turned into functions
(0x1801180a0 vt+0xc0, 0x18011b500 vt+0x7d8, 0x18011b780 vt+0x160). Disassemble
and create them, then decompile.

CONTROL: 0x18011b780 and 0x18011b500 must come out as tiny getters (the callers
treat the result as an object whose +0x30 is a vector). If instead they decode
as garbage, the live vtable read (or these addresses) is wrong.

Also: FUN_1800515e0 is the item copy/assign called by the item registration
(vt+0xa08 = FUN_18011cca0) -- it should copy the duplicate field at +0x10, which
independently confirms +0x10 is a member of the item record rather than of a
list node.
"""
import traceback

OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/store/dup9_out.txt"

def w(fh, s=""):
    fh.write(str(s) + "\n")

try:
    fh = open(OUT, "w")
    for a in (0x1801180A0, 0x18011B500, 0x18011B780):
        try:
            flat.disassemble(addr(a))
        except Exception as e:
            w(fh, "disassemble(%#x) -> %s" % (a, e))
        try:
            f = flat.createFunction(addr(a), None)
            w(fh, "createFunction(%#x) -> %s" % (a, f))
        except Exception as e:
            w(fh, "createFunction(%#x) -> %s" % (a, e))

    for a, lbl in ((0x18011B780, "vt+0x160"), (0x18011B500, "vt+0x7d8"),
                   (0x1801180A0, "vt+0x0c0 THE CALL ON THE NOT-DUPLICATE BRANCH"),
                   (0x1800515E0, "item copy/assign FUN_1800515e0")):
        s = dec(a)
        w(fh, "")
        w(fh, "#" * 70)
        w(fh, "# %s  %#x  len(src)=%d  FULL" % (lbl, a, len(s)))
        w(fh, "#" * 70)
        w(fh, s)

    # callees of the vt+0xc0 target, once it is a function
    w(fh, "")
    w(fh, "=== callees of 0x1801180a0 ===")
    f = func(0x1801180A0)
    seen = []
    if f is not None:
        it = listing.getInstructions(f.getBody(), True)
        while it.hasNext():
            ins = it.next()
            for r in ins.getReferencesFrom():
                t = int(r.getToAddress().getOffset())
                g = fm.getFunctionAt(addr(t))
                if g is not None and t not in seen:
                    seen.append(t)
                    w(fh, "   %#x %s" % (t, g.getName()))
    for t in seen:
        s = dec(t)
        w(fh, "")
        w(fh, "-" * 70)
        w(fh, "-- callee %#x len(src)=%d FULL" % (t, len(s)))
        w(fh, "-" * 70)
        w(fh, s)

    fh.close()
    print("WROTE", OUT)
except Exception:
    traceback.print_exc()
