"""HYPOTHESIS: model+0x1fd2e (IS_TRADING_ENABLED) reads 0 either because the
constructor defaults it to 0 (never set) or because FUN_18011dc50 ran and wrote 0.
The disp32 scan found only 2 sites for 0x1fd2e, so the constructor must initialise
it as part of a WIDER store (qword/xmm) whose displacement is lower. Find the model
constructor via rip-refs to vtable 0x18021c2a0 and read the initialising store.
CONTROL: +0x1fd3a/+0x1fd3d read 1 live; whatever store covers them must produce 1,
so the same store decoded for 0x1fd2e is trustworthy.
ALSO: locate the transfer-market refusal path (route literal, CARDS_CB_ERR_* xrefs).
"""
import traceback, struct
try:
    VT = 0x18021c2a0
    print("=== A. xrefs to model vtable %#x ===" % VT)
    for frm, typ, fn, ent in xrefs_to(VT):
        print("  %#x %-14s %-40s ent=%#x" % (frm, typ, fn, ent))

    print("\n=== B. disp32 scan .text for displacements 0x1fd00..0x1fd60 ===")
    tb = None
    for b in mem.getBlocks():
        if b.getName() == ".text":
            tstart = int(b.getStart().getOffset())
            tlen = int(b.getEnd().getOffset()) - tstart + 1
            tb = read_bytes(tstart, tlen)
    print("  .text len =", len(tb))
    hitmap = {}
    for disp in range(0x1fd00, 0x1fd60):
        pat = struct.pack("<i", disp)
        i = tb.find(pat)
        while i != -1:
            hitmap.setdefault(disp, []).append(tstart + i)
            i = tb.find(pat, i + 1)
    for disp in sorted(hitmap):
        for a in hitmap[disp]:
            f = fm.getFunctionContaining(addr(a))
            print("  disp +%#07x at %#x  in %s  bytes=%s" % (
                disp, a, f.getName() if f else "?",
                read_bytes(a - 4, 14).hex(" ")))

    print("\n=== C. transfermarket route literal ===")
    for pat in [b"/transfermarket", b"transfermarket", b"TransferMarket",
                b"tradepile", b"watchlist", b"TRANSFER_MARKET"]:
        hits = find_all(pat)
        print("  %-20s %d hits: %s" % (pat.decode(), len(hits), [hex(h) for h in hits[:8]]))

    print("\n=== D. CARDS_CB_ERR_* literals and xrefs ===")
    for a in find_all(b"CARDS_CB_ERR_"):
        s = rd_str(a, 80)
        if "UNAVAIL" in s or "TRAD" in s or "MARKET" in s or "OFFLINE" in s or "CONN" in s:
            xr = xrefs_to(a)
            print("  %#x %-42s xrefs=%s" % (a, s, [(hex(x[0]), x[2]) for x in xr]))
except Exception:
    traceback.print_exc()
