"""ADVERSARIAL BATCH 1.

HYPOTHESES UNDER ATTACK (all from another agent, assumed WRONG until reproduced):
 H1  item+0x49 = (untradeable == false), written by atom 0x361 in FUN_18013fe00.
 H2  FUN_1801a7260 (TO_TRADE_PILE) requires item+0x49 != 0, and the eight flags are
     ENABLE flags.
 H3  FUN_18003e370 publishes 8 names in the order DISCARD, MODIFY, TO_ACTIVE_SQUAD,
     TO_TRADE_PILE, ... and FUN_1800e2a40 fills those 8 bytes in that order.
 H4  item+0x54 is the discard LEVEL written at 0x180141e8a..0x180141ea3, not itemType.
 H5  the itemState table starts at 0x180229cc0 with 12 entries.
 H6  FUN_180166660 has exactly one caller.
 H7  FUN_1801a8620 (+0x38) and FUN_1801a8090 (+0x3c) have exactly one xref each.

CONTROL: for every "exactly one caller" claim I also run the SAME xrefs_to call on a
function that is known to have many callers (FUN_180135ff0, the value-SKIP, ~134) and
on the FNV hasher 0x180180d00, so a zero/one result cannot be a broken scan.
Everything is printed IN FULL; no truncation.
"""
import traceback, sys

OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/cards/adv2/q1_raw.txt"
try:
    f = open(OUT, "w")

    def P(*a):
        s = " ".join(str(x) for x in a)
        f.write(s + "\n")

    P("=" * 30, "CONTROL: xrefs machinery works", "=" * 30)
    for nm, a in (("FUN_180135ff0 value-SKIP", 0x180135FF0),
                  ("FUN_180180d00 FNV hasher", 0x180180D00),
                  ("FUN_1801c7620 BOOL prim", 0x1801C7620)):
        xr = xrefs_to(a)
        ents = sorted(set(e for _, t, _, e in xr if "CALL" in t and e))
        P("%s: %d refs, %d distinct calling funcs" % (nm, len(xr), len(ents)))

    P()
    P("=" * 30, "H7 discard getters", "=" * 30)
    for nm, a in (("FUN_1801a8620 (+0x38 DISCARD_CREDITS?)", 0x1801A8620),
                  ("FUN_1801a8090 (+0x3c CALCULATED?)", 0x1801A8090),
                  ("FUN_1801a80c0 (CARD_LEVEL?)", 0x1801A80C0)):
        P("---", nm)
        fn = fm.getFunctionAt(addr(a))
        P("   function at addr:", fn.getName() if fn else None)
        for frm, t, cf, e in xrefs_to(a):
            P("   ref %#x %s in %s@%#x" % (frm, t, cf, e))
        P("   BODY:")
        P(dec(a))

    P()
    P("=" * 30, "H6 FUN_180166660 callers", "=" * 30)
    for frm, t, cf, e in xrefs_to(0x180166660):
        P("   ref %#x %s in %s@%#x" % (frm, t, cf, e))
    P(dec(0x180166660))

    P()
    P("=" * 30, "H5 itemState table walk from 0x180229c00", "=" * 30)
    a = 0x180229C00
    for i in range(40):
        p = qword(a + i * 0x10)
        q = qword(a + i * 0x10 + 8)
        s = ""
        if 0x180000000 <= p < 0x181000000:
            try:
                s = rd_str(p, 60)
            except Exception:
                s = "?"
        P("  %#x  p=%#018x q=%#018x  %r" % (a + i * 0x10, p, q, s))

    P()
    P("=" * 30, "H2 TO_TRADE_PILE predicate + siblings", "=" * 30)
    for a in (0x1801A7260, 0x1801A8940, 0x1801A71C0, 0x1801A7210, 0x1801A7250,
              0x1801A7180, 0x1801A7320, 0x1801A71E0, 0x1801A8900, 0x1801A89F0):
        fn = fm.getFunctionAt(addr(a))
        P("### %#x %s  xrefs=%d" % (a, fn.getName() if fn else "NO FUNC", len(xrefs_to(a))))
        for frm, t, cf, e in xrefs_to(a):
            P("     ref %#x %s in %s@%#x" % (frm, t, cf, e))
        P(dec(a))
        P()

    P()
    P("=" * 30, "H3 publisher + filler, FULL", "=" * 30)
    for a in (0x18003E370, 0x1800E2A40):
        P("### %#x len-of-decompile follows" % a)
        d = dec(a)
        P("   len(src) =", len(d))
        P(d)
        P()

    P()
    P("=" * 30, "H4 level write at 0x180141e60..0x180141ec0 raw disasm", "=" * 30)
    ins = listing.getInstructions(addr(0x180141E40), True)
    n = 0
    while ins.hasNext() and n < 60:
        i = ins.next()
        if int(i.getAddress().getOffset()) > 0x180141EC0:
            break
        P("  %#x  %s" % (int(i.getAddress().getOffset()), i))
        n += 1

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