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.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2021-01-15 17:06:19 +01:00
parent 7975857079
commit 35b42e5600
4 changed files with 839 additions and 528 deletions

View File

@@ -262,6 +262,9 @@ missing_audit_h = files('missing_audit.h')
missing_capability_h = files('missing_capability.h')
missing_socket_h = files('missing_socket.h')
missing_syscall_def_h = files('missing_syscall_def.h')
basic_sources += missing_syscall_def_h
generate_af_list = find_program('generate-af-list.sh')
af_list_txt = custom_target(
'af-list.txt',
@@ -330,32 +333,6 @@ foreach item : [['af', af_list_txt, 'af', ''],
endforeach
basic_sources += generated_gperf_headers
basic_gcrypt_sources = files(
'gcrypt-util.c',
'gcrypt-util.h')
libbasic = static_library(
'basic',
basic_sources,
include_directories : includes,
dependencies : [versiondep,
threads,
libcap,
libseccomp,
libselinux,
libm,
libdl],
c_args : ['-fvisibility=default'],
install : false)
# A convenience library that is separate from libbasic to avoid
# unnecessary linking to libgcrypt.
libbasic_gcrypt = static_library(
'basic-gcrypt',
basic_gcrypt_sources,
include_directories : includes,
dependencies : [libgcrypt],
c_args : ['-fvisibility=default'])
############################################################
@@ -382,3 +359,47 @@ run_target(
command : [syscall_table_update_sh, meson.current_source_dir()] + arch_list)
syscall_names_text = files('syscall-names.text')
syscall_lists = []
foreach arch: arch_list
syscall_lists += files('syscalls-@0@'.format(arch))
endforeach
missing_syscalls_py = find_program('missing_syscalls.py')
run_target(
'update-syscall-header',
command : [missing_syscalls_py,
missing_syscall_def_h,
syscall_lists])
############################################################
libbasic = static_library(
'basic',
basic_sources,
include_directories : includes,
dependencies : [versiondep,
threads,
libcap,
libseccomp,
libselinux,
libm,
libdl],
c_args : ['-fvisibility=default'],
install : false)
############################################################
basic_gcrypt_sources = files(
'gcrypt-util.c',
'gcrypt-util.h')
# A convenience library that is separate from libbasic to avoid
# unnecessary linking to libgcrypt.
libbasic_gcrypt = static_library(
'basic-gcrypt',
basic_gcrypt_sources,
include_directories : includes,
dependencies : [libgcrypt],
c_args : ['-fvisibility=default'])

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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}')