diff mbox series

[v2,5/7] perf trace beauty: Add syscalltbl.sh generating all system call tables

Message ID 20250210165108.95894-6-irogers@google.com (mailing list archive)
State Superseded
Headers show
Series perf: Support multiple system call tables in the build | expand

Checks

Context Check Description
bjorn/pre-ci_am success Success
bjorn/build-rv32-defconfig success build-rv32-defconfig
bjorn/build-rv64-clang-allmodconfig success build-rv64-clang-allmodconfig
bjorn/build-rv64-gcc-allmodconfig success build-rv64-gcc-allmodconfig
bjorn/build-rv64-nommu-k210-defconfig success build-rv64-nommu-k210-defconfig
bjorn/build-rv64-nommu-k210-virt success build-rv64-nommu-k210-virt
bjorn/checkpatch warning checkpatch
bjorn/dtb-warn-rv64 success dtb-warn-rv64
bjorn/header-inline success header-inline
bjorn/kdoc success kdoc
bjorn/module-param success module-param
bjorn/verify-fixes success verify-fixes
bjorn/verify-signedoff success verify-signedoff

Commit Message

Ian Rogers Feb. 10, 2025, 4:51 p.m. UTC
Rather than generating individual syscall header files generate a
single trace/beauty/generated/syscalltbl.c. In a syscalltbls array
have references to each architectures tables along with the
corresponding e_machine. When the 32-bit or 64-bit table is ambiguous,
match the perf binary's type. For ARM32 don't use the arm64 32-bit
table which is smaller. EM_NONE is present for is no machine matches.

Conditionally compile the tables, only having the appropriate 32 and
64-bit table. If ALL_SYSCALLTBL is defined all tables can be
compiled.

Signed-off-by: Ian Rogers <irogers@google.com>
Reviewed-by: Howard Chu <howardchu95@gmail.com>
---
 tools/perf/Makefile.perf              |   9 +
 tools/perf/trace/beauty/syscalltbl.sh | 274 ++++++++++++++++++++++++++
 2 files changed, 283 insertions(+)
 create mode 100755 tools/perf/trace/beauty/syscalltbl.sh

Comments

Charlie Jenkins Feb. 11, 2025, 12:22 a.m. UTC | #1
On Mon, Feb 10, 2025 at 08:51:06AM -0800, Ian Rogers wrote:
> Rather than generating individual syscall header files generate a
> single trace/beauty/generated/syscalltbl.c. In a syscalltbls array
> have references to each architectures tables along with the
> corresponding e_machine. When the 32-bit or 64-bit table is ambiguous,
> match the perf binary's type. For ARM32 don't use the arm64 32-bit
> table which is smaller. EM_NONE is present for is no machine matches.
> 
> Conditionally compile the tables, only having the appropriate 32 and
> 64-bit table. If ALL_SYSCALLTBL is defined all tables can be
> compiled.

Is there somewhere that the ALL_SYSCALLTBL could be documented? I talk
about this more in patch 7, but if this also could help perf report
display the correct syscall names, then ALL_SYSCALLTBL maybe should be
the default?

