| #!/bin/sh |
| |
| # ********************************************************** |
| # Copyright (c) 2011-2022 Google, Inc. All rights reserved. |
| # Copyright (c) 2002-2010 VMware, Inc. All rights reserved. |
| # ********************************************************** |
| |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are met: |
| # |
| # * Redistributions of source code must retain the above copyright notice, |
| # this list of conditions and the following disclaimer. |
| # |
| # * Redistributions in binary form must reproduce the above copyright notice, |
| # this list of conditions and the following disclaimer in the documentation |
| # and/or other materials provided with the distribution. |
| # |
| # * Neither the name of VMware, Inc. nor the names of its contributors may be |
| # used to endorse or promote products derived from this software without |
| # specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| # ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE |
| # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
| # DAMAGE. |
| |
| # Copyright (c) 2001-2002 Massachusetts Institute of Technology |
| # Copyright (c) 2001-2002 Hewlett-Packard Company |
| |
| ########################################################################### |
| ## |
| ## DynamoRIO @name@ script for Linux |
| ## |
| ## Usage for drrun or drinject: |
| ## For a single client, use the -c form and separate the application with --: |
| ## @name@ [-v] [-debug] [-dr_home <path>] [-logdir <path>] |
| ## [<dr_options>]* -c <path> [client_ops]* |
| ## -- <executable> [args ...] |
| ## |
| ## For multiple clients, use either of these forms: |
| ## @name@ [-v] [-debug] [-dr_home <path>] [-logdir <path>] |
| ## -client <path> <id> "<client_ops>" [<dr_options>]* |
| ## -- <executable> [args ...] |
| ## |
| ## @name@ [-v] [-debug] [-dr_home <path>] [-ops <dr_options>]* |
| ## [-logdir <path>] -client <path> <executable> [args ...] |
| ## |
| ## For drconfig, use the -reg or -unreg options described below. |
| ## |
| ## Option explanation: |
| ## [-v] Verbose output |
| ## [-debug] Use debug build of DynamoRIO (release is default) |
| ## [-@archother@] Use @archother@-bit DynamoRIO (default is @archdefault@-bit). This |
| ## should match what the client library and executable |
| ## being run were compiled for. |
| ## [-norun] Requests that an application NOT be run under DR |
| ## control. Useful for following all child processes |
| ## except a blocklist. DR will still be loaded, and |
| ## the app API available. |
| ## [-reg <executable>] Only for drconfig. Creates configuration file for |
| ## the specified application name. |
| ## [-unreg <executable>] Only for drconfig. Removes configuration file for |
| ## the specified application name. |
| ## [-dr_home <path>] Path to the DynamoRIO install. |
| ## Defaults to .. from @name@; may also be omitted |
| ## if DYNAMORIO_HOME is defined in the environment. |
| ## [-ops <dr_options>] DynamoRIO options (such as -stderr_mask 0xc |
| ## or -opt_memory: see docs). Can also be specified |
| ## with DYNAMORIO_OPTIONS in the environment. |
| ## Can be repeated. |
| ## If the application is separated by "--", the |
| ## "-ops" is not required. |
| ## [-logdir <path>] Path to logging directory. Defaults to ../logs from |
| ## @name@; may also be omitted if DYNAMORIO_LOGDIR |
| ## is defined in the environment. |
| ## [-c <path> <options>*] Registers one client to run alongside DR. Assigns |
| ## the client an id of 0. All remaining arguments |
| ## until the -- arg before the app are interpreted as |
| ## client options. Must come after all drrun and DR |
| ## ops. Incompatible with -client. Requires using -- |
| ## to separate the app executable. |
| ## [-client <path> <ID> "<options>"] |
| ## Register one or more clients to run alongside DR. |
| ## This option is only valid when registering a |
| ## process. The -client option takes three arguments: |
| ## the full path to a client library, a unique 8-digit |
| ## hex ID, and an optional list of client options |
| ## (use "" to specify no options). Multiple clients |
| ## can be installed via multiple -client options. In |
| ## this case, clients specified first on the command |
| ## line have higher priority. Neither the path nor |
| ## the options may contain semicolon characters. |
| ## <executable> [args...] The executable to run under DynamoRIO (and the args |
| ## to pass to it if running now). |
| |
| lib=release |
| arch=@archdefault@ |
| # drconfig: config=1, runapp=0 |
| # drrun: config=1, runapp=1 |
| # drinject: config=0, runapp=1 |
| config=@config@ |
| runapp=@runapp@ |
| static=@static@ |
| |
| default_home_rel="`dirname $0`/.." |
| default_home=`cd $default_home_rel ; pwd` |
| client_list="" |
| rununder=1 |
| unreg=0 |
| app="" |
| |
| if [ "$1" = "" ] || [ "$1" = "-h" ] || [ "$1" = "-help" ] || [ "$1" = "--help" ] |
| then |
| # sed would be more precise but may not be available |
| head -n 101 $0 | tail -n 65 |
| exit |
| fi |
| |
| early="" |
| verbose="" |
| specified_ops="" |
| # Read options |
| while [ "$1" = "-v" ] || [ "$1" = "-debug" ] || [ "$1" = "-dr_home" ] || \ |
| [ "$1" = "-ops" ] || [ "$1" = "-logdir" ] || [ "$1" = "-client" ] || \ |
| [ "$1" = "-32" ] || [ "$1" = "-64" ] || [ "$1" = "-norun" ] || \ |
| [ "$1" = "-reg" ] || [ "$1" = "-unreg" ] || [ "$1" = "-early" ] |
| do |
| |
| if [ "$1" = "-early" ] |
| then |
| early=yes |
| specified_ops=yes |
| if [ -n "$ops" ] |
| then |
| ops="$ops -early_inject" |
| else |
| ops="-early_inject" |
| fi |
| shift |
| fi |
| |
| if [ "$1" = "-v" ] |
| then |
| verbose=yes |
| shift |
| fi |
| |
| if [ "$1" = "-debug" ] |
| then |
| lib=debug |
| shift |
| fi |
| |
| if [ "$1" = "-norun" ] |
| then |
| rununder=0 |
| shift |
| fi |
| |
| if [ "$1" = "-reg" ] && [ "$config" = "1" ] |
| then |
| shift |
| app="$1" |
| shift |
| fi |
| |
| if [ "$1" = "-unreg" ] && [ "$config" = "1" ] |
| then |
| unreg=1 |
| shift |
| app="$1" |
| shift |
| fi |
| |
| if [ "$1" = "-32" ] |
| then |
| arch=32 |
| shift |
| fi |
| |
| if [ "$1" = "-64" ] |
| then |
| arch=64 |
| shift |
| fi |
| |
| if [ "$1" = "-dr_home" ] |
| then |
| shift |
| DYNAMORIO_HOME="$1" |
| shift |
| fi |
| |
| if [ "$1" = "-ops" ] |
| then |
| shift |
| specified_ops=yes |
| if [ -n "$ops" ] |
| then |
| ops="$ops $1" |
| else |
| ops="$1" |
| fi |
| shift |
| fi |
| |
| if [ "$1" = "-logdir" ] |
| then |
| shift |
| logdir=$1 |
| shift |
| fi |
| |
| if [ "$1" = "-client" ] |
| then |
| shift |
| client="$1" |
| shift |
| client_id="$1" |
| shift |
| client_ops="$1" |
| shift |
| # setup client |
| if [ ! -n "$client" ] || [ ! -n "$client_id" ] |
| then |
| echo "ERROR - client not fully specified" |
| echo "$usage" |
| exit |
| fi |
| if [ ! -e $client ] |
| then |
| echo "ERROR - client lib $client not found" |
| echo "$usage" |
| exit |
| fi |
| # convert to absolute path |
| client=`cd \`dirname $client\` ; pwd`/`basename $client` |
| # add to list now in case multiple |
| if [ -n "$client_list" ] |
| then |
| client_list="${client_list};${client};${client_id};${client_ops}" |
| else |
| client_list="${client};${client_id};${client_ops}" |
| fi |
| fi |
| |
| done |
| |
| # if there are still options, assume user is using -- to separate and |
| # pass through options to DR. we do not handle mixing DR options with |
| # script options: DR must come last. we would need to generate |
| # code here from optionsx.h to do otherwise, or to sanity check |
| # the DR options here. |
| case "$1" in |
| -*) |
| specified_ops=yes |
| while [ "$1" != "--" ] && [ "$1" != "" ] && [ "$1" != "-c" ] |
| do |
| if [ -n "$ops" ] |
| then |
| ops="$ops $1" |
| else |
| ops="$1" |
| fi |
| shift |
| done |
| |
| # Support alternative client specification: |
| # drrun [script ops...] [dr ops...] -c <client> [client ops...] -- app |
| if [ "$1" = "-c" ] |
| then |
| shift |
| client="$1" |
| shift |
| client_id=0 |
| client_ops="" |
| # setup client |
| if [ ! -n "$client" ] |
| then |
| echo "ERROR - client not fully specified" |
| echo "$usage" |
| exit |
| fi |
| if [ ! -e $client ] |
| then |
| echo "ERROR - client lib $client not found" |
| echo "$usage" |
| exit |
| fi |
| while [ "$1" != "--" ] && [ "$1" != "" ] |
| do |
| if [ -n "$client_ops" ] |
| then |
| client_ops="$client_ops $1" |
| else |
| client_ops="$1" |
| fi |
| shift |
| done |
| # convert to absolute path |
| client=`cd \`dirname $client\` ; pwd`/`basename $client` |
| if [ -n "$client_list" ] |
| then |
| echo "ERROR - cannot use multiple clients with -c" |
| exit 1 |
| else |
| client_list="${client};${client_id};${client_ops}" |
| fi |
| fi |
| |
| # -- indicates app command. |
| if [ "$1" = "--" ] |
| then |
| shift |
| fi |
| ;; |
| esac |
| |
| if [ ! -n "$DYNAMORIO_HOME" ] |
| then |
| DYNAMORIO_HOME="$default_home" |
| fi |
| |
| if [ "$static" = "0" ] |
| then |
| # Setup lib path |
| if [ ! -n "$dr_lib_path" ] |
| then |
| dr_lib_path=$DYNAMORIO_HOME/lib$arch |
| dr_ext_path=$DYNAMORIO_HOME/ext/lib$arch |
| fi |
| if [ ! -e "$dr_lib_path/$lib/libdynamorio.so" ] |
| then |
| # Support running from old build dir layout |
| dr_lib_build_path=$DYNAMORIO_HOME/lib |
| dr_ext_build_path=$DYNAMORIO_HOME/ext/lib |
| if [ -e "$dr_lib_build_path/libdynamorio.so" ] |
| then |
| lib="" |
| dr_lib_path=$dr_lib_build_path |
| dr_ext_path=$dr_ext_build_path |
| else |
| if [ "$unreg" = "0" ] && [ "$rununder" = "1" ] |
| then |
| echo "ERROR - libdynamorio.so not found in $dr_lib_path/$lib" |
| echo "$usage" |
| exit |
| fi |
| fi |
| fi |
| # convert to absolute path |
| dr_lib_path=`cd "$dr_lib_path" ; pwd` |
| dr_ext_path=`cd "$dr_ext_path" ; pwd` |
| fi |
| |
| if [ ! -n "$*" ] && [ "$app" = "" ] |
| then |
| echo "ERROR - no application specified" |
| echo "$usage" |
| exit |
| fi |
| |
| # setup logdir |
| if [ ! -n "$logdir" ] |
| then |
| if [ -n "$DYNAMORIO_LOGDIR" ] |
| then |
| logdir=$DYNAMORIO_LOGDIR |
| else |
| logdir=$default_home/logs |
| fi |
| fi |
| if [ ! -d $logdir ] |
| then |
| if [ "$unreg" = "0" ] && [ "$rununder" = "1" ] |
| then |
| echo "ERROR - logdir $logdir not found" |
| echo "$usage" |
| exit |
| fi |
| fi |
| # convert to absolute path and export |
| export DYNAMORIO_LOGDIR=`cd $logdir ; pwd` |
| |
| # client options |
| if [ -n "$client_list" ] |
| then |
| client_op_string="-code_api -client_lib \"$client_list\"" |
| else |
| client_op_string="" |
| fi |
| |
| # setup options |
| if [ "$specified_ops" = "yes" ] |
| then |
| export DYNAMORIO_OPTIONS="${client_op_string} $ops" |
| else |
| export DYNAMORIO_OPTIONS="${client_op_string} $DYNAMORIO_OPTIONS" |
| fi |
| |
| # i#85/PR 212034: we now use config files |
| |
| if [ ! -n "$DYNAMORIO_CONFIGDIR" ] |
| then |
| if [ -n "$HOME" ] && [ -d "$HOME" ] |
| then |
| export DYNAMORIO_CONFIGDIR=$HOME |
| elif [ "$config" = "1" ] && [ "$runapp" = "1" ]; |
| then |
| # If creating an anonymous config file, use a temp dir rather |
| # than failing if there's no $HOME or specified dir. |
| # We don't want to run mktemp b/c we'd leave an empty dir behind |
| # on every run. We match drconfiglib, except we also check for |
| # existence up front, and we prefer /tmp to $PWD. Xref i#939. |
| if [ -n "$TMP" ] && [ -d "$TMP" ] |
| then |
| export DYNAMORIO_CONFIGDIR=$TMP |
| elif [ -n "$TEMP" ] && [ -d "$TEMP" ] |
| then |
| export DYNAMORIO_CONFIGDIR=$TEMP |
| elif [ -n "$TMPDIR" ] && [ -d "$TMPDIR" ] |
| then |
| export DYNAMORIO_CONFIGDIR=$TMPDIR |
| elif [ -d "/tmp" ] |
| then |
| export DYNAMORIO_CONFIGDIR="/tmp" |
| else |
| # last resort: cur dir |
| export DYNAMORIO_CONFIGDIR=$PWD |
| fi |
| fi |
| fi |
| |
| if [ ! -d "$DYNAMORIO_CONFIGDIR" ] |
| then |
| echo "ERROR - neither DYNAMORIO_CONFIGDIR nor HOME exists" |
| exit |
| fi |
| |
| cfgdir="$DYNAMORIO_CONFIGDIR/.dynamorio" |
| if [ ! -d $cfgdir ] |
| then |
| mkdir -p "$cfgdir" |
| if [ "$?" != 0 ] |
| then |
| echo "ERROR - failed to create config dir $cfgdir" |
| exit |
| fi |
| fi |
| |
| if [ "$app" = "" ] |
| then |
| app="$1" |
| shift |
| fi |
| |
| # better to require bash and use ${app##*/}? |
| name=`basename $app` |
| if [ "$early" = "yes" ] |
| then |
| appwhich=`which $app` |
| if [ "$appwhich" = "" ] |
| then |
| appwhich=$app |
| fi |
| appdir=`dirname $appwhich` |
| fullpath=`cd $appdir;pwd` |
| fullname="$fullpath/$name" |
| fi |
| |
| if [ "$config" = "1" ] |
| then |
| if [ "$runapp" = "1" ] |
| then |
| cfgfile="$cfgdir/$name.$$.1config$arch" |
| echo "# one-time config file" > $cfgfile |
| if [ "$verbose" = "yes" ] |
| then |
| echo "Using $lib DynamoRIO ($dr_lib_path/$lib/libdynamorio.so)" |
| echo "With DynamoRIO options=\"$DYNAMORIO_OPTIONS\"" |
| echo "Using logging directory=\"$DYNAMORIO_LOGDIR\"" |
| echo "Running \"$app $*\"" |
| fi |
| else |
| cfgfile="$cfgdir/$name.config$arch" |
| echo "# DynamoRIO config file" > $cfgfile |
| fi |
| if [ "$unreg" = "1" ] |
| then |
| rm $cfgfile |
| if [ "$verbose" = "yes" ] |
| then |
| echo "Removed config file $cfgfile" |
| fi |
| exit 0 |
| else |
| echo "DYNAMORIO_RUNUNDER=${rununder}" >> $cfgfile |
| echo "DYNAMORIO_OPTIONS=$DYNAMORIO_OPTIONS" >> $cfgfile |
| echo "DYNAMORIO_LOGDIR=$DYNAMORIO_LOGDIR" >> $cfgfile |
| echo "DYNAMORIO_AUTOINJECT=$dr_lib_path/$lib/libdynamorio.so" >> $cfgfile |
| echo "DYNAMORIO_HOME=$dr_lib_path" >> $cfgfile |
| fi |
| fi |
| |
| if [ "$runapp" = "1" ] |
| then |
| # keep same pid for easier scripting |
| if [ "$early" = "yes" ] |
| then |
| drloader="$DYNAMORIO_HOME/bin$arch/drloader" |
| if [ "$verbose" = "yes" ] |
| then |
| echo "experimental support for early injection in Linux" |
| fi |
| exec "$drloader" "$dr_lib_path/$lib/libdynamorio.so" "$fullname" "$@" |
| else |
| if [ "$static" = "1" ] |
| then |
| export DYNAMORIO_TAKEOVER_IN_INIT=1 |
| else |
| export LD_LIBRARY_PATH=$dr_lib_path/$lib:$dr_ext_path/$lib:$LD_LIBRARY_PATH |
| export LD_PRELOAD="libdynamorio.so libdrpreload.so" |
| if [ -z "$LD_USE_LOAD_BIAS" ] |
| then |
| if [ "$verbose" = "yes" ] |
| then |
| echo "Setting LD_USE_LOAD_BIAS for PIEs (i#719)" |
| echo "Set LD_USE_LOAD_BIAS=0 prior to running this script" |
| echo "if this is a problem" |
| fi |
| export LD_USE_LOAD_BIAS=1 |
| fi |
| fi |
| exec $app "$@" |
| fi |
| else |
| if [ "$verbose" = "yes" ] |
| then |
| echo "Wrote config file $cfgfile" |
| exit 0 |
| fi |
| fi |
| exit 1 |