#!/usr/bin/env bash
set -eu

OUTDIR=$1
ARCH=$2
ABI=$3

# architecture-specific cppflags
declare -A AFLAGS
AFLAGS[arm]="-D__ARM_EABI__"

AFLAGS[x32]="-D__ILP32__"
AFLAGS[x86_64]="-D__LP64__"

AFLAGS[riscv64]="-D__LP64__"

if ! [ -z ${AFLAGS[$ABI]+x} ]; then
	flags=${AFLAGS[$ABI]}
else
	flags=""
fi

INC_DEF=/usr/src/linux
p_linux="${LINUX_SRC:-$INC_DEF}"

TMP=$(mktemp -d)
make -C "$p_linux" ARCH="$ARCH" O="$TMP" headers_install

# errors
cpp -D__"$ABI"__ -undef -dM "$TMP/usr/include/asm/errno.h" -I"$TMP/usr/include" | sort -nrk3 | awk '
BEGIN {
	FS=" "
	print "#ifndef KIplatform_error\n\
#define KIplatform_error\n\
\n\
enum k_platform_error {"
}

{
	if ($2 !~ "^_"){
		ids[$2] = $3
		if ($3 ~ /^[0-9]+$/) val=$3
		else val=ids[$3]
		printf("\tk_platform_error_%s = %d,\n", $2, val)
	}
}

END {
	print "};\n\
\n\
#endif"
}
' > "$OUTDIR/error_table.h"

# syscalls
cpp -dM -undef "$TMP/usr/include/asm/unistd.h" -I"$TMP/usr/include" \
-D"${ABI^^}" -D"__${ABI}__" ${flags} | awk '
BEGIN {
	FS=" "
	print "#include <stdio.h>\n\
		#include <asm/unistd.h>\n\
		int main(void) {\
		puts(\"#ifndef KIplatform_syscall\");\
		puts(\"#define KIplatform_syscall\\n\");\
		puts(\"enum k_platform_syscall {\");"
}

{
	if ($2 ~ "(^__NR_)" && $2 !~ "NR3264")
	{
		sub("^.*_", "", $2)
		calls[$2]++
	}
}

END {
	for (call in calls) {
		printf("#ifdef __NR_%s\n", call)
		printf("printf(\"\\tk_platform_syscall_%s = %%d,\\n\", __NR_%s);\n", call, call)
		printf("#endif\n")
	}
	print "puts(\"};\\n\\n#endif\");\n\
	return 0;\n}"
}' | gcc -x c -U__LP64__ -U__ILP32__ -U__i386__ -D"${ABI^^}" \
-D"__${ABI}__" ${flags} -I"$TMP/usr/include" -o "$TMP/ls_calls" -

"$TMP/ls_calls" > "$OUTDIR/system_calls.h"

rm -rf "$TMP"
