"""Find concrete siblings of the live notifier listener's abstract vtable."""

import struct

VTABLE = 0x1801ED6D0
DTOR = 0x180018EF0
PURECALL_THUNK = 0x1801C577A

print("=== exact vtable references ===")
for row in xrefs_to(VTABLE):
    print(row)

print("\n=== vtables sharing the live listener destructor ===")
for hit in find_all(struct.pack("<Q", DTOR), blocks=(".rdata", ".data")):
    try:
        slots = [qword(hit + i * 8) for i in range(12)]
    except Exception:
        continue
    # Require the same broad interface shape: destructor in slot 0 and at least
    # one CardsDLL code pointer after it. This filters incidental data matches.
    if slots[0] != DTOR or not any(0x180000000 <= x < 0x1801E5000 for x in slots[1:]):
        continue
    print("vtable=%#x slot8=%#x %s" %
          (hit, slots[1], "PURE" if slots[1] == PURECALL_THUNK else "CONCRETE"))
    for i, target in enumerate(slots):
        print("  +%#04x %#x %s" % (i * 8, target, fname(target)))
    refs_here = xrefs_to(hit)
    if refs_here:
        print("  refs:", refs_here)
