#!/bin/bash

# This script generates the systemtap syscall database.  It takes the strace
# sources as an input, and generates couple of systemtap tapset files.  Before
# you run this script, make sure that STRACE_SRC points to fresh strace git
# sources.
#
# As of 2/2019, strace source can be obtained by the following command:
#
#    git clone https://github.com/strace/strace strace-code
#
# Functions syscall_name() and syscall_num() are the primary feature front-end.

set -e

STRACE_SRC=${STRACE_SRC:-$HOME/strace-code/src}
TAPSET_SRC=$(readlink -f $(dirname $0)/../tapset)

TAPSET_X86_64=$TAPSET_SRC/linux/x86_64/syscall_num.stp
TAPSET_I386=$TAPSET_SRC/linux/i386/syscall_num.stp
TAPSET_POWERPC=$TAPSET_SRC/linux/powerpc/syscall_num.stp
TAPSET_S390=$TAPSET_SRC/linux/s390/syscall_num.stp
TAPSET_ARM=$TAPSET_SRC/linux/arm/syscall_num.stp
TAPSET_AARCH64=$TAPSET_SRC/linux/arm64/syscall_num.stp
TAPSET_MIPS=$TAPSET_SRC/linux/mips/syscall_num.stp
TAPSET_RISCV=$TAPSET_SRC/linux/riscv/syscall_num.stp

SYSCALLS_32=$(mktemp)
SYSCALLS_64=$(mktemp)

function __init() {
> $SYSCALLS_32
> $SYSCALLS_64
}

function __dump_syscalls() {
    test $2 -eq 64 && __OUT=$SYSCALLS_64 || __OUT=$SYSCALLS_32
    #Need to mung things so BASE_NR replaced with actual number
    processed=$(mktemp)
    cpp -I${STRACE_SRC}/linux/generic $1 -DLINUX_MIPSO32 -DLINUX_MIPSN32 -DLINUX_MIPSN64 > $processed
    cat $processed | tr -d ' ' | awk -v bt=$2 -F'[][\"]' '/^\[[^\]]+\]={[^}]/ {
        printf("__syscall_%s_num2name[%s]=\"%s\"\n", bt, $2, $4);
        printf("__syscall_%s_name2num[\"%s\"]=%s\n", bt, $4, $2)
    }' >> $__OUT
}

function __generate_tapset() {
    __TAPSET_FILE=$1
    __L64=$(wc -l $SYSCALLS_64 | cut -d\  -f1)
    __L32=$(wc -l $SYSCALLS_32 | cut -d\  -f1)

    cat > $__TAPSET_FILE <<EOF01
# This is arch specific syscall table generated by scripts/dump-syscalls.sh

%( arch =="$2" %?
EOF01

    test $__L32 -gt 0 && cat >> $__TAPSET_FILE <<EOF02
global __syscall_32_num2name[$((${__L32} / 2))]
global __syscall_32_name2num[$((${__L32} / 2))]
EOF02

    test $__L64 -gt 0 && cat >> $__TAPSET_FILE <<EOF03
global __syscall_64_num2name[$((${__L64} / 2))]
global __syscall_64_name2num[$((${__L64} / 2))]
EOF03

    cat >> $__TAPSET_FILE <<EOF04
%)

probe init {
%( arch =="$2" %?
EOF04

cat $SYSCALLS_32 $SYSCALLS_64  | sort -t\" -k2 >> $__TAPSET_FILE



    cat >> $__TAPSET_FILE <<EOF05
%)
} /* probe init */
EOF05
}


# ======= x86_64 =======
__init
__dump_syscalls $STRACE_SRC/linux/x86_64/syscallent.h 64
__dump_syscalls $STRACE_SRC/linux/i386/syscallent.h 32
__generate_tapset $TAPSET_X86_64 x86_64

# ======= i386 =======
__init
__dump_syscalls $STRACE_SRC/linux/i386/syscallent.h 32
__generate_tapset $TAPSET_I386 i386

# ======= powerpc =======
__init
__dump_syscalls $STRACE_SRC/linux/powerpc64/syscallent.h 64
__dump_syscalls $STRACE_SRC/linux/powerpc/syscallent.h 32
__generate_tapset $TAPSET_POWERPC powerpc

# ======= s390 =======
__init
__dump_syscalls $STRACE_SRC/linux/s390x/syscallent.h 64
__dump_syscalls $STRACE_SRC/linux/s390/syscallent.h 32
__generate_tapset $TAPSET_S390 s390

# ======= arm =======
__init
__dump_syscalls $STRACE_SRC/linux/arm/syscallent.h 32
__generate_tapset $TAPSET_ARM arm

# ======= aarch64 =======
__init
__dump_syscalls $STRACE_SRC/linux/arm/syscallent.h 32
__dump_syscalls $STRACE_SRC/linux/64/syscallent.h 64
__dump_syscalls $STRACE_SRC/linux/aarch64/syscallent.h 64
__generate_tapset $TAPSET_AARCH64 arm64

# ======= mips =======
__init
__dump_syscalls $STRACE_SRC/linux/mips/syscallent-n64.h 64
__dump_syscalls $STRACE_SRC/linux/mips/syscallent-o32.h 32
__dump_syscalls $STRACE_SRC/linux/mips/syscallent-n32.h 32
__generate_tapset $TAPSET_MIPS mips
# ======= riscv =======
__init
__dump_syscalls $STRACE_SRC/linux/riscv64/syscallent.h 64
# Currently strace doesn't have actual encoding of RISCV32 syscalls.
# However, the call names should match up closely and should be better
# than nothing.
__dump_syscalls $STRACE_SRC/linux/riscv64/syscallent.h 32
__generate_tapset $TAPSET_RISCV riscv

rm -f $SYSCALLS_32 $SYSCALLS_64
