summaryrefslogtreecommitdiff
path: root/libc/sysdeps/unix/make-syscalls.sh
diff options
context:
space:
mode:
Diffstat (limited to 'libc/sysdeps/unix/make-syscalls.sh')
-rw-r--r--libc/sysdeps/unix/make-syscalls.sh342
1 files changed, 342 insertions, 0 deletions
diff --git a/libc/sysdeps/unix/make-syscalls.sh b/libc/sysdeps/unix/make-syscalls.sh
new file mode 100644
index 000000000..0ec8b28fd
--- /dev/null
+++ b/libc/sysdeps/unix/make-syscalls.sh
@@ -0,0 +1,342 @@
+#! /bin/sh
+
+# Usage: make-syscalls.sh ../sysdeps/unix/common
+# Expects $sysdirs in environment.
+
+##############################################################################
+
+# Syscall Signature Key Letters for BP Thunks:
+#
+# a: unchecked address (e.g., 1st arg to mmap)
+# b: non-NULL buffer (e.g., 2nd arg to read; return value from mmap)
+# B: optionally-NULL buffer (e.g., 4th arg to getsockopt)
+# f: buffer of 2 ints (e.g., 4th arg to socketpair)
+# F: 3rd arg to fcntl
+# i: scalar (any signedness & size: int, long, long long, enum, whatever)
+# I: 3rd arg to ioctl
+# n: scalar buffer length (e.g., 3rd arg to read)
+# N: pointer to value/return scalar buffer length (e.g., 6th arg to recvfrom)
+# p: non-NULL pointer to typed object (e.g., any non-void* arg)
+# P: optionally-NULL pointer to typed object (e.g., 2nd argument to gettimeofday)
+# s: non-NULL string (e.g., 1st arg to open)
+# S: optionally-NULL string (e.g., 1st arg to acct)
+# v: vararg scalar (e.g., optional 3rd arg to open)
+# V: byte-per-page vector (3rd arg to mincore)
+# W: wait status, optionally-NULL pointer to int (e.g., 2nd arg of wait4)
+
+ptr='[abBfFINpPsSWV]' # all pointer keyletters
+int='[inv]' # all scalar keyletters
+typ='[ifnNpP]' # typed-arg keyletters: we capture type for use in thunk
+
+##############################################################################
+
+thisdir=$1; shift
+
+echo ''
+echo \#### DIRECTORY = $thisdir
+# Check each sysdep dir with higher priority than this one,
+# and remove from $calls all the functions found in other dirs.
+# Punt when we reach the directory defining these syscalls.
+sysdirs=`for dir in $sysdirs; do
+ test $dir = $thisdir && break; echo $dir; done`
+echo \#### SYSDIRS = $sysdirs
+
+# Get the list of system calls for this directory.
+calls=`sed 's/#.*$//
+/^[ ]*$/d' $thisdir/syscalls.list`
+
+calls=`echo "$calls" |
+while read file caller rest; do
+ # Remove each syscall that is implemented by a file in $dir.
+ # If a syscall specified a "caller", then only compile that syscall
+ # if the caller function is also implemented in this directory.
+ srcfile=-;
+ for dir in $sysdirs; do
+ { test -f $dir/$file.c && srcfile=$dir/$file.c; } ||
+ { test -f $dir/$file.S && srcfile=$dir/$file.S; } ||
+ { test -f $dir/$file.s && srcfile=$dir/$file.s; } ||
+ { test x$caller != x- &&
+ { { test -f $dir/$caller.c && srcfile=$dir/$caller.c; } ||
+ { test -f $dir/$caller.S && srcfile=$dir/$caller.S; } ||
+ { test -f $dir/$caller.s && srcfile=$dir/$caller.s; }; }; } && break;
+ done;
+ echo $file $srcfile $caller $rest;
+done`
+
+# Any calls left?
+test -n "$calls" || exit 0
+
+# Emit rules to compile the syscalls remaining in $calls.
+echo "$calls" |
+while read file srcfile caller syscall args strong weak; do
+
+ case x"$syscall" in
+ x-) callnum=_ ;;
+ *)
+ # Figure out if $syscall is defined with a number in syscall.h.
+ callnum=-
+ eval `{ echo "#include <sysdep.h>";
+ echo "callnum=SYS_ify ($syscall)"; } |
+ $asm_CPP -D__OPTIMIZE__ - |
+ sed -n -e "/^callnum=.*$syscall/d" \
+ -e "/^\(callnum=\)[ ]*\(.*\)/s//\1'\2'/p"`
+ ;;
+ esac
+
+ cancellable=
+ noerrno=
+ case $args in
+ C*) cancellable=-cancel; args=`echo $args | sed 's/C:\?//'`;;
+ E*) noerrno=_NOERRNO; args=`echo $args | sed 's/E:\?//'`;;
+ V*) noerrno=_ERRVAL; args=`echo $args | sed 's/V:\?//'`;;
+ esac
+
+ # Derive the number of arguments from the argument signature
+ case $args in
+ [0-9]) nargs=$args;;
+ ?:) nargs=0;;
+ ?:?) nargs=1;;
+ ?:??) nargs=2;;
+ ?:???) nargs=3;;
+ ?:????) nargs=4;;
+ ?:?????) nargs=5;;
+ ?:??????) nargs=6;;
+ ?:???????) nargs=7;;
+ ?:????????) nargs=8;;
+ ?:?????????) nargs=9;;
+ esac
+
+ # Make sure only the first syscall rule is used, if multiple dirs
+ # define the same syscall.
+ echo ''
+ echo "#### CALL=$file NUMBER=$callnum ARGS=$args SOURCE=$srcfile"
+
+ case x$srcfile"$callnum" in
+ x--)
+ # Undefined callnum for an extra syscall.
+ if [ x$caller != x- ]; then
+ if [ x$noerrno != x ]; then
+ echo >&2 "$0: no number for $fileno, no-error syscall ($strong $weak)"
+ exit 2
+ fi
+ echo "unix-stub-syscalls += $strong $weak"
+ fi
+ ;;
+ x*-) ;; ### Do nothing for undefined callnum
+ x-*)
+ echo "ifeq (,\$(filter $file,\$(unix-syscalls)))"
+
+ case $weak in
+ *@*)
+ # The versioned symbols are only in the shared library.
+ echo "ifneq (,\$(filter .os,\$(object-suffixes)))"
+ ;;
+ esac
+ # Accumulate the list of syscall files for this directory.
+ echo "unix-syscalls += $file"
+ test x$caller = x- || echo "unix-extra-syscalls += $file"
+
+ # Emit a compilation rule for this syscall.
+ case $weak in
+ *@*)
+ # The versioned symbols are only in the shared library.
+ echo "\
+shared-only-routines += $file
+\$(objpfx)${file}.os: \\"
+ ;;
+ *)
+ echo "\
+\$(foreach o,\$(object-suffixes),\$(objpfx)$file\$o) \
+\$(foreach o,\$(object-suffixes),\$(objpfx)ptw-$file\$o) \
+\$(objpfx)rtld-$file.os: \\"
+ ;;
+ esac
+
+ echo " \$(common-objpfx)s-proto$cancellable.d"
+ case x"$callnum" in
+ x_)
+ echo "\
+ (echo '/* Dummy module requested by syscalls.list */'; \\"
+ ;;
+ x*)
+ echo "\
+ \$(make-target-directory)
+ (echo '#include <sysdep$cancellable.h>'; \\
+ echo 'PSEUDO$noerrno ($strong, $syscall, $nargs)'; \\
+ echo ' ret$noerrno'; \\
+ echo 'PSEUDO_END$noerrno($strong)'; \\
+ echo 'libc_hidden_def ($strong)'; \\"
+ ;;
+ esac
+
+ # Append any weak aliases or versions defined for this syscall function.
+
+ # A shortcoming in the current gas is that it will only allow one
+ # version-alias per symbol. So we create new strong aliases as needed.
+ vcount=""
+
+ for name in $weak; do
+ case $name in
+ *@@*)
+ base=`echo $name | sed 's/@@.*//'`
+ ver=`echo $name | sed 's/.*@@//'`
+ if test -z "$vcount" ; then
+ source=$strong
+ vcount=1
+ else
+ source="${strong}_${vcount}"
+ vcount=`expr $vcount + 1`
+ echo " echo 'strong_alias ($strong, $source)'; \\"
+ fi
+ echo " echo 'default_symbol_version($source, $base, $ver)'; \\"
+ ;;
+ *@*)
+ base=`echo $name | sed 's/@.*//'`
+ ver=`echo $name | sed 's/.*@//'`
+ if test -z "$vcount" ; then
+ source=$strong
+ vcount=1
+ else
+ source="${strong}_${vcount}"
+ vcount=`expr $vcount + 1`
+ echo " echo 'strong_alias ($strong, $source)'; \\"
+ fi
+ echo " echo 'symbol_version($source, $base, $ver)'; \\"
+ ;;
+ !*)
+ name=`echo $name | sed 's/.//'`
+ echo " echo 'strong_alias ($strong, $name)'; \\"
+ echo " echo 'libc_hidden_def ($name)'; \\"
+ ;;
+ *)
+ echo " echo 'weak_alias ($strong, $name)'; \\"
+ echo " echo 'libc_hidden_weak ($name)'; \\"
+ ;;
+ esac
+ done
+
+ # And finally, pipe this all into the compiler.
+ echo ' ) | $(compile-syscall)'
+
+ case $weak in
+ *@*)
+ # The versioned symbols are only in the shared library.
+ echo endif
+ ;;
+ esac
+
+ echo endif
+ ;;
+ esac
+
+ case x"$callnum",$srcfile,$args in
+ x[_-],-,* | x*,*.[sS],*V*) ;;
+ x*,-,*$ptr* | x*,*.[sS],*$ptr*)
+
+ nv_weak=`for name in $weak; do
+ case $name in
+ *@*) ;;
+ *) echo $name;;
+ esac; done`
+
+ # choose the name with the fewest leading underscores, preferably none
+ set `echo $strong $nv_weak |tr '@ \t' ' \n\n' |sort -r`
+ callname=$1
+
+ # convert signature string to individual numbered arg names
+ # e.g., i:ipbN -> i0 i1 p2 b3 N4
+ set `echo $args |
+ sed -e 's/^\(.\):\(.*\)/\2 <\10>/' \
+ -e 's/^\([^ ]\)\(.*\)/\2 <\11>/' \
+ -e 's/^\([^ ]\)\(.*\)/\2 <\12>/' \
+ -e 's/^\([^ ]\)\(.*\)/\2 <\13>/' \
+ -e 's/^\([^ ]\)\(.*\)/\2 <\14>/' \
+ -e 's/^\([^ ]\)\(.*\)/\2 <\15>/' \
+ -e 's/^\([^ ]\)\(.*\)/\2 <\16>/' \
+ -e 's/^\([^ ]\)\(.*\)/\2 <\17>/' \
+ -e 's/^\([^ ]\)\(.*\)/\2 <\18>/' \
+ -e 's/^\([^ ]\)\(.*\)/\2 <\19>/'`
+ rtn=$1; shift
+ args=$*
+ arglist=`echo $* |sed 's/ /, /g'`
+
+ # The best way to understand what's going on here is to examine
+ # the output in BUILDDIR/sysd-syscalls.
+
+ # generate makefile envelope & rule head
+ echo "ifeq (,\$(filter $file,\$(bp-thunks)))"
+ echo "bp-thunks += $file"
+ echo "\$(objpfx)\$(bppfx)$file.ob: \$(common-objpfx)s-proto-bp.d"
+
+ # generate macro head
+ echo " (echo '#define $callname(`echo $arglist | \
+ sed -e 's/[<>]//g'`) `echo $rtn | \
+ sed -e 's/<\('$typ'0\)>/\1v;/g' \
+ -e 's/<\(b0\)>/x0; extern char \1v;/g'` \\'; \\"
+
+ # generate extern decls of dummy variables for each arg
+ echo " echo '`echo $args | \
+ sed -e 's/<\('$typ'[1-9]\)>/extern \1, \1v;/g' \
+ -e 's/<\([abBFIsSV][1-9]\)>/extern char \1v;/g' \
+ -e 's/<\([Wv][1-9]\)>/extern int \1v;/g'` \\'; \\"
+
+ # generate bounded-pointer thunk declarator
+ echo " echo '`echo $rtn | \
+ sed -e 's/<\('$ptr'0\)>/__typeof (\1v) *__bounded/g' \
+ -e 's/<\('$int'0\)>/__typeof (\1v)/g'` BP_SYM ($strong) (`echo $arglist | \
+ sed -e 's/<\('$ptr'[1-9]\)>/__typeof (\1v) *__bounded \1a/g' \
+ -e 's/<\('$int'[1-9]\)>/__typeof (\1v) \1a/g'`) { \\'; \\"
+
+ # generate extern primitive syscall declaration
+ echo " echo ' extern `echo $rtn | \
+ sed -e 's/<\('$ptr'0\)>/__typeof (\1v) *__unbounded/g' \
+ -e 's/<\('$int'0\)>/__typeof (\1v)/g'` ($callname) (`echo $arglist | \
+ sed -e 's/<\('$ptr'[1-9]\)>/__typeof (\1v) *__unbounded/g' \
+ -e 's/<\('$int'[1-9]\)>/__typeof (\1v)/g'`); \\'; \\"
+
+ # generate call the primtive system call, optionally wrapping bounds
+ # around the result if the signature's return keyletter is `b'.
+ echo " echo ' return `echo $rtn |
+ sed -e 's/<b0>/BOUNDED_N (/' \
+ -e 's/<.0>//'`($callname) (`echo $arglist | \
+ sed -e 's/<\(a[1-9]\)>/__ptrvalue (\1a)/g' \
+ -e 's/<\(n[1-9]\)>, <\(V[1-9]\)>/\1a, CHECK_N_PAGES (\2a, \1a)/g' \
+ -e 's/<\(b[1-9]\)>, <\(n[1-9]\)>/CHECK_N (\1a, \2a), \2a/g' \
+ -e 's/<\(b[1-9]\)>, <\(N[1-9]\)>/CHECK_N (\1a, *CHECK_1 (\2a)), __ptrvalue (\2a)/g' \
+ -e 's/<\(B[1-9]\)>, <\(n[1-9]\)>/CHECK_N_NULL_OK (\1a, \2a), \2a/g' \
+ -e 's/<\(B[1-9]\)>, <\(N[1-9]\)>/CHECK_N_NULL_OK (\1a, *CHECK_1 (\2a)), __ptrvalue (\2a)/g' \
+ -e 's/<\(f[1-9]\)>/CHECK_N (\1a, 2)/g' \
+ -e 's/<\(i[1-9]\)>, <\(F[1-9]\)>/\1a, CHECK_FCNTL (\2a, \1a)/g' \
+ -e 's/<\(i[1-9]\)>, <\(I[1-9]\)>/\1a, CHECK_IOCTL (\2a, \1a)/g' \
+ -e 's/<\(p[1-9]\)>/CHECK_1 (\1a)/g' \
+ -e 's/<\([PW][1-9]\)>/CHECK_1_NULL_OK (\1a)/g' \
+ -e 's/<\(s[1-9]\)>/CHECK_STRING (\1a)/g' \
+ -e 's/<\(S[1-9]\)>/CHECK_STRING_NULL_OK (\1a)/g' \
+ -e 's/<\([ivn][1-9]\)>/\1a/g'`)`echo $rtn $args |
+ sed -e 's/<b0>.*<\(n[1-9]\)>.*/, \1a)/' \
+ -e 's/<.0>.*//'`; \\'; \\"
+
+ echo " echo '} \\'; \\"
+
+ echo " echo 'libc_hidden_def (BP_SYM ($strong)) \\'; \\"
+
+ # generate thunk aliases
+ for name in $nv_weak; do
+ echo " echo 'weak_alias (BP_SYM ($strong), BP_SYM ($name)) \\'; \\"
+ echo " echo 'libc_hidden_weak (BP_SYM ($name)) \\'; \\"
+ done
+
+ # wrap up
+ echo "\
+ echo ''; \\
+ echo '#include <bp-thunks.h>'; \\
+ ) | \$(COMPILE.c) -x c -o \$@ -"
+### Use this for debugging intermediate output:
+### ) >\$(@:.ob=.c)
+### \$(subst -c,-E,\$(COMPILE.c)) -o \$(@:.ob=.ib) \$(@:.ob=.c)
+### \$(COMPILE.c) -x cpp-output -o \$@ \$(@:.ob=.ib)"
+ echo endif
+ ;;
+ esac
+
+done