> 
> Signed-off-by: Ian Rogers <irogers@google.com>
> Reviewed-by: Howard Chu <howardchu95@gmail.com>
> ---
>  tools/perf/Makefile.perf              |   9 +
>  tools/perf/trace/beauty/syscalltbl.sh | 274 ++++++++++++++++++++++++++
>  2 files changed, 283 insertions(+)
>  create mode 100755 tools/perf/trace/beauty/syscalltbl.sh
> 
> diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
> index 55d6ce9ea52f..793e702f9aaf 100644
> --- a/tools/perf/Makefile.perf
> +++ b/tools/perf/Makefile.perf
> @@ -559,6 +559,14 @@ beauty_ioctl_outdir := $(beauty_outdir)/ioctl
>  # Create output directory if not already present
>  $(shell [ -d '$(beauty_ioctl_outdir)' ] || mkdir -p '$(beauty_ioctl_outdir)')
>  
> +syscall_array := $(beauty_outdir)/syscalltbl.c
> +syscall_tbl := $(srctree)/tools/perf/trace/beauty/syscalltbl.sh
> +syscall_tbl_data := $(srctree)/tools/scripts/syscall.tbl \
> +	$(wildcard $(srctree)/tools/perf/arch/*/entry/syscalls/syscall*.tbl)
> +
> +$(syscall_array): $(syscall_tbl) $(syscall_tbl_data)
> +	$(Q)$(SHELL) '$(syscall_tbl)' $(srctree)/tools $@
> +
>  fs_at_flags_array := $(beauty_outdir)/fs_at_flags_array.c
>  fs_at_flags_tbl := $(srctree)/tools/perf/trace/beauty/fs_at_flags.sh
>  
> @@ -878,6 +886,7 @@ build-dir   = $(or $(__build-dir),.)
>  
>  prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders \
>  	arm64-sysreg-defs \
> +	$(syscall_array) \
>  	$(fs_at_flags_array) \
>  	$(clone_flags_array) \
>  	$(drm_ioctl_array) \
> diff --git a/tools/perf/trace/beauty/syscalltbl.sh b/tools/perf/trace/beauty/syscalltbl.sh
> new file mode 100755
> index 000000000000..635924dc5f59
> --- /dev/null
> +++ b/tools/perf/trace/beauty/syscalltbl.sh
> @@ -0,0 +1,274 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Generate all syscall tables.
> +#
> +# Each line of the syscall table should have the following format:
> +#
> +# NR ABI NAME [NATIVE] [COMPAT]
> +#
> +# NR       syscall number
> +# ABI      ABI name
> +# NAME     syscall name
> +# NATIVE   native entry point (optional)
> +# COMPAT   compat entry point (optional)
> +
> +set -e
> +
> +usage() {
> +       cat >&2 <<EOF
> +usage: $0 <TOOLS DIRECTORY> <OUTFILE>
> +
> +  <TOOLS DIRECTORY>    path to kernel tools directory
> +  <OUTFILE>            output header file
> +EOF
> +       exit 1
> +}
> +
> +if [ $# -ne 2 ]; then
> +       usage
> +fi
> +tools_dir=$1
> +outfile=$2
> +
> +build_tables() {
> +	infile="$1"
> +	outfile="$2"
> +	abis=$(echo "($3)" | tr ',' '|')
> +	e_machine="$4"
> +
> +	if [ ! -f "$infile" ]
> +	then
> +		echo "Missing file $infile"
> +		exit 1
> +	fi
> +	sorted_table=$(mktemp /tmp/syscalltbl.XXXXXX)
> +	grep -E "^[0-9]+[[:space:]]+$abis" "$infile" | sort -n > "$sorted_table"
> +
> +	echo "static const char *const syscall_num_to_name_${e_machine}[] = {" >> "$outfile"
> +	# the params are: nr abi name entry compat
> +	# use _ for intentionally unused variables according to SC2034
> +	while read -r nr _ name _ _; do
> +		echo "	[$nr] = \"$name\"," >> "$outfile"
> +	done < "$sorted_table"
> +	echo "};" >> "$outfile"
> +
> +	echo "static const uint16_t syscall_sorted_names_${e_machine}[] = {" >> "$outfile"
> +
> +	# When sorting by name, add a suffix of 0s upto 20 characters so that
> +	# system calls that differ with a numerical suffix don't sort before
> +	# those without. This default behavior of sort differs from that of
> +	# strcmp used at runtime. Use sed to strip the trailing 0s suffix
> +	# afterwards.
> +	grep -E "^[0-9]+[[:space:]]+$abis" "$infile" | awk '{printf $3; for (i = length($3); i < 20; i++) { printf "0"; }; print " " $1}'| sort | sed 's/\([a-zA-Z1-9]\+\)0\+ \([0-9]\+\)/\1 \2/' > "$sorted_table"
> +	while read -r name nr; do
> +		echo "	$nr,	/* $name */" >> "$outfile"
> +	done < "$sorted_table"
> +	echo "};" >> "$outfile"
> +
> +	rm -f "$sorted_table"
> +}
> +
> +rm -f "$outfile"
> +cat >> "$outfile" <<EOF
> +#include <elf.h>
> +#include <stdint.h>
> +#include <asm/bitsperlong.h>
> +#include <linux/kernel.h>
> +
> +struct syscalltbl {
> +       const char *const *num_to_name;
> +       const uint16_t *sorted_names;
> +       uint16_t e_machine;
> +       uint16_t num_to_name_len;
> +       uint16_t sorted_names_len;
> +};
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__alpha__)
> +EOF
> +build_tables "$tools_dir/perf/arch/alpha/entry/syscalls/syscall.tbl" "$outfile" common,64 EM_ALPHA
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__alpha__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__arm__) || defined(__aarch64__)
> +EOF
> +build_tables "$tools_dir/perf/arch/arm/entry/syscalls/syscall.tbl" "$outfile" common,32,oabi EM_ARM
> +build_tables "$tools_dir/perf/arch/arm64/entry/syscalls/syscall_64.tbl" "$outfile" common,64,renameat,rlimit,memfd_secret EM_AARCH64
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__arm__) || defined(__aarch64__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__csky__)
> +EOF
> +build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,32,csky,time32,stat64,rlimit EM_CSKY
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__csky__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__mips__)
> +EOF
> +build_tables "$tools_dir/perf/arch/mips/entry/syscalls/syscall_n64.tbl" "$outfile" common,64,n64 EM_MIPS
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__mips__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__hppa__)
> +#if __BITS_PER_LONG != 64
> +EOF
> +build_tables "$tools_dir/perf/arch/parisc/entry/syscalls/syscall.tbl" "$outfile" common,32 EM_PARISC
> +echo "#else" >> "$outfile"
> +build_tables "$tools_dir/perf/arch/parisc/entry/syscalls/syscall.tbl" "$outfile" common,64 EM_PARISC
> +cat >> "$outfile" <<EOF
> +#endif //__BITS_PER_LONG != 64
> +#endif // defined(ALL_SYSCALLTBL) || defined(__hppa__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__powerpc__) || defined(__powerpc64__)
> +EOF
> +build_tables "$tools_dir/perf/arch/powerpc/entry/syscalls/syscall.tbl" "$outfile" common,32,nospu EM_PPC
> +build_tables "$tools_dir/perf/arch/powerpc/entry/syscalls/syscall.tbl" "$outfile" common,64,nospu EM_PPC64
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__powerpc__) || defined(__powerpc64__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__riscv)
> +#if __BITS_PER_LONG != 64
> +EOF
> +build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,32,riscv,memfd_secret EM_RISCV
> +echo "#else" >> "$outfile"
> +build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,64,riscv,rlimit,memfd_secret EM_RISCV
> +cat >> "$outfile" <<EOF
> +#endif //__BITS_PER_LONG != 64
> +#endif // defined(ALL_SYSCALLTBL) || defined(__riscv)
> +#if defined(ALL_SYSCALLTBL) || defined(__s390x__)
> +EOF
> +build_tables "$tools_dir/perf/arch/s390/entry/syscalls/syscall.tbl" "$outfile" common,64,renameat,rlimit,memfd_secret EM_S390
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__s390x__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__sh__)
> +EOF
> +build_tables "$tools_dir/perf/arch/sh/entry/syscalls/syscall.tbl" "$outfile" common,32 EM_SH
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__sh__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__sparc64__) || defined(__sparc__)
> +#if __BITS_PER_LONG != 64
> +EOF
> +build_tables "$tools_dir/perf/arch/sparc/entry/syscalls/syscall.tbl" "$outfile" common,32 EM_SPARC
> +echo "#else" >> "$outfile"
> +build_tables "$tools_dir/perf/arch/sparc/entry/syscalls/syscall.tbl" "$outfile" common,64 EM_SPARC
> +cat >> "$outfile" <<EOF
> +#endif //__BITS_PER_LONG != 64
> +#endif // defined(ALL_SYSCALLTBL) || defined(__sparc64__) || defined(__sparc__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
> +EOF
> +build_tables "$tools_dir/perf/arch/x86/entry/syscalls/syscall_32.tbl" "$outfile" common,32,i386 EM_386
> +build_tables "$tools_dir/perf/arch/x86/entry/syscalls/syscall_64.tbl" "$outfile" common,64 EM_X86_64
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__xtensa__)
> +EOF
> +build_tables "$tools_dir/perf/arch/xtensa/entry/syscalls/syscall.tbl" "$outfile" common,32 EM_XTENSA
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__xtensa__)
> +
> +#if __BITS_PER_LONG != 64
> +EOF
> +build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,32 EM_NONE
> +echo "#else" >> "$outfile"
> +build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,64 EM_NONE
> +echo "#endif //__BITS_PER_LONG != 64" >> "$outfile"
> +
> +build_outer_table() {
> +       e_machine=$1
> +       outfile="$2"
> +       cat >> "$outfile" <<EOF
> +       {
> +	      .num_to_name = syscall_num_to_name_$e_machine,
> +	      .sorted_names = syscall_sorted_names_$e_machine,
> +	      .e_machine = $e_machine,
> +	      .num_to_name_len = ARRAY_SIZE(syscall_num_to_name_$e_machine),
> +	      .sorted_names_len = ARRAY_SIZE(syscall_sorted_names_$e_machine),
> +       },
> +EOF
> +}
> +
> +cat >> "$outfile" <<EOF
> +static const struct syscalltbl syscalltbls[] = {
> +#if defined(ALL_SYSCALLTBL) || defined(__alpha__)
> +EOF
> +build_outer_table EM_ALPHA "$outfile"
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__alpha__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__arm__) || defined(__aarch64__)
> +EOF
> +build_outer_table EM_ARM "$outfile"
> +build_outer_table EM_AARCH64 "$outfile"
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__arm__) || defined(__aarch64__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__csky__)
> +EOF
> +build_outer_table EM_CSKY "$outfile"
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__csky__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__mips__)
> +EOF
> +build_outer_table EM_MIPS "$outfile"
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__mips__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__hppa__)
> +EOF
> +build_outer_table EM_PARISC "$outfile"
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__hppa__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__powerpc__) || defined(__powerpc64__)
> +EOF
> +build_outer_table EM_PPC "$outfile"
> +build_outer_table EM_PPC64 "$outfile"
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__powerpc__) || defined(__powerpc64__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__riscv)
> +EOF
> +build_outer_table EM_RISCV "$outfile"
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__riscv)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__s390x__)
> +EOF
> +build_outer_table EM_S390 "$outfile"
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__s390x__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__sh__)
> +EOF
> +build_outer_table EM_SH "$outfile"
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__sh__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__sparc64__) || defined(__sparc__)
> +EOF
> +build_outer_table EM_SPARC "$outfile"
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__sparc64__) || defined(__sparc__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
> +EOF
> +build_outer_table EM_386 "$outfile"
> +build_outer_table EM_X86_64 "$outfile"
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
> +
> +#if defined(ALL_SYSCALLTBL) || defined(__xtensa__)
> +EOF
> +build_outer_table EM_XTENSA "$outfile"
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__xtensa__)
> +EOF
> +build_outer_table EM_NONE "$outfile"
> +cat >> "$outfile" <<EOF
> +};
> +EOF
> -- 
> 2.48.1.502.g6dc24dfdaf-goog
>
Ian Rogers Feb. 11, 2025, 5:08 a.m. UTC | #2
On Mon, Feb 10, 2025 at 4:22 PM Charlie Jenkins <charlie@rivosinc.com> wrote:
>
> On Mon, Feb 10, 2025 at 08:51:06AM -0800, Ian Rogers wrote:
> > Rather than generating individual syscall header files generate a
> > single trace/beauty/generated/syscalltbl.c. In a syscalltbls array
> > have references to each architectures tables along with the
> > corresponding e_machine. When the 32-bit or 64-bit table is ambiguous,
> > match the perf binary's type. For ARM32 don't use the arm64 32-bit
> > table which is smaller. EM_NONE is present for is no machine matches.
> >
> > Conditionally compile the tables, only having the appropriate 32 and
> > 64-bit table. If ALL_SYSCALLTBL is defined all tables can be
> > compiled.
>
> Is there somewhere that the ALL_SYSCALLTBL could be documented? I talk
> about this more in patch 7, but if this also could help perf report
> display the correct syscall names, then ALL_SYSCALLTBL maybe should be
> the default?

