| #!/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 <http://www.gnu.org/licenses/>. |
| |
| |
| # 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 <http://www.gnu.org/licenses/>. */ |
| |
| #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() |