"""D3 FINAL: pin down response+0x17c, the byte that vetoes tradingEnabled.

The massinfo response ctor FUN_180173a50 constructs a sub-object at +0xd8 via
FUN_18010ea80. 0x17c - 0xd8 = 0xa4, so a deserializer handed base=+0xd8 would
reach it as [base+0xa4] (disp32 a4 00 00 00), which the earlier +0x17c scan could
not see. Scan for that displacement too, and decompile every sub-parser the
massinfo deserializer delegates to.

CONTROL for the 0xa4 scan: the same scan is run for 0x28 (the settings sub-struct
base, whose ctor FUN_18014e320 is known to write +0x1c and +0x28) -- if the
harness cannot see a displacement it is known to contain, its absences are void.
Second control: FUN_18010ea80 must show writes consistent with a ~0xb0-byte
object, otherwise +0xd8 is not the parent of +0x17c and the arithmetic is wrong.
"""
import traceback

try:
    TEXT_LO, TEXT_HI = 0x180001000, 0x1801e5000
    text = read_bytes(TEXT_LO, TEXT_HI - TEXT_LO)

    def dispscan(disp):
        pat = int(disp).to_bytes(4, "little")
        out, i = [], text.find(pat)
        while i != -1:
            va = TEXT_LO + i
            f = fm.getFunctionContaining(addr(va))
            out.append((va, f.getName() if f else "?",
                        int(f.getEntryPoint().getOffset()) if f else 0,
                        text[max(0, i - 8):i + 8].hex()))
            i = text.find(pat, i + 1)
        return out

    print("### disp32 +0xa4 sites in the 0x18010e000-0x180180000 band")
    for va, nm, ent, ctx in dispscan(0xA4):
        if 0x18010E000 <= va < 0x180180000:
            print("    %#x  %-24s (%#x)  ctx=%s" % (va, nm, ent, ctx))

    for label, a in [
        ("FUN_18010ea80  ctor of the +0xd8 sub-object", 0x18010EA80),
        ("FUN_180142470  userData(0x36d) parser", 0x180142470),
        ("FUN_18013adb0  pileSizeClientData(0x227) parser -> +0xc8", 0x18013ADB0),
        ("FUN_180139610  arm 0x10c helper", 0x180139610),
        ("FUN_180174160  arm 0x339 parser -> +0x200", 0x180174160),
        ("FUN_18013a1c0  arm 0x19a", 0x18013A1C0),
        ("FUN_18013bd40  arm 0x263", 0x18013BD40),
    ]:
        src = dec(a)
        print("=" * 78)
        print("### %s  @ %#x  len(src)=%d" % (label, a, len(src)))
        print("=" * 78)
        print(src)
except Exception:
    traceback.print_exc()