So I think ALL_SYSCALLTBL should just go to being the default once we
have a use for it. Currently `perf trace record` doesn't capture the
e_machine of the executing processes, so recording on say a RISC-V
machine and then analyzing on an x86-64 isn't possible. I was worried
that just making ALL_SYSCALLTBL the default would lead to complaints
about increases in binary size or something. This patch series does
what's sensible for things that work right now. ALL_SYSCALLTBL is
useful for making sure the tables other than for your build machine at
least compile. If others feel strongly it should be the default I
don't have a problem changing the code.

Thanks,
Ian

> >
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > Reviewed-by: Howard Chu <howardchu95@gmail.com>
> > ---
> >  tools/perf/Makefile.perf              |   9 +
> >  tools/perf/trace/beauty/syscalltbl.sh | 274 ++++++++++++++++++++++++++
> >  2 files changed, 283 insertions(+)
> >  create mode 100755 tools/perf/trace/beauty/syscalltbl.sh
> >
> > diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
> > index 55d6ce9ea52f..793e702f9aaf 100644
> > --- a/tools/perf/Makefile.perf
> > +++ b/tools/perf/Makefile.perf
> > @@ -559,6 +559,14 @@ beauty_ioctl_outdir := $(beauty_outdir)/ioctl
> >  # Create output directory if not already present
> >  $(shell [ -d '$(beauty_ioctl_outdir)' ] || mkdir -p '$(beauty_ioctl_outdir)')
> >
> > +syscall_array := $(beauty_outdir)/syscalltbl.c
> > +syscall_tbl := $(srctree)/tools/perf/trace/beauty/syscalltbl.sh
> > +syscall_tbl_data := $(srctree)/tools/scripts/syscall.tbl \
> > +     $(wildcard $(srctree)/tools/perf/arch/*/entry/syscalls/syscall*.tbl)
> > +
> > +$(syscall_array): $(syscall_tbl) $(syscall_tbl_data)
> > +     $(Q)$(SHELL) '$(syscall_tbl)' $(srctree)/tools $@
> > +
> >  fs_at_flags_array := $(beauty_outdir)/fs_at_flags_array.c
> >  fs_at_flags_tbl := $(srctree)/tools/perf/trace/beauty/fs_at_flags.sh
> >
> > @@ -878,6 +886,7 @@ build-dir   = $(or $(__build-dir),.)
> >
> >  prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders \
> >       arm64-sysreg-defs \
> > +     $(syscall_array) \
> >       $(fs_at_flags_array) \
> >       $(clone_flags_array) \
> >       $(drm_ioctl_array) \
> > diff --git a/tools/perf/trace/beauty/syscalltbl.sh b/tools/perf/trace/beauty/syscalltbl.sh
> > new file mode 100755
> > index 000000000000..635924dc5f59
> > --- /dev/null
> > +++ b/tools/perf/trace/beauty/syscalltbl.sh
> > @@ -0,0 +1,274 @@
> > +#!/bin/sh
> > +# SPDX-License-Identifier: GPL-2.0
> > +#
> > +# Generate all syscall tables.
> > +#
> > +# Each line of the syscall table should have the following format:
> > +#
> > +# NR ABI NAME [NATIVE] [COMPAT]
> > +#
> > +# NR       syscall number
> > +# ABI      ABI name
> > +# NAME     syscall name
> > +# NATIVE   native entry point (optional)
> > +# COMPAT   compat entry point (optional)
> > +
> > +set -e
> > +
> > +usage() {
> > +       cat >&2 <<EOF
> > +usage: $0 <TOOLS DIRECTORY> <OUTFILE>
> > +
> > +  <TOOLS DIRECTORY>    path to kernel tools directory
> > +  <OUTFILE>            output header file
> > +EOF
> > +       exit 1
> > +}
> > +
> > +if [ $# -ne 2 ]; then
> > +       usage
> > +fi
> > +tools_dir=$1
> > +outfile=$2
> > +
> > +build_tables() {
> > +     infile="$1"
> > +     outfile="$2"
> > +     abis=$(echo "($3)" | tr ',' '|')
> > +     e_machine="$4"
> > +
> > +     if [ ! -f "$infile" ]
> > +     then
> > +             echo "Missing file $infile"
> > +             exit 1
> > +     fi
> > +     sorted_table=$(mktemp /tmp/syscalltbl.XXXXXX)
> > +     grep -E "^[0-9]+[[:space:]]+$abis" "$infile" | sort -n > "$sorted_table"
> > +
> > +     echo "static const char *const syscall_num_to_name_${e_machine}[] = {" >> "$outfile"
> > +     # the params are: nr abi name entry compat
> > +     # use _ for intentionally unused variables according to SC2034
> > +     while read -r nr _ name _ _; do
> > +             echo "  [$nr] = \"$name\"," >> "$outfile"
> > +     done < "$sorted_table"
> > +     echo "};" >> "$outfile"
> > +
> > +     echo "static const uint16_t syscall_sorted_names_${e_machine}[] = {" >> "$outfile"
> > +
> > +     # When sorting by name, add a suffix of 0s upto 20 characters so that
> > +     # system calls that differ with a numerical suffix don't sort before
> > +     # those without. This default behavior of sort differs from that of
> > +     # strcmp used at runtime. Use sed to strip the trailing 0s suffix
> > +     # afterwards.
> > +     grep -E "^[0-9]+[[:space:]]+$abis" "$infile" | awk '{printf $3; for (i = length($3); i < 20; i++) { printf "0"; }; print " " $1}'| sort | sed 's/\([a-zA-Z1-9]\+\)0\+ \([0-9]\+\)/\1 \2/' > "$sorted_table"
> > +     while read -r name nr; do
> > +             echo "  $nr,    /* $name */" >> "$outfile"
> > +     done < "$sorted_table"
> > +     echo "};" >> "$outfile"
> > +
> > +     rm -f "$sorted_table"
> > +}
> > +
> > +rm -f "$outfile"
> > +cat >> "$outfile" <<EOF
> > +#include <elf.h>
> > +#include <stdint.h>
> > +#include <asm/bitsperlong.h>
> > +#include <linux/kernel.h>
> > +
> > +struct syscalltbl {
> > +       const char *const *num_to_name;
> > +       const uint16_t *sorted_names;
> > +       uint16_t e_machine;
> > +       uint16_t num_to_name_len;
> > +       uint16_t sorted_names_len;
> > +};
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__alpha__)
> > +EOF
> > +build_tables "$tools_dir/perf/arch/alpha/entry/syscalls/syscall.tbl" "$outfile" common,64 EM_ALPHA
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__alpha__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__arm__) || defined(__aarch64__)
> > +EOF
> > +build_tables "$tools_dir/perf/arch/arm/entry/syscalls/syscall.tbl" "$outfile" common,32,oabi EM_ARM
> > +build_tables "$tools_dir/perf/arch/arm64/entry/syscalls/syscall_64.tbl" "$outfile" common,64,renameat,rlimit,memfd_secret EM_AARCH64
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__arm__) || defined(__aarch64__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__csky__)
> > +EOF
> > +build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,32,csky,time32,stat64,rlimit EM_CSKY
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__csky__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__mips__)
> > +EOF
> > +build_tables "$tools_dir/perf/arch/mips/entry/syscalls/syscall_n64.tbl" "$outfile" common,64,n64 EM_MIPS
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__mips__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__hppa__)
> > +#if __BITS_PER_LONG != 64
> > +EOF
> > +build_tables "$tools_dir/perf/arch/parisc/entry/syscalls/syscall.tbl" "$outfile" common,32 EM_PARISC
> > +echo "#else" >> "$outfile"
> > +build_tables "$tools_dir/perf/arch/parisc/entry/syscalls/syscall.tbl" "$outfile" common,64 EM_PARISC
> > +cat >> "$outfile" <<EOF
> > +#endif //__BITS_PER_LONG != 64
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__hppa__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__powerpc__) || defined(__powerpc64__)
> > +EOF
> > +build_tables "$tools_dir/perf/arch/powerpc/entry/syscalls/syscall.tbl" "$outfile" common,32,nospu EM_PPC
> > +build_tables "$tools_dir/perf/arch/powerpc/entry/syscalls/syscall.tbl" "$outfile" common,64,nospu EM_PPC64
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__powerpc__) || defined(__powerpc64__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__riscv)
> > +#if __BITS_PER_LONG != 64
> > +EOF
> > +build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,32,riscv,memfd_secret EM_RISCV
> > +echo "#else" >> "$outfile"
> > +build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,64,riscv,rlimit,memfd_secret EM_RISCV
> > +cat >> "$outfile" <<EOF
> > +#endif //__BITS_PER_LONG != 64
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__riscv)
> > +#if defined(ALL_SYSCALLTBL) || defined(__s390x__)
> > +EOF
> > +build_tables "$tools_dir/perf/arch/s390/entry/syscalls/syscall.tbl" "$outfile" common,64,renameat,rlimit,memfd_secret EM_S390
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__s390x__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__sh__)
> > +EOF
> > +build_tables "$tools_dir/perf/arch/sh/entry/syscalls/syscall.tbl" "$outfile" common,32 EM_SH
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__sh__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__sparc64__) || defined(__sparc__)
> > +#if __BITS_PER_LONG != 64
> > +EOF
> > +build_tables "$tools_dir/perf/arch/sparc/entry/syscalls/syscall.tbl" "$outfile" common,32 EM_SPARC
> > +echo "#else" >> "$outfile"
> > +build_tables "$tools_dir/perf/arch/sparc/entry/syscalls/syscall.tbl" "$outfile" common,64 EM_SPARC
> > +cat >> "$outfile" <<EOF
> > +#endif //__BITS_PER_LONG != 64
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__sparc64__) || defined(__sparc__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
> > +EOF
> > +build_tables "$tools_dir/perf/arch/x86/entry/syscalls/syscall_32.tbl" "$outfile" common,32,i386 EM_386
> > +build_tables "$tools_dir/perf/arch/x86/entry/syscalls/syscall_64.tbl" "$outfile" common,64 EM_X86_64
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__xtensa__)
> > +EOF
> > +build_tables "$tools_dir/perf/arch/xtensa/entry/syscalls/syscall.tbl" "$outfile" common,32 EM_XTENSA
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__xtensa__)
> > +
> > +#if __BITS_PER_LONG != 64
> > +EOF
> > +build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,32 EM_NONE
> > +echo "#else" >> "$outfile"
> > +build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,64 EM_NONE
> > +echo "#endif //__BITS_PER_LONG != 64" >> "$outfile"
> > +
> > +build_outer_table() {
> > +       e_machine=$1
> > +       outfile="$2"
> > +       cat >> "$outfile" <<EOF
> > +       {
> > +           .num_to_name = syscall_num_to_name_$e_machine,
> > +           .sorted_names = syscall_sorted_names_$e_machine,
> > +           .e_machine = $e_machine,
> > +           .num_to_name_len = ARRAY_SIZE(syscall_num_to_name_$e_machine),
> > +           .sorted_names_len = ARRAY_SIZE(syscall_sorted_names_$e_machine),
> > +       },
> > +EOF
> > +}
> > +
> > +cat >> "$outfile" <<EOF
> > +static const struct syscalltbl syscalltbls[] = {
> > +#if defined(ALL_SYSCALLTBL) || defined(__alpha__)
> > +EOF
> > +build_outer_table EM_ALPHA "$outfile"
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__alpha__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__arm__) || defined(__aarch64__)
> > +EOF
> > +build_outer_table EM_ARM "$outfile"
> > +build_outer_table EM_AARCH64 "$outfile"
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__arm__) || defined(__aarch64__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__csky__)
> > +EOF
> > +build_outer_table EM_CSKY "$outfile"
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__csky__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__mips__)
> > +EOF
> > +build_outer_table EM_MIPS "$outfile"
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__mips__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__hppa__)
> > +EOF
> > +build_outer_table EM_PARISC "$outfile"
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__hppa__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__powerpc__) || defined(__powerpc64__)
> > +EOF
> > +build_outer_table EM_PPC "$outfile"
> > +build_outer_table EM_PPC64 "$outfile"
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__powerpc__) || defined(__powerpc64__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__riscv)
> > +EOF
> > +build_outer_table EM_RISCV "$outfile"
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__riscv)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__s390x__)
> > +EOF
> > +build_outer_table EM_S390 "$outfile"
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__s390x__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__sh__)
> > +EOF
> > +build_outer_table EM_SH "$outfile"
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__sh__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__sparc64__) || defined(__sparc__)
> > +EOF
> > +build_outer_table EM_SPARC "$outfile"
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__sparc64__) || defined(__sparc__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
> > +EOF
> > +build_outer_table EM_386 "$outfile"
> > +build_outer_table EM_X86_64 "$outfile"
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
> > +
> > +#if defined(ALL_SYSCALLTBL) || defined(__xtensa__)
> > +EOF
> > +build_outer_table EM_XTENSA "$outfile"
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__xtensa__)
> > +EOF
> > +build_outer_table EM_NONE "$outfile"
> > +cat >> "$outfile" <<EOF
> > +};
> > +EOF
> > --
> > 2.48.1.502.g6dc24dfdaf-goog
> >
Arnd Bergmann Feb. 11, 2025, 8:08 a.m. UTC | #3
On Mon, Feb 10, 2025, at 17:51, Ian Rogers wrote:

