"""Read one pagemap entry on Linux; this is not an atomic memory snapshot."""

import ctypes
import os
import sys

ENTRY_BYTES = 8
PFN_MASK = (1 << 55) - 1


def read_u64(path, index):
    if index < 0:
        raise ValueError("negative entry index")
    with open(path, "rb", buffering=0) as stream:
        stream.seek(index * ENTRY_BYTES)
        raw = stream.read(ENTRY_BYTES)
    if len(raw) != ENTRY_BYTES:
        raise EOFError("incomplete 64-bit entry")
    return int.from_bytes(raw, sys.byteorder)


def main():
    page_size = os.sysconf("SC_PAGE_SIZE")
    buffer = ctypes.create_string_buffer(page_size)
    buffer[0] = b"A"
    address = ctypes.addressof(buffer)
    entry = read_u64("/proc/self/pagemap", address // page_size)
    present = bool(entry & (1 << 63))
    swapped = bool(entry & (1 << 62))
    print(f"address={address:#x} present={present} swapped={swapped}")
    print(f"soft_dirty={bool(entry & (1 << 55))}")
    print(f"exclusive={bool(entry & (1 << 56))}")
    if swapped:
        print(f"swap_type={entry & 31} swap_offset={(entry >> 5) & ((1 << 50) - 1)}")
        return
    if not present:
        return
    pfn = entry & PFN_MASK
    if pfn == 0:
        print("PFN is zero: it may be hidden; no physical-page lookup attempted.")
        return
    print(f"pfn={pfn}")
    for path in ("/proc/kpagecount", "/proc/kpageflags"):
        try:
            value = read_u64(path, pfn)
        except (OSError, EOFError) as error:
            print(f"{path}: unavailable ({error})")
        else:
            print(f"{path}: {value:#x}")


if __name__ == "__main__":
    main()
