from __future__ import annotations
import xml.etree.ElementTree
import glob
import os


def parse_gdb_xml_file(fname):
    assert fname.endswith("-linux.xml")
    tree = xml.etree.ElementTree.parse(fname)
    syscalls = tree.findall("syscall")
    return {int(e.attrib["number"]): e.attrib["name"] for e in syscalls}


def parse_unistd_include_header(header_path):
    with open(header_path) as f:
        lines = [l.strip() for l in f.read().strip().split("\n") if "__NR_" in l]
        syscalls = {}
        for l in lines:
            spl = l.split()
            assert spl[0] == "#define"
            assert spl[1].startswith("__NR_")
            name = spl[1][len("__NR_") :]
            nr = int(spl[2])
            syscalls[nr] = name
        return syscalls


def dump_mapping(abi, mapping):
    print(f'\nlib.add_number_mapping_from_dict("{abi}", {{')
    for num in sorted(mapping):
        print(f'    {num}: "{mapping[num]}",')
    print("})")


def main():
    syscalls_by_abi = {}
    for fname in glob.glob("/usr/share/gdb/syscalls/*-linux.xml"):
        abi = os.path.basename(fname)[: -len("-linux.xml")]
        syscalls_by_abi[abi] = parse_gdb_xml_file(fname)

    syscalls_by_abi["amd64"] = parse_unistd_include_header("/usr/include/x86_64-linux-gnu/asm/unistd_64.h")
    syscalls_by_abi["i386"] = parse_unistd_include_header("/usr/include/x86_64-linux-gnu/asm/unistd_32.h")

    syscalls_by_abi["i386"][90] = "old_mmap"  # name the old mmap differently
    syscalls_by_abi["arm"] = {num: name for num, name in syscalls_by_abi["arm"].items() if not name.startswith("ARM_")}

    syscalls_by_abi["armhf"] = {num + 0x900000: name for num, name in syscalls_by_abi["arm"].items()}

    for abi, mapping in sorted(syscalls_by_abi.items()):
        dump_mapping(abi, mapping)


if __name__ == "__main__":
    main()