> +# Each line of the syscall table should have the following format:
> +#
> +# NR ABI NAME [NATIVE] [COMPAT]
> +#
> +# NR       syscall number
> +# ABI      ABI name
> +# NAME     syscall name
> +# NATIVE   native entry point (optional)
> +# COMPAT   compat entry point (optional)

On x86, there is now a sixth optional field.

> +#if defined(ALL_SYSCALLTBL) || defined(__arm__) || defined(__aarch64__)
> +EOF
> +build_tables "$tools_dir/perf/arch/arm/entry/syscalls/syscall.tbl" 
> "$outfile" common,32,oabi EM_ARM
> +build_tables 

The oabi syscalls probably shouldn't be part of the default set here.
Technically these are two separate ABIs, though EABI is a subset of
OABI for the most most part. Some of the calling conventions are
also different.

> "$tools_dir/perf/arch/arm64/entry/syscalls/syscall_64.tbl" "$outfile" 
> common,64,renameat,rlimit,memfd_secret EM_AARCH64
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__arm__) || 
> defined(__aarch64__)

Hardcoding the set of ABIs in the middle of the script seems
too fragile to me, I'm worried that these get out of sync quickly.

> +#if defined(ALL_SYSCALLTBL) || defined(__mips__)
> +EOF
> +build_tables 
> "$tools_dir/perf/arch/mips/entry/syscalls/syscall_n64.tbl" "$outfile" 
> common,64,n64 EM_MIPS
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__mips__)

What about n32/o32? The syscall tables are completely different here.

> +#if defined(ALL_SYSCALLTBL) || defined(__powerpc__) || 
> defined(__powerpc64__)
> +EOF
> +build_tables "$tools_dir/perf/arch/powerpc/entry/syscalls/syscall.tbl" 
> "$outfile" common,32,nospu EM_PPC
> +build_tables "$tools_dir/perf/arch/powerpc/entry/syscalls/syscall.tbl" 
> "$outfile" common,64,nospu EM_PPC64
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__powerpc__) || 
> defined(__powerpc64__)

This skips the SPU table, but I think that's fine.

> +EOF
> +build_tables "$tools_dir/perf/arch/s390/entry/syscalls/syscall.tbl" 
> "$outfile" common,64,renameat,rlimit,memfd_secret EM_S390
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__s390x__)

This skips the 32-bit table, though I think that one is already
planned to be discontinued in the future.

