summaryrefslogtreecommitdiffstats
path: root/src/basic/missing_syscalls.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/basic/missing_syscalls.py')
-rw-r--r--src/basic/missing_syscalls.py162
1 files changed, 162 insertions, 0 deletions
diff --git a/src/basic/missing_syscalls.py b/src/basic/missing_syscalls.py
new file mode 100644
index 0000000..642d4d9
--- /dev/null
+++ b/src/basic/missing_syscalls.py
@@ -0,0 +1,162 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+import sys
+import functools
+
+# We only generate numbers for a dozen or so syscalls
+SYSCALLS = [
+ 'bpf',
+ 'close_range',
+ 'copy_file_range',
+ 'epoll_pwait2',
+ 'getrandom',
+ 'memfd_create',
+ 'mount_setattr',
+ 'move_mount',
+ 'name_to_handle_at',
+ 'open_tree',
+ 'openat2',
+ 'pidfd_open',
+ 'pidfd_send_signal',
+ 'pkey_mprotect',
+ 'renameat2',
+ 'setns',
+ 'statx',
+]
+
+def dictify(f):
+ def wrap(*args, **kwargs):
+ return dict(f(*args, **kwargs))
+ return functools.update_wrapper(wrap, f)
+
+@dictify
+def parse_syscall_table(filename):
+ print(f'Reading {filename}…')
+ for line in open(filename):
+ items = line.split()
+ if len(items) >= 2:
+ yield items[0], int(items[1])
+
+def parse_syscall_tables(filenames):
+ return {filename.split('-')[-1][:-4]: parse_syscall_table(filename)
+ for filename in filenames}
+
+DEF_TEMPLATE_A = '''\
+
+#ifndef __IGNORE_{syscall}
+'''
+
+DEF_TEMPLATE_B = '''\
+# if defined(__aarch64__)
+# define systemd_NR_{syscall} {nr_arm64}
+# elif defined(__alpha__)
+# define systemd_NR_{syscall} {nr_alpha}
+# elif defined(__arc__) || defined(__tilegx__)
+# define systemd_NR_{syscall} {nr_arc}
+# elif defined(__arm__)
+# define systemd_NR_{syscall} {nr_arm}
+# elif defined(__i386__)
+# define systemd_NR_{syscall} {nr_i386}
+# elif defined(__ia64__)
+# define systemd_NR_{syscall} {nr_ia64}
+# elif defined(__loongarch64)
+# define systemd_NR_{syscall} {nr_loongarch64}
+# elif defined(__m68k__)
+# define systemd_NR_{syscall} {nr_m68k}
+# elif defined(_MIPS_SIM)
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define systemd_NR_{syscall} {nr_mipso32}
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
+# define systemd_NR_{syscall} {nr_mips64n32}
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
+# define systemd_NR_{syscall} {nr_mips64}
+# else
+# error "Unknown MIPS ABI"
+# endif
+# elif defined(__hppa__)
+# define systemd_NR_{syscall} {nr_parisc}
+# elif defined(__powerpc__)
+# define systemd_NR_{syscall} {nr_powerpc}
+# elif defined(__riscv)
+# if __riscv_xlen == 32
+# define systemd_NR_{syscall} {nr_riscv32}
+# elif __riscv_xlen == 64
+# define systemd_NR_{syscall} {nr_riscv64}
+# else
+# error "Unknown RISC-V ABI"
+# endif
+# elif defined(__s390__)
+# define systemd_NR_{syscall} {nr_s390}
+# elif defined(__sparc__)
+# define systemd_NR_{syscall} {nr_sparc}
+# elif defined(__x86_64__)
+# if defined(__ILP32__)
+# define systemd_NR_{syscall} ({nr_x86_64} | /* __X32_SYSCALL_BIT */ 0x40000000)
+# else
+# define systemd_NR_{syscall} {nr_x86_64}
+# endif
+# elif !defined(missing_arch_template)
+%s
+# endif
+'''
+
+DEF_TEMPLATE_C = '''\
+
+/* may be an (invalid) negative number due to libseccomp, see PR 13319 */
+# if defined __NR_{syscall} && __NR_{syscall} >= 0
+# if defined systemd_NR_{syscall}
+assert_cc(__NR_{syscall} == systemd_NR_{syscall});
+# endif
+# else
+# if defined __NR_{syscall}
+# undef __NR_{syscall}
+# endif
+# if defined systemd_NR_{syscall} && systemd_NR_{syscall} >= 0
+# define __NR_{syscall} systemd_NR_{syscall}
+# endif
+# endif
+#endif'''
+
+DEF_TEMPLATE = (DEF_TEMPLATE_A +
+ DEF_TEMPLATE_B % '# warning "{syscall}() syscall number is unknown for your architecture"' +
+ DEF_TEMPLATE_C)
+
+ARCH_CHECK = '''\
+/* Note: if this code looks strange, this is because it is derived from the same
+ * template as the per-syscall blocks below. */
+''' + '\n'.join(line for line in DEF_TEMPLATE_B.splitlines()
+ if ' define ' not in line) % '''\
+# warning "Current architecture is missing from the template"
+# define missing_arch_template 1'''
+
+def print_syscall_def(syscall, tables, out):
+ mappings = {f'nr_{arch}':t.get(syscall, -1)
+ for arch, t in tables.items()}
+ print(DEF_TEMPLATE.format(syscall=syscall, **mappings),
+ file=out)
+
+def print_syscall_defs(syscalls, tables, out):
+ print('''\
+/* SPDX-License-Identifier: LGPL-2.1-or-later
+ * This file is generated by src/basic/missing_syscalls.py. Do not edit!
+ *
+ * Use 'ninja -C build update-syscall-tables' to download new syscall tables,
+ * and 'ninja -C build update-syscall-header' to regenerate this file.
+ */
+#pragma once
+''',
+ file=out)
+ print(ARCH_CHECK, file=out)
+ for syscall in syscalls:
+ print_syscall_def(syscall, tables, out)
+
+if __name__ == '__main__':
+ output_file = sys.argv[1]
+ arch_files = sys.argv[2:]
+ out = open(output_file, 'wt')
+
+ tables = parse_syscall_tables(arch_files)
+ print_syscall_defs(SYSCALLS, tables, out)
+
+ print(f'Wrote {output_file}')