#!/bin/sh # # makewrappers, script to auto-generate wrapper functions # # Copyright (c) 2008-2010 Wind River Systems, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the Lesser GNU General Public License version 2.1 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the Lesser GNU General Public License for more details. # # You should have received a copy of the Lesser GNU General Public License # version 2.1 along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # case $# in 0) echo >&2 "Usage: makewrappers file [...]" exit 1 ;; esac # save old versions test -f "pseudo_wrapfuncs.c" && mv pseudo_wrapfuncs.c pseudo_wrapfuncs.c.old test -f "pseudo_wrapfuncs.h" && mv pseudo_wrapfuncs.h pseudo_wrapfuncs.h.old # create files exec 5>pseudo_wrapfuncs.c exec 6>pseudo_wrapfuncs.h exec 7>pseudo_wrapper_table.c # "cat >&N <&5 <&6 <&7 <&2 'Reading signatures...\n' for file in "$@" do # read lines containing wrappable functions, write wrapper # declarations, definitions, and so on. printf >&2 '[%s]' "$file" while read signature do # skip comments case $signature in \#*) continue;; esac # obtain return type, name, and arguments args=`expr "$signature" : '[^(]*(\(.*\));'` modifiers=`expr "$signature" : '.*; /\* \(.*\) \*/'` return_and_name=`expr "$signature" : '\([^(]*\)('` name=`expr "$return_and_name" : '.*[^a-zA-Z0-9_]\([a-zA-Z0-9_]*\)$'` type=`expr "$return_and_name" : '\(.*[^ ]\) *'"$name"'$'` printf >&2 ' %s' "$name" wrapargnames='' argnames='' # for handling path canonicalization pathnames='' flags='0' dirfd='AT_FDCWD' save_IFS=$IFS IFS=, set -- $args IFS=$save_IFS args='' dummy_args='' optional_arg=false prepend='' depth=0 for arg do # handle optional arguments, like the third arg # to open() if [ $depth -gt 0 ]; then case $arg in *\)*) lcount=`echo $arg | tr -cd '(' | wc -c` rcount=`echo $arg | tr -cd ')' | wc -c` depth=`expr $depth + $lcount - $rcount` prepend="${prepend:+$prepend,}$arg" arg="" ;; *) prepend="${prepend:+$prepend,}$arg" arg="" ;; esac else case $arg in *\(*) lcount=`echo $arg | tr -cd '(' | wc -c` rcount=`echo $arg | tr -cd ')' | wc -c` depth=`expr $depth + $lcount - $rcount` prepend="${prepend:+$prepend,}$arg" arg="" ;; esac fi # we're inside nested ()s if [ $depth -gt 0 ]; then continue fi arg="$prepend$arg" # strip whitespace arg=${arg# } arg=${arg% } prepend='' case $arg in ...*) optional_arg=true args="$args${args:+, }..." dummy_args="$dummy_args${dummy_args:+, }..." arg=`expr "$arg" : '\.\.\.{\(.*\)}'` argname=`expr "$arg" : '.*[^a-zA-Z0-9_]\([a-zA-Z0-9_]*\)$'` argnames="$argnames${argnames:+, }$argname" wrapargnames="$wrapargnames${wrapargnames:+, }$argname" # we need this to extract and pass the argument optional_decl=$arg optional_prev=$prev_argname optional_name=$argname optional_type=`expr "$arg" : '\(.*[^ ]\) *'"$argname"'$'` ;; *\(*) # function pointer argname=`expr "$arg" : '[^(]*(\*\([a-zA-Z0-9_]*\).*'` args="$args${args:+, }$arg" dummy_args="$dummy_args${dummy_args:+, }$arg __attribute__((unused))" wrapargnames="$wrapargnames${wrapargnames:+, }$argname" argnames="$argnames${argnames:+, }$argname" prev_argname=$argname ;; *) argname=`expr "$arg" : '.*[^a-zA-Z0-9_](*\([a-zA-Z0-9_]*\))*(*)*$'` args="$args${args:+, }$arg" dummy_args="$dummy_args${dummy_args:+, }$arg __attribute__((unused))" # special handling for canonicalization # set this before changing path -> rpath, for guts files wrapargnames="$wrapargnames${wrapargnames:+, }$argname" case $argname in *path) pathnames="${pathnames+${pathnames} }$argname" argname="r$argname" ;; dirfd) dirfd='dirfd';; flags) flags='flags';; esac argnames="$argnames${argnames:+, }$argname" prev_argname=$argname ;; esac done # see whether flags was overridden flags_tmp=`expr "$modifiers" : 'flags=\([^ ]*\)'` if [ -n "$flags_tmp" ]; then flags=$flags_tmp fi decl_paths='' alloc_paths='' free_paths='' # any argument ending in "path" is presumed to need to be # converted to a chroot path. To avoid this, name the # argument something else (e.g. "template" for mkstemp) for p in $pathnames; do decl_paths="${decl_paths} char *r$p = (char *) $p;" alloc_paths="${alloc_paths} r$p = pseudo_root_path(__func__, __LINE__, $dirfd, $p, $flags);" free_paths="${free_paths} free(r$p);" done # determine default return value. is_void=false case $type in int|ssize_t|long) default_value=-1;; uid_t|gid_t) default_value=0;; *'*') default_value=NULL;; void) is_void=true default_value='' ;; *) echo >&2 " Unknown type '$type'." ; exit 1 ;; esac if $is_void; then write_return() { printf "return" } write_assign() { printf "(void)" } write_decl() { : # do nothing } else write_return() { printf "return %s" "$1" } write_assign() { printf "%s =" "$1" } write_decl() { printf "%s %s = %s;" "$1" "$2" "$3" } fi # create the wrappers # first the dummy, and the function pointer: cat >&5 <&5 <&5 <&5 < 0) { if (real_$name) { $(write_assign rc) (*real_$name)($argnames); } else { $(write_assign rc) dummy_$name($argnames); } } else { $alloc_paths $(write_assign rc) wrap_$name($argnames); $free_paths } save_errno = errno; pseudo_droplock(); sigprocmask(SIG_SETMASK, &saved, NULL); errno = save_errno; pseudo_debug(4, "completed: $name\n"); $(write_return rc); } else { pseudo_droplock(); sigprocmask(SIG_SETMASK, &saved, NULL); pseudo_debug(4, "completed: $name\n"); $(write_return "dummy_$name($argnames)"); } } EOF # and now the signature part for the actual implementation: # and the guts include file. # the wrapper function is actually declared in # pseudo_wrapper.c, with guts implemented in a separate # file with comments indicating the signature. guts="guts/$name.c" # the actual wrapper function, including argument setup if $optional_arg; then cat >&5 << EOF static $type wrap_$name($args) { $(write_decl "$type" "rc" "$default_value") $optional_decl; va_list ap; va_start(ap, $optional_prev); $optional_name = va_arg(ap, $optional_type); va_end(ap); #include "$guts" $(write_return rc); } EOF else cat >&5 << EOF static $type wrap_$name($args) { $(write_decl "$type" "rc" "$default_value") #include "$guts" $(write_return rc); } EOF fi # if the guts file didn't already exist, create a default. if test ! -f "$guts"; then if $optional_arg; then cat > "$guts" < "$guts" <&6 <&7 <&2 '.\n' # sentinel values cat >&7 <