> +#if defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
> +EOF
> +build_tables "$tools_dir/perf/arch/x86/entry/syscalls/syscall_32.tbl" 
> "$outfile" common,32,i386 EM_386
> +build_tables "$tools_dir/perf/arch/x86/entry/syscalls/syscall_64.tbl" 
> "$outfile" common,64 EM_X86_64
> +cat >> "$outfile" <<EOF
> +#endif // defined(ALL_SYSCALLTBL) || defined(__i386__) || 
> defined(__x86_64__)

This misses the x32 table.

   Arnd
Ian Rogers Feb. 11, 2025, 5:24 p.m. UTC | #4
On Tue, Feb 11, 2025 at 12:09 AM Arnd Bergmann <arnd@arndb.de> wrote:
>
> On Mon, Feb 10, 2025, at 17:51, Ian Rogers wrote:
>
> > +# Each line of the syscall table should have the following format:
> > +#
> > +# NR ABI NAME [NATIVE] [COMPAT]
> > +#
> > +# NR       syscall number
> > +# ABI      ABI name
> > +# NAME     syscall name
> > +# NATIVE   native entry point (optional)
> > +# COMPAT   compat entry point (optional)
>
> On x86, there is now a sixth optional field.

Thanks, I'll add and repost a v3. I had some other questions below so
I'll try to do everything together to avoid noise.

> > +#if defined(ALL_SYSCALLTBL) || defined(__arm__) || defined(__aarch64__)
> > +EOF
> > +build_tables "$tools_dir/perf/arch/arm/entry/syscalls/syscall.tbl"
> > "$outfile" common,32,oabi EM_ARM
> > +build_tables
>
> The oabi syscalls probably shouldn't be part of the default set here.
> Technically these are two separate ABIs, though EABI is a subset of
> OABI for the most most part. Some of the calling conventions are
> also different.

Ack. I was carrying forward:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/perf/arch/arm/entry/syscalls/Kbuild#n3
but noticed that we weren't adding this for arm64:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/perf/arch/arm64/entry/syscalls/Kbuild
I'm happy to drop and have the ARM64 behavior. I'll make it a separate
patch in case there is a desire from someone to revert.

> > "$tools_dir/perf/arch/arm64/entry/syscalls/syscall_64.tbl" "$outfile"
> > common,64,renameat,rlimit,memfd_secret EM_AARCH64
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__arm__) ||
> > defined(__aarch64__)
>
> Hardcoding the set of ABIs in the middle of the script seems
> too fragile to me, I'm worried that these get out of sync quickly.

I agree, again this is carrying forward a behavior and at least after
these changes the location is just one place. Do you have any
suggestions on how to do better?

Fwiw, I wonder a related problem/question that has come up primarily
with Arnaldo and Howard is in having a way to determine system call
argument types so that perf trace can pretty print them. For example,
if via BTF it is found an argument is a "const char*" then it is
assumed to be a string, but a "char *" is not as it may just be an out
argument. There's a source for more information in the syzkaller
project:
https://github.com/google/syzkaller/blob/master/sys/linux/sys.txt
Perhaps there's a way to generate this information from the Linux
build and feed it into perf's build. It is out-of-scope for what I'm
trying to do here, but I thought it worth a mention given my general
ignorance on wider things.

> > +#if defined(ALL_SYSCALLTBL) || defined(__mips__)
> > +EOF
> > +build_tables
> > "$tools_dir/perf/arch/mips/entry/syscalls/syscall_n64.tbl" "$outfile"
> > common,64,n64 EM_MIPS
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__mips__)
>
> What about n32/o32? The syscall tables are completely different here.

So perf hasn't historically supported them and no one is asking for
support. Generating more tables isn't the problem, but we need to have
some way of determining which table to use for n32/o32. I see
EF_MIPS_ABI_O32 and EF_MIPS_ABI_O64, so we could add support by
extending the lookup of the table to be both of e_machine and e_flags.
I'm less clear on choosing n32. That said, back in the 90s I was
working to port MIPS code to Itanium via binary translation. Given now
Itanium is obsolete, I'm not sure it is worth adding complexity for
the sake of MIPS. I'm happy to do what others feel is best here, but
my default position is just to carry what the existing behavior is
forward.

> > +#if defined(ALL_SYSCALLTBL) || defined(__powerpc__) ||
> > defined(__powerpc64__)
> > +EOF
> > +build_tables "$tools_dir/perf/arch/powerpc/entry/syscalls/syscall.tbl"
> > "$outfile" common,32,nospu EM_PPC
> > +build_tables "$tools_dir/perf/arch/powerpc/entry/syscalls/syscall.tbl"
> > "$outfile" common,64,nospu EM_PPC64
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__powerpc__) ||
> > defined(__powerpc64__)
>
> This skips the SPU table, but I think that's fine.
>
> > +EOF
> > +build_tables "$tools_dir/perf/arch/s390/entry/syscalls/syscall.tbl"
> > "$outfile" common,64,renameat,rlimit,memfd_secret EM_S390
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__s390x__)
>
> This skips the 32-bit table, though I think that one is already
> planned to be discontinued in the future.

Thankfully we have awesome s390 devs on the mailing list, hopefully
they'll shout out if I'm doing things wrong.

> > +#if defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
> > +EOF
> > +build_tables "$tools_dir/perf/arch/x86/entry/syscalls/syscall_32.tbl"
> > "$outfile" common,32,i386 EM_386
> > +build_tables "$tools_dir/perf/arch/x86/entry/syscalls/syscall_64.tbl"
> > "$outfile" common,64 EM_X86_64
> > +cat >> "$outfile" <<EOF
> > +#endif // defined(ALL_SYSCALLTBL) || defined(__i386__) ||
> > defined(__x86_64__)
>
> This misses the x32 table.

Again I'm carrying forward a behavior. Would it be worth adding x32?

Context: I handled x86 on Android over 10 years ago. x86 phones were
64-bit long before ARM or Apple phones, the kernel was 64-bit but the
userland was forced to be 32-bit. ARM32 has R15 be the program
counter, Sophie Wilson's idea, and when Android's security folks
experimented with ASLR they found it to be free as a consequence of
ARM32. On x86 not x32 then you're in the land of thunk bx, losing a
register and extra instructions. We never did x32 on Android as it
became irrelevant when I brought up x86-64 on Android. The desire for
x32 was for RIP encoding to fix the ASLR issue, not so much the extra
registers, and because Android used to mandate a 32-bit user land
(this was so extreme that even the developer's C to generally ARM
cross-compilers were built as 32-bit binaries). Given x32 was done for
Android, Android never used it, I have a hard time thinking we should
be adding support to perf. That said there is likely other context
that I'm unaware of as I'm surprised x32 still exists. Fwiw, it
saddens me that the x32 experience means that for APX we're still
getting the x86-64 ABI moved forward and silly things like the var
args convention on %al (there for C80 compatibility I once believed -
not really an issue today). On ARM64 registers there are at least 8
callee-save general purpose and floating point registers, so the x86
model of pretty much everything is caller-save means function calls
are expensive and you may need aggressive inlining. Anyway, sorry for
going on so much.

Thanks,
Ian
Arnd Bergmann Feb. 11, 2025, 5:53 p.m. UTC | #5
On Tue, Feb 11, 2025, at 18:24, Ian Rogers wrote:
> On Tue, Feb 11, 2025 at 12:09 AM Arnd Bergmann <arnd@arndb.de> wrote:
>> On Mon, Feb 10, 2025, at 17:51, Ian Rogers wrote:
>> > "$tools_dir/perf/arch/arm64/entry/syscalls/syscall_64.tbl" "$outfile"
>> > common,64,renameat,rlimit,memfd_secret EM_AARCH64
>> > +cat >> "$outfile" <<EOF
>> > +#endif // defined(ALL_SYSCALLTBL) || defined(__arm__) ||
>> > defined(__aarch64__)
>>
>> Hardcoding the set of ABIs in the middle of the script seems
>> too fragile to me, I'm worried that these get out of sync quickly.
>
> I agree, again this is carrying forward a behavior and at least after
> these changes the location is just one place. Do you have any
> suggestions on how to do better?

