#!/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 3/2017, strace source can be obtained by the following command:
#
#    git clone https://git.code.sf.net/p/strace/code strace-code
#
# Functions syscall_name() and syscall_num() are the primary feature front-end.

set -e

STRACE_SRC=${STRACE_SRC:-$HOME/strace-code}
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

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
    cat $1 | tr -d ' ' | awk -v bt=$2 -F'[][\"]' '/^\[[0-9]+\]={[^}]/ {
        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

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 {
EOF04

cat $SYSCALLS_32 >> $__TAPSET_FILE
cat $SYSCALLS_64 >> $__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

# ======= i386 =======
__init
__dump_syscalls $STRACE_SRC/linux/i386/syscallent.h 32
__generate_tapset $TAPSET_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

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

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

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

# ======= 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

rm -f $SYSCALLS_32 $SYSCALLS_64
