"""D3 THE ANSWER: FUN_18013ec10 sets the veto byte.

The +0xd8 sub-object's constructor FUN_18010ea80 defaults its byte +0xa4 to 0
(`*(undefined1 *)(param_1 + 0x29) = 0`), and response+0xd8+0xa4 == response+0x17c
-- the byte that makes FUN_180174630 zero the tradingEnabled field.

The disp32 +0xa4 scan found exactly one non-copy-constructor WRITE in a parser:
0x18013f039 in FUN_18013ec10, encoded `83 f8 01 / 75 06 / 88 87 a4 00 00 00`
i.e. "if (x == 1) byte[rdi+0xa4] = al". Decompile FUN_18013ec10 in full, find the
atom that feeds it, and find its callers to confirm the base is response+0xd8.

CONTROL: FUN_1801129f0 is in the same scan and must turn out to be a
copy/assign of the same struct (it reads +0xa4 and writes +0xa4 from another
object), not a parser. If it is a parser the classification is wrong.
"""
import traceback

try:
    for label, a in [
        ("FUN_18013ec10  the parser that sets the veto byte", 0x18013EC10),
        ("FUN_1801129f0  CONTROL, expected copy/assign", 0x1801129F0),
    ]:
        src = dec(a, 600)
        print("=" * 78)
        print("### %s  @ %#x  len(src)=%d" % (label, a, len(src)))
        print("=" * 78)
        print(src)
        print()

    print("### callers of FUN_18013ec10")
    for frm, typ, fn, ent in xrefs_to(0x18013EC10):
        print("   from %#x %s in %s (%#x)" % (frm, typ, fn, ent))
    print("### absolute-pointer sites for FUN_18013ec10")
    for h in find_all((0x18013EC10).to_bytes(8, "little"), blocks=(".rdata", ".data")):
        print("   %#x" % h)
except Exception:
    traceback.print_exc()