Not sure, but I have some patches that I was planning to send
that puts these into arch/*/kernel/Makefile.syscalls for all
architectures in a consistent way. Ideally we'd use the same
Makefile contents for tools/perf in order to trivially sync
them, but I'm also happy to hear other suggestions.

Your patches are currently ahead of mine, so I don't want to
hold you up. 

> Fwiw, I wonder a related problem/question that has come up primarily
> with Arnaldo and Howard is in having a way to determine system call
> argument types so that perf trace can pretty print them. For example,
> if via BTF it is found an argument is a "const char*" then it is
> assumed to be a string, but a "char *" is not as it may just be an out
> argument. There's a source for more information in the syzkaller
> project:
> https://github.com/google/syzkaller/blob/master/sys/linux/sys.txt
> Perhaps there's a way to generate this information from the Linux
> build and feed it into perf's build. It is out-of-scope for what I'm
> trying to do here, but I thought it worth a mention given my general
> ignorance on wider things.

Yes, this is also something I've been trying to work on. In particular
the calling conventions for 64-bit register arguments on 32-bit
targets need some help. My plan for this is to have a consistent
mapping of internal (sys_foo()) function names to argument lists,
instead of having some calls that are slightly different depending
on the architecture or ABI.

This should be in a machine-readable format so it can be parsed
not only by perf but also any other project that needs a list
(libc, gdb, qemu, strace, rust, ...)

>> > +#if defined(ALL_SYSCALLTBL) || defined(__mips__)
>> > +EOF
>> > +build_tables
>> > "$tools_dir/perf/arch/mips/entry/syscalls/syscall_n64.tbl" "$outfile"
>> > common,64,n64 EM_MIPS
>> > +cat >> "$outfile" <<EOF
>> > +#endif // defined(ALL_SYSCALLTBL) || defined(__mips__)
>>
>> What about n32/o32? The syscall tables are completely different here.
>
> So perf hasn't historically supported them and no one is asking for
> support. Generating more tables isn't the problem, but we need to have
> some way of determining which table to use for n32/o32. I see
> EF_MIPS_ABI_O32 and EF_MIPS_ABI_O64, so we could add support by
> extending the lookup of the table to be both of e_machine and e_flags.
> I'm less clear on choosing n32. That said, back in the 90s I was
> working to port MIPS code to Itanium via binary translation. Given now
> Itanium is obsolete, I'm not sure it is worth adding complexity for
> the sake of MIPS. I'm happy to do what others feel is best here, but
> my default position is just to carry what the existing behavior is
> forward.

I think the way it actually works on mips is that all syscalls are
allowed in any task and the actual number identifies both the
ABI and the syscall. In some variant, the same is true on arm
(oabi/eabi) and x86-64 (64/x32), but oabi and x32 are both too
obsolete to put much work into them.

There is still some interest in mips, maybe you can poke the
maintainers and see if someone is willing to help out since you
have done the bulk of the work already.

>> > +EOF
>> > +build_tables "$tools_dir/perf/arch/s390/entry/syscalls/syscall.tbl"
>> > "$outfile" common,64,renameat,rlimit,memfd_secret EM_S390
>> > +cat >> "$outfile" <<EOF
>> > +#endif // defined(ALL_SYSCALLTBL) || defined(__s390x__)
>>
>> This skips the 32-bit table, though I think that one is already
>> planned to be discontinued in the future.
>
> Thankfully we have awesome s390 devs on the mailing list, hopefully
> they'll shout out if I'm doing things wrong.

I also remembered that I had a patch to bring the s390 syscall.tbl
into the same format as the others, since the behavior is currently
a bit different for compat calls. I think there is also a chance
that they want to discontinue 32-bit mode entirely, given that
the last 32-bit machine was discontinued over 20 years ago, and
support for native 32-bit kernels got removed 10 years ago
after Debian 8 moved to 64 bit.

If they are confident that there are no more remaining users that
rely on 32-bit binaries, we could both save some work.

>> > +#if defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
>> > +EOF
>> > +build_tables "$tools_dir/perf/arch/x86/entry/syscalls/syscall_32.tbl"
>> > "$outfile" common,32,i386 EM_386
>> > +build_tables "$tools_dir/perf/arch/x86/entry/syscalls/syscall_64.tbl"
>> > "$outfile" common,64 EM_X86_64
>> > +cat >> "$outfile" <<EOF
>> > +#endif // defined(ALL_SYSCALLTBL) || defined(__i386__) ||
>> > defined(__x86_64__)
>>
>> This misses the x32 table.
>
> Again I'm carrying forward a behavior. Would it be worth adding x32?

I would probably document it in the file as an intentional
omission, same as for arm oabi

> That said there is likely other context
> that I'm unaware of as I'm surprised x32 still exists.

There are a handful of people still testing it, and some still
using it, but I agree it completely failed to get enough
traction to be worth maintaining.

I view x32 (and the corresponding arm64 ilp32 mode that never
made it in) mostly as an exercise in benchmark(et)ing, since
it showed noticeably higher results in some versions of specint
and some compiler workloads, compared to both normal 32-bit and
64-bit modes. The time that we already wasted on maintaining
it must have long surpassed any such benefits though, so I
certainly don't want to waste more time on it.

     Arnd
Ian Rogers Feb. 11, 2025, 6:45 p.m. UTC | #6
On Tue, Feb 11, 2025 at 9:53 AM Arnd Bergmann <arnd@arndb.de> wrote:
>
> On Tue, Feb 11, 2025, at 18:24, Ian Rogers wrote:
> > On Tue, Feb 11, 2025 at 12:09 AM Arnd Bergmann <arnd@arndb.de> wrote:
> >> On Mon, Feb 10, 2025, at 17:51, Ian Rogers wrote:
> >> > "$tools_dir/perf/arch/arm64/entry/syscalls/syscall_64.tbl" "$outfile"
> >> > common,64,renameat,rlimit,memfd_secret EM_AARCH64
> >> > +cat >> "$outfile" <<EOF
> >> > +#endif // defined(ALL_SYSCALLTBL) || defined(__arm__) ||
> >> > defined(__aarch64__)
> >>
> >> Hardcoding the set of ABIs in the middle of the script seems
> >> too fragile to me, I'm worried that these get out of sync quickly.
> >
> > I agree, again this is carrying forward a behavior and at least after
> > these changes the location is just one place. Do you have any
> > suggestions on how to do better?
>
> Not sure, but I have some patches that I was planning to send
> that puts these into arch/*/kernel/Makefile.syscalls for all
> architectures in a consistent way. Ideally we'd use the same
> Makefile contents for tools/perf in order to trivially sync
> them, but I'm also happy to hear other suggestions.
>
> Your patches are currently ahead of mine, so I don't want to
> hold you up.
>
> > Fwiw, I wonder a related problem/question that has come up primarily
> > with Arnaldo and Howard is in having a way to determine system call
> > argument types so that perf trace can pretty print them. For example,
> > if via BTF it is found an argument is a "const char*" then it is
> > assumed to be a string, but a "char *" is not as it may just be an out
> > argument. There's a source for more information in the syzkaller
> > project:
> > https://github.com/google/syzkaller/blob/master/sys/linux/sys.txt
> > Perhaps there's a way to generate this information from the Linux
> > build and feed it into perf's build. It is out-of-scope for what I'm
> > trying to do here, but I thought it worth a mention given my general
> > ignorance on wider things.
>
> Yes, this is also something I've been trying to work on. In particular
> the calling conventions for 64-bit register arguments on 32-bit
> targets need some help. My plan for this is to have a consistent
> mapping of internal (sys_foo()) function names to argument lists,
> instead of having some calls that are slightly different depending
> on the architecture or ABI.
>
> This should be in a machine-readable format so it can be parsed
> not only by perf but also any other project that needs a list
> (libc, gdb, qemu, strace, rust, ...)

Awesome, thanks for working on this!

