1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
|
#!/bin/bash
# $1 - install/uninstall
# $2 - PID/unique name
# $3 - RULE name
# $4 - class
# $5 - method
# $6 - number of args
# $7 - entry/exit/line
# $8 - backtrace trigger
exec 1>&2 # redirect byteman/etc. tracing output to stderr, for easier filtering
if [[ $# -gt 8 || $# -lt 7 ]]; then
echo "need seven or eight arguments"
exit 1
fi
arg_command=$1
# resolve the overloaded parameter; PR21020
if [ $arg_command = "install31" ]; then
mode=install
stap="31"
elif [ $arg_command = "uninstall31" ]; then
mode=uninstall
stap="31"
elif [ $arg_command = "install" ]; then
mode=install
stap=""
elif [ $arg_command = "uninstall" ]; then
mode=uninstall
else
exit 1
fi
arg_jvmpid=$2
arg_rulename=$3
arg_class=$4
arg_method=$5
arg_argcount=$6
arg_probetype=$7
if [ $# -eq 7 ]; then
arg_backtrace=0
else
arg_backtrace=$8
fi
SYSTEMTAP_DIR=${SYSTEMTAP_DIR-$HOME/.systemtap}
BYTEMAN_HOME=${BYTEMAN_HOME-/usr/share/java/byteman}
JAVA_HOME=${JAVA_HOME-/usr/lib/jvm/java}
BYTEMAN_INSTALL_OPTS=${BYTEMAN_INSTALL_OPTS--Dorg.jboss.byteman.transform.all=true}
SYSTEMTAP_VERBOSE=${SYSTEMTAP_VERBOSE-0}
if [ "$SYSTEMTAP_VERBOSE" != "0" ]; then
BYTEMAN_INSTALL_OPTS="$BYTEMAN_INSTALL_OPTS -Dorg.jboss.byteman.verbose"
set -x
else
exec >/dev/null
# NB: preserve stderr
fi
prefix=@prefix@
exec_prefix=@exec_prefix@
pkglibexecdir=@pkglibexecdir@
HELPERSDT_JAR=${pkglibexecdir}/HelperSDT.jar
if [ ! -f ${HELPERSDT_JAR} ]; then
exec 1>&2
echo "Missing $HELPERSDT_JAR"
exit 1
fi
flagdir="$SYSTEMTAP_DIR/java"
mkdir -p $flagdir
# Find our target jvm pid. Due to the possibility of our
# target jvm pid being passed as a string, we need to allow
# for the possiblity that more than one pid may match the
# target jvm pid. If this is the case, we need to have a
# nested call to stapbm with the actual pid of the jvm pid
if ! [[ $arg_jvmpid =~ ^[0-9]+$ ]]; then
target_pid=`jps -l | grep $arg_jvmpid | cut -f1 -d" "`
for target in $target_pid; do
$0 "$arg_command" "$target" "$arg_rulename" "$arg_class" "$arg_method" "$arg_argcount" "$arg_probetype" "$arg_backtrace"
done
exit 0
else
target_pid=$arg_jvmpid
fi
# Our target jvm may not have the byteman agent installed yet. Let's do
# that first. We use a signal file in $flagdir to show that the
# JVM is ready for further bytemanning without a prior setup step,
# and include in it the designated byteman agent listening-port number.
#
byteman_installed_portfile=$flagdir/`hostname`-${target_pid}-bm
exec 200>>$byteman_installed_portfile # open/create lock file
flock -x 200 # exclusive-lock it
if [ -s $byteman_installed_portfile ]; then
bmport=`cat $byteman_installed_portfile`
if [ "$SYSTEMTAP_VERBOSE" != "0" ]; then
echo "Byteman agent reused for java pid $target_pid, port $bmport"
fi
# XXX: liveness-check the port; bmsubmit with no argument just lists current rules
# if fails, delete the _portfile and retry everything
else
# bmport=9091
bmport=`expr 9090 + $RANDOM % 10000`
existing=`ss -atn | awk '{print $4}' | grep ':'$bmport'$'`
if [ "x$existing" != "x" ]; then
echo "Byteman port $bmport already in use, retrying."
exec "$@"
fi
# There are two ways to invoke and run byteman operations with the jvm's we're interested
# in, we can alter the startup arguments to include a -javaagent parameter, or use
# byteman and its use of VMAttach libraries, for our case it always makes sense to use
# byteman classes directly and avoid -javaagent
bminstall -b -p $bmport $BYTEMAN_INSTALL_OPTS $target_pid
if [ $? -ne 0 ]; then
echo "Byteman agent failed to install for java pid $target_pid, port $bmport"
exit 1
fi
bmsubmit -p $bmport -s $HELPERSDT_JAR
if [ $? -ne 0 ]; then
echo "Byteman agent failed to load HelperSDT.jar java pid $target_pid, port $bmport"
exit 1
fi
echo $bmport > $byteman_installed_portfile
if [ "$SYSTEMTAP_VERBOSE" != "0" ]; then
echo "Byteman agent installed for java pid $target_pid, port $bmport"
fi
# XXX: Erase file to keep it from sticking around indefinitely,
# in case process ends, machine reboots, pid gets reused
# XXX: consider explicit notification to stapbm via process("java").begin/end ?
# ... or else: liveness-check below
fi
exec 200>&- # close file & release flock
function echo_bytemanrule()
{
echo "RULE $arg_rulename"
echo "CLASS $arg_class"
echo "METHOD $arg_method"
echo "HELPER org.systemtap.byteman.helper.HelperSDT"
case "$arg_probetype" in
entry)
echo "AT ENTRY"
;;
exi*)
echo "AT RETURN"
;;
*)
echo "AT LINE $arg_probetype"
;;
esac
echo "IF TRUE"
if [ "$arg_backtrace" == "1" ]; then
echo 'DO STAP_BACKTRACE("'$arg_rulename'");'
else
echo -n 'DO '
fi
case "$arg_argcount" in
# For PR21010, we invoke another java<->stap ABI
0) echo -n 'METHOD_STAP'$stap'_PROBE0("'$arg_rulename'")' ;;
1) echo -n 'METHOD_STAP'$stap'_PROBE1("'$arg_rulename'", $1)' ;;
2) echo -n 'METHOD_STAP'$stap'_PROBE2("'$arg_rulename'", $1, $2)' ;;
3) echo -n 'METHOD_STAP'$stap'_PROBE3("'$arg_rulename'", $1, $2, $3)' ;;
4) echo -n 'METHOD_STAP'$stap'_PROBE4("'$arg_rulename'", $1, $2, $3, $4)' ;;
5) echo -n 'METHOD_STAP'$stap'_PROBE5("'$arg_rulename'", $1, $2, $3, $4, $5)' ;;
6) echo -n 'METHOD_STAP'$stap'_PROBE6("'$arg_rulename'", $1, $2, $3, $4, $5, $6)' ;;
7) echo -n 'METHOD_STAP'$stap'_PROBE7("'$arg_rulename'", $1, $2, $3, $4, $5, $6, $7)' ;;
8) echo -n 'METHOD_STAP'$stap'_PROBE8("'$arg_rulename'", $1, $2, $3, $4, $5, $6, $7, $8)' ;;
9) echo -n 'METHOD_STAP'$stap'_PROBE9("'$arg_rulename'", $1, $2, $3, $4, $5, $6, $7, $8, $9)' ;;
10) echo -n 'METHOD_STAP'$stap'_PROBE10("'$arg_rulename'", $1, $2, $3, $4, $5, $6, $7, $8, $9, $10)' ;;
*) echo 'bad arg-count'; exit 1 ;;
esac
if [ "$arg_backtrace" == "1" ]; then
echo ';'
echo 'METHOD_BT_DELETE("'$arg_rulename'")'
else
echo ''
fi
echo "ENDRULE"
}
# Generate the byteman rule file on-the-fly
btmfile=$flagdir/`hostname`-$$.btm
echo_bytemanrule > $btmfile
trap 'rm -f $btmfile' 0 1 2 3 4 5 9 15
if [ "$SYSTEMTAP_VERBOSE" != "0" ]; then
echo "Byteman rule file:"
cat $btmfile
fi
if [ $mode = "uninstall" ]; then
bmcmd=-u
else
bmcmd=-l
fi
bmsubmit -p $bmport $bmcmd $btmfile
|