"""HYPOTHESIS (Q3): the market refusal and the Seasons refusal are both taken BEFORE any
request is built, so the gate must sit in a caller of the request builder. Walking up
from the route literal "/transfermarket?..." and from the seasons route literals should
expose the predicate, and if the two chains share a callee that predicate is the shared
term.

CONTROL: the SAME walk is run for routes we KNOW the client does issue this session
(/item, /squad/). If the walk produces a plausible-looking "gate" for a route that
demonstrably fires, the walk proves nothing and I say so.

Form-independent: Ghidra refs AND a raw rip-relative disp32 scan over all of .text.
"""
import struct, traceback

try:
    ts = te = None
    for b in mem.getBlocks():
        if str(b.getName()) == ".text":
            ts, te = int(b.getStart().getOffset()), int(b.getEnd().getOffset())
    text = b""
    a = ts
    while a <= te:
        n = min(1 << 20, te - a + 1)
        text += read_bytes(a, n)
        a += n
    print("len(.text)=%d base=%#x" % (len(text), ts))

    def rip_refs(va):
        out = []
        for i in range(0, len(text) - 4):
            d = struct.unpack_from("<i", text, i)[0]
            if ts + i + 4 + d == va:
                out.append(ts + i)
        return out

    ROUTES = [
        ("MARKET", b"/transfermarket?type=%s&start=%d&num=%d\x00"),
        ("TRADEPILE", b"/tradepile\x00"),
        ("WATCHLIST", b"/watchlist\x00"),
        ("SEASONS_HIST", b"/season/user/history?type=online\x00"),
        ("CONTROL_ITEM", b"/item\x00"),
    ]
    for name, lit in ROUTES:
        print("\n" + "=" * 70)
        print("### ROUTE %s %r" % (name, lit))
        vas = find_all(lit, blocks=(".rdata", ".data"))
        print("  literal occurrences:", [hex(v) for v in vas])
        for v in vas:
            gx = xrefs_to(v)
            rr = rip_refs(v)
            print("  %#x ghidra_xrefs=%s" % (v, [(hex(x[0]), x[1], x[2]) for x in gx]))
            print("  %#x rip_disp_sites=%s" % (v, [hex(x) for x in rr[:12]]))
            fns = set()
            for site in rr:
                f = fm.getFunctionContaining(addr(site))
                if f:
                    fns.add((f.getName(), int(f.getEntryPoint().getOffset())))
            for fn, ent in sorted(fns):
                print("    in %s %#x" % (fn, ent))
                try:
                    cs = callers(ent)
                except Exception as e:
                    cs = []
                    print("      callers() err", e)
                for c in cs[:20]:
                    print("      <- ", c)
except Exception:
    traceback.print_exc()