> >> > +#if defined(ALL_SYSCALLTBL) || defined(__mips__)
> >> > +EOF
> >> > +build_tables
> >> > "$tools_dir/perf/arch/mips/entry/syscalls/syscall_n64.tbl" "$outfile"
> >> > common,64,n64 EM_MIPS
> >> > +cat >> "$outfile" <<EOF
> >> > +#endif // defined(ALL_SYSCALLTBL) || defined(__mips__)
> >>
> >> What about n32/o32? The syscall tables are completely different here.
> >
> > So perf hasn't historically supported them and no one is asking for
> > support. Generating more tables isn't the problem, but we need to have
> > some way of determining which table to use for n32/o32. I see
> > EF_MIPS_ABI_O32 and EF_MIPS_ABI_O64, so we could add support by
> > extending the lookup of the table to be both of e_machine and e_flags.
> > I'm less clear on choosing n32. That said, back in the 90s I was
> > working to port MIPS code to Itanium via binary translation. Given now
> > Itanium is obsolete, I'm not sure it is worth adding complexity for
> > the sake of MIPS. I'm happy to do what others feel is best here, but
> > my default position is just to carry what the existing behavior is
> > forward.
>
> I think the way it actually works on mips is that all syscalls are
> allowed in any task and the actual number identifies both the
> ABI and the syscall. In some variant, the same is true on arm
> (oabi/eabi) and x86-64 (64/x32), but oabi and x32 are both too
> obsolete to put much work into them.
>
> There is still some interest in mips, maybe you can poke the
> maintainers and see if someone is willing to help out since you
> have done the bulk of the work already.

Thanks, adding linux-mips@vger.kernel.org. Here is the original
feedback for them for context:
https://lore.kernel.org/lkml/07c5c3ad-5a6d-4eda-95f2-ed16e7504d4c@app.fastmail.com/

> >> > +EOF
> >> > +build_tables "$tools_dir/perf/arch/s390/entry/syscalls/syscall.tbl"
> >> > "$outfile" common,64,renameat,rlimit,memfd_secret EM_S390
> >> > +cat >> "$outfile" <<EOF
> >> > +#endif // defined(ALL_SYSCALLTBL) || defined(__s390x__)
> >>
> >> This skips the 32-bit table, though I think that one is already
> >> planned to be discontinued in the future.
> >
> > Thankfully we have awesome s390 devs on the mailing list, hopefully
> > they'll shout out if I'm doing things wrong.
>
> I also remembered that I had a patch to bring the s390 syscall.tbl
> into the same format as the others, since the behavior is currently
> a bit different for compat calls. I think there is also a chance
> that they want to discontinue 32-bit mode entirely, given that
> the last 32-bit machine was discontinued over 20 years ago, and
> support for native 32-bit kernels got removed 10 years ago
> after Debian 8 moved to 64 bit.
>
> If they are confident that there are no more remaining users that
> rely on 32-bit binaries, we could both save some work.
>
> >> > +#if defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
> >> > +EOF
> >> > +build_tables "$tools_dir/perf/arch/x86/entry/syscalls/syscall_32.tbl"
> >> > "$outfile" common,32,i386 EM_386
> >> > +build_tables "$tools_dir/perf/arch/x86/entry/syscalls/syscall_64.tbl"
> >> > "$outfile" common,64 EM_X86_64
> >> > +cat >> "$outfile" <<EOF
> >> > +#endif // defined(ALL_SYSCALLTBL) || defined(__i386__) ||
> >> > defined(__x86_64__)
> >>
> >> This misses the x32 table.
> >
> > Again I'm carrying forward a behavior. Would it be worth adding x32?
>
> I would probably document it in the file as an intentional
> omission, same as for arm oabi

Ack.

> > That said there is likely other context
> > that I'm unaware of as I'm surprised x32 still exists.
>
> There are a handful of people still testing it, and some still
> using it, but I agree it completely failed to get enough
> traction to be worth maintaining.
>
> I view x32 (and the corresponding arm64 ilp32 mode that never
> made it in) mostly as an exercise in benchmark(et)ing, since
> it showed noticeably higher results in some versions of specint
> and some compiler workloads, compared to both normal 32-bit and
> 64-bit modes. The time that we already wasted on maintaining
> it must have long surpassed any such benefits though, so I
> certainly don't want to waste more time on it.

:-) I ate part of a cake intended as a goodwill gesture toward getting
x32 into Android.

Thanks,
Ian
David Laight Feb. 12, 2025, 1:59 p.m. UTC | #7
On Tue, 11 Feb 2025 18:53:14 +0100
"Arnd Bergmann" <arnd@arndb.de> wrote:

...
> I think the way it actually works on mips is that all syscalls are
> allowed in any task and the actual number identifies both the
> ABI and the syscall. In some variant, the same is true on arm
> (oabi/eabi) and x86-64 (64/x32), but oabi and x32 are both too
> obsolete to put much work into them.

IIRC x86-64 processes can also just make i386 system calls.
Even switching to/from 64bit mode isn't privileged.

	David
diff mbox series

Patch

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 55d6ce9ea52f..793e702f9aaf 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -559,6 +559,14 @@  beauty_ioctl_outdir := $(beauty_outdir)/ioctl
 # Create output directory if not already present
 $(shell [ -d '$(beauty_ioctl_outdir)' ] || mkdir -p '$(beauty_ioctl_outdir)')
 
