#!/usr/bin/env python3 # Copyright (C) 2024-2025 Free Software Foundation, Inc. # Contributed by Timur Golubovich # This file is part of GDB. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # To get help message for this script, run: # ./gdb/syscalls/riscv-linux-canonicalize-syscall-gen.py --help # Execution result: # usage: riscv-linux-canonicalize-syscall-gen.py [-h] # # Generate file gdb/riscv-linux-canonicalize-syscall-gen.c from # gdb/syscalls/riscv-linux.xml. # # options: # -h, --help show this help message and exit import argparse import re import xml.etree.ElementTree as ET from pathlib import Path FILE = Path(__file__).resolve() HEAD = f"""\ /* DO NOT EDIT: Autogenerated by {FILE.name} Copyright (C) 2024-2025 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "defs.h" #include "riscv-linux-tdep.h" /* riscv_linux_canonicalize_syscall maps from the native RISC-V Linux set of syscall ids into a canonical set of syscall ids used by process record. */ enum gdb_syscall riscv_linux_canonicalize_syscall (int syscall) {{ switch (syscall) {{ """ TAIL = """\ default: return gdb_sys_no_syscall; } } """ HELP_MESSAGE = """\ Generate file gdb/riscv-linux-canonicalize-syscall-gen.c from gdb/syscalls/riscv-linux.xml. """ class Generator: def _get_gdb_syscalls(self, gdb_syscalls_path: Path) -> set[str]: gdb_syscalls = set[str]() with open(gdb_syscalls_path, "r", encoding="UTF-8") as file: for line in file: match = re.search(r"(gdb_sys_\S+)\s*=", line) if match: gdb_syscalls.add(match[1].strip()) return gdb_syscalls def _get_arch_syscalls(self, xml_syscalls_path: Path) -> dict[str, int]: arch_syscalls: dict[str, int] = {} syscalls_info = ET.parse(xml_syscalls_path) for syscall in syscalls_info.findall("syscall"): sysname = syscall.attrib["name"] sysno = int(syscall.attrib["number"]) arch_syscalls[sysname] = sysno return arch_syscalls def _get_canon_syscalls_lines( self, arch_syscalls: dict[str, int], gdb_syscalls: set[str], exceptions: dict[str, str], ) -> list[str]: canon_syscalls: dict[int, str] = {} for sysname, sysno in arch_syscalls.items(): if sysname in exceptions: sysname = exceptions[sysname] gdb_sysname = f"gdb_sys_{sysname}" value = f" /* case {sysno}: return {gdb_sysname}; */\n" if gdb_sysname in gdb_syscalls: value = f" case {sysno}: return {gdb_sysname};\n" canon_syscalls[sysno] = value return [canon_syscalls[sysno] for sysno in sorted(canon_syscalls)] def generate(self) -> None: repo_path = FILE.parent.parent.parent gdb_path = repo_path / "gdb" xml_syscalls_path = gdb_path / "syscalls" / "riscv-linux.xml" gdb_syscalls_path = gdb_path / "linux-record.h" arch_syscalls_path = gdb_path / "riscv-linux-canonicalize-syscall-gen.c" exceptions = {"mmap": "old_mmap"} arch_syscalls = self._get_arch_syscalls(xml_syscalls_path) gdb_syscalls = self._get_gdb_syscalls(gdb_syscalls_path) canon_syscalls_lines = self._get_canon_syscalls_lines( arch_syscalls, gdb_syscalls, exceptions ) with open(arch_syscalls_path, "w", encoding="UTF-8") as file: file.writelines(HEAD) file.writelines(canon_syscalls_lines) file.writelines(TAIL) def main() -> int: parser = argparse.ArgumentParser(description=HELP_MESSAGE) parser.parse_args() Generator().generate() return 0 if __name__ == "__main__": main()