From 35b42e560039fd87d4ae4d99cd54d1d4e89710b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Fri, 15 Jan 2021 17:06:19 +0100 Subject: src/basic: generate missing syscall headers programatically Getting the numbers right for all architectures has proven to be a constant chore. Let's autogenerate the header from the tables that were imported in one of the previous commits. Fixes #18074. (Hopefully. I cannot verify this on all architectures.) To update the lists, or to update the header after template changes: ninja -C build update-syscall-tables update-syscall-header Note: the generated file is saved in git. Initially I wanted to only store the tables in git, and generate the header during each build. Generation is quick enough, but the header is used in many many places (wherever missing_syscall.h is included, directly or indirectly), which means that we would need to declare the dependency in meson, so the header would be generated early enough. This turned out to be very noisy. Storing the generated header in version control avoids the hassle. --- src/basic/missing_syscalls.py | 115 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 src/basic/missing_syscalls.py (limited to 'src/basic/missing_syscalls.py') diff --git a/src/basic/missing_syscalls.py b/src/basic/missing_syscalls.py new file mode 100644 index 0000000000..750b724828 --- /dev/null +++ b/src/basic/missing_syscalls.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +import sys +import os +import functools + +# We only generate numbers for a dozen or so syscalls +SYSCALLS = [ + 'bpf', + 'close_range', + 'copy_file_range', + 'getrandom', + 'memfd_create', + 'name_to_handle_at', + '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]: parse_syscall_table(filename) + for filename in filenames} + +DEF_TEMPLATE = '''\ +#ifndef __IGNORE_{syscall} +# 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(__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(__powerpc__) +# define systemd_NR_{syscall} {nr_powerpc} +# 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 +# else +# warning "{syscall}() syscall number is unknown for your architecture" +# endif + +/* may be (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 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('/* This file is generated. Do not edit! */\n', 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}') -- cgit v1.2.1