+syscall_array := $(beauty_outdir)/syscalltbl.c
+syscall_tbl := $(srctree)/tools/perf/trace/beauty/syscalltbl.sh
+syscall_tbl_data := $(srctree)/tools/scripts/syscall.tbl \
+	$(wildcard $(srctree)/tools/perf/arch/*/entry/syscalls/syscall*.tbl)
+
+$(syscall_array): $(syscall_tbl) $(syscall_tbl_data)
+	$(Q)$(SHELL) '$(syscall_tbl)' $(srctree)/tools $@
+
 fs_at_flags_array := $(beauty_outdir)/fs_at_flags_array.c
 fs_at_flags_tbl := $(srctree)/tools/perf/trace/beauty/fs_at_flags.sh
 
@@ -878,6 +886,7 @@  build-dir   = $(or $(__build-dir),.)
 
 prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h archheaders \
 	arm64-sysreg-defs \
+	$(syscall_array) \
 	$(fs_at_flags_array) \
 	$(clone_flags_array) \
 	$(drm_ioctl_array) \
diff --git a/tools/perf/trace/beauty/syscalltbl.sh b/tools/perf/trace/beauty/syscalltbl.sh
new file mode 100755
index 000000000000..635924dc5f59
--- /dev/null
+++ b/tools/perf/trace/beauty/syscalltbl.sh
@@ -0,0 +1,274 @@ 
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# Generate all syscall tables.
+#
+# Each line of the syscall table should have the following format:
+#
+# NR ABI NAME [NATIVE] [COMPAT]
+#
+# NR       syscall number
+# ABI      ABI name
+# NAME     syscall name
+# NATIVE   native entry point (optional)
+# COMPAT   compat entry point (optional)
+
+set -e
+
+usage() {
+       cat >&2 <<EOF
+usage: $0 <TOOLS DIRECTORY> <OUTFILE>
+
+  <TOOLS DIRECTORY>    path to kernel tools directory
+  <OUTFILE>            output header file
+EOF
+       exit 1
+}
+
+if [ $# -ne 2 ]; then
+       usage
+fi
+tools_dir=$1
+outfile=$2
+
+build_tables() {
+	infile="$1"
+	outfile="$2"
+	abis=$(echo "($3)" | tr ',' '|')
+	e_machine="$4"
+
+	if [ ! -f "$infile" ]
+	then
+		echo "Missing file $infile"
+		exit 1
+	fi
+	sorted_table=$(mktemp /tmp/syscalltbl.XXXXXX)
+	grep -E "^[0-9]+[[:space:]]+$abis" "$infile" | sort -n > "$sorted_table"
+
+	echo "static const char *const syscall_num_to_name_${e_machine}[] = {" >> "$outfile"
+	# the params are: nr abi name entry compat
+	# use _ for intentionally unused variables according to SC2034
+	while read -r nr _ name _ _; do
+		echo "	[$nr] = \"$name\"," >> "$outfile"
+	done < "$sorted_table"
+	echo "};" >> "$outfile"
+
+	echo "static const uint16_t syscall_sorted_names_${e_machine}[] = {" >> "$outfile"
+
+	# When sorting by name, add a suffix of 0s upto 20 characters so that
+	# system calls that differ with a numerical suffix don't sort before
+	# those without. This default behavior of sort differs from that of
+	# strcmp used at runtime. Use sed to strip the trailing 0s suffix
+	# afterwards.
+	grep -E "^[0-9]+[[:space:]]+$abis" "$infile" | awk '{printf $3; for (i = length($3); i < 20; i++) { printf "0"; }; print " " $1}'| sort | sed 's/\([a-zA-Z1-9]\+\)0\+ \([0-9]\+\)/\1 \2/' > "$sorted_table"
+	while read -r name nr; do
+		echo "	$nr,	/* $name */" >> "$outfile"
+	done < "$sorted_table"
+	echo "};" >> "$outfile"
+
+	rm -f "$sorted_table"
+}
+
+rm -f "$outfile"
+cat >> "$outfile" <<EOF
+#include <elf.h>
+#include <stdint.h>
+#include <asm/bitsperlong.h>
+#include <linux/kernel.h>
+
+struct syscalltbl {
+       const char *const *num_to_name;
+       const uint16_t *sorted_names;
+       uint16_t e_machine;
+       uint16_t num_to_name_len;
+       uint16_t sorted_names_len;
+};
+
+#if defined(ALL_SYSCALLTBL) || defined(__alpha__)
+EOF
+build_tables "$tools_dir/perf/arch/alpha/entry/syscalls/syscall.tbl" "$outfile" common,64 EM_ALPHA
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__alpha__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__arm__) || defined(__aarch64__)
+EOF
+build_tables "$tools_dir/perf/arch/arm/entry/syscalls/syscall.tbl" "$outfile" common,32,oabi EM_ARM
+build_tables "$tools_dir/perf/arch/arm64/entry/syscalls/syscall_64.tbl" "$outfile" common,64,renameat,rlimit,memfd_secret EM_AARCH64
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__arm__) || defined(__aarch64__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__csky__)
+EOF
+build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,32,csky,time32,stat64,rlimit EM_CSKY
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__csky__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__mips__)
+EOF
+build_tables "$tools_dir/perf/arch/mips/entry/syscalls/syscall_n64.tbl" "$outfile" common,64,n64 EM_MIPS
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__mips__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__hppa__)
+#if __BITS_PER_LONG != 64
+EOF
+build_tables "$tools_dir/perf/arch/parisc/entry/syscalls/syscall.tbl" "$outfile" common,32 EM_PARISC
+echo "#else" >> "$outfile"
+build_tables "$tools_dir/perf/arch/parisc/entry/syscalls/syscall.tbl" "$outfile" common,64 EM_PARISC
+cat >> "$outfile" <<EOF
+#endif //__BITS_PER_LONG != 64
+#endif // defined(ALL_SYSCALLTBL) || defined(__hppa__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__powerpc__) || defined(__powerpc64__)
+EOF
+build_tables "$tools_dir/perf/arch/powerpc/entry/syscalls/syscall.tbl" "$outfile" common,32,nospu EM_PPC
+build_tables "$tools_dir/perf/arch/powerpc/entry/syscalls/syscall.tbl" "$outfile" common,64,nospu EM_PPC64
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__powerpc__) || defined(__powerpc64__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__riscv)
+#if __BITS_PER_LONG != 64
+EOF
+build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,32,riscv,memfd_secret EM_RISCV
+echo "#else" >> "$outfile"
+build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,64,riscv,rlimit,memfd_secret EM_RISCV
+cat >> "$outfile" <<EOF
+#endif //__BITS_PER_LONG != 64
+#endif // defined(ALL_SYSCALLTBL) || defined(__riscv)
+#if defined(ALL_SYSCALLTBL) || defined(__s390x__)
+EOF
+build_tables "$tools_dir/perf/arch/s390/entry/syscalls/syscall.tbl" "$outfile" common,64,renameat,rlimit,memfd_secret EM_S390
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__s390x__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__sh__)
+EOF
+build_tables "$tools_dir/perf/arch/sh/entry/syscalls/syscall.tbl" "$outfile" common,32 EM_SH
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__sh__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__sparc64__) || defined(__sparc__)
+#if __BITS_PER_LONG != 64
+EOF
+build_tables "$tools_dir/perf/arch/sparc/entry/syscalls/syscall.tbl" "$outfile" common,32 EM_SPARC
+echo "#else" >> "$outfile"
+build_tables "$tools_dir/perf/arch/sparc/entry/syscalls/syscall.tbl" "$outfile" common,64 EM_SPARC
+cat >> "$outfile" <<EOF
+#endif //__BITS_PER_LONG != 64
+#endif // defined(ALL_SYSCALLTBL) || defined(__sparc64__) || defined(__sparc__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
+EOF
+build_tables "$tools_dir/perf/arch/x86/entry/syscalls/syscall_32.tbl" "$outfile" common,32,i386 EM_386
+build_tables "$tools_dir/perf/arch/x86/entry/syscalls/syscall_64.tbl" "$outfile" common,64 EM_X86_64
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__xtensa__)
+EOF
+build_tables "$tools_dir/perf/arch/xtensa/entry/syscalls/syscall.tbl" "$outfile" common,32 EM_XTENSA
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__xtensa__)
+
+#if __BITS_PER_LONG != 64
+EOF
+build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,32 EM_NONE
+echo "#else" >> "$outfile"
+build_tables "$tools_dir/scripts/syscall.tbl" "$outfile" common,64 EM_NONE
+echo "#endif //__BITS_PER_LONG != 64" >> "$outfile"
+
+build_outer_table() {
+       e_machine=$1
+       outfile="$2"
+       cat >> "$outfile" <<EOF
+       {
+	      .num_to_name = syscall_num_to_name_$e_machine,
+	      .sorted_names = syscall_sorted_names_$e_machine,
+	      .e_machine = $e_machine,
+	      .num_to_name_len = ARRAY_SIZE(syscall_num_to_name_$e_machine),
+	      .sorted_names_len = ARRAY_SIZE(syscall_sorted_names_$e_machine),
+       },
+EOF
+}
+
+cat >> "$outfile" <<EOF
+static const struct syscalltbl syscalltbls[] = {
+#if defined(ALL_SYSCALLTBL) || defined(__alpha__)
+EOF
+build_outer_table EM_ALPHA "$outfile"
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__alpha__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__arm__) || defined(__aarch64__)
+EOF
+build_outer_table EM_ARM "$outfile"
+build_outer_table EM_AARCH64 "$outfile"
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__arm__) || defined(__aarch64__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__csky__)
+EOF
+build_outer_table EM_CSKY "$outfile"
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__csky__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__mips__)
+EOF
+build_outer_table EM_MIPS "$outfile"
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__mips__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__hppa__)
+EOF
+build_outer_table EM_PARISC "$outfile"
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__hppa__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__powerpc__) || defined(__powerpc64__)
+EOF
+build_outer_table EM_PPC "$outfile"
+build_outer_table EM_PPC64 "$outfile"
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__powerpc__) || defined(__powerpc64__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__riscv)
+EOF
+build_outer_table EM_RISCV "$outfile"
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__riscv)
+
+#if defined(ALL_SYSCALLTBL) || defined(__s390x__)
+EOF
+build_outer_table EM_S390 "$outfile"
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__s390x__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__sh__)
+EOF
+build_outer_table EM_SH "$outfile"
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__sh__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__sparc64__) || defined(__sparc__)
+EOF
+build_outer_table EM_SPARC "$outfile"
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__sparc64__) || defined(__sparc__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
+EOF
+build_outer_table EM_386 "$outfile"
+build_outer_table EM_X86_64 "$outfile"
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__i386__) || defined(__x86_64__)
+
+#if defined(ALL_SYSCALLTBL) || defined(__xtensa__)
+EOF
+build_outer_table EM_XTENSA "$outfile"
+cat >> "$outfile" <<EOF
+#endif // defined(ALL_SYSCALLTBL) || defined(__xtensa__)
+EOF
+build_outer_table EM_NONE "$outfile"
+cat >> "$outfile" <<EOF
+};
+EOF