Commit | Line | Data |
---|---|---|
eb6adb25 PMF |
1 | #!/bin/bash |
2 | ||
4a7c7161 PMF |
3 | # usttrace by Pierre-Marc Fournier 2009 |
4 | # Distributed under the GPLv2. | |
5 | ||
63f16f2e PMF |
6 | function error() { |
7 | echo "$0: error: $1" 2>/dev/stderr | |
8 | } | |
9 | ||
cd814711 | 10 | USTTRACE_DIR="$(dirname $0)" |
6b22d5c1 JB |
11 | if [ -x "${USTTRACE_DIR}/ustd/ustd" ] ; then |
12 | # Use the not installed libraries instead | |
13 | USTD="${USTTRACE_DIR}/ustd/ustd" | |
14 | LIBINTERFORK_PATH="${USTTRACE_DIR}/libinterfork/.libs/libinterfork.so" | |
15 | LIBMALLOCWRAP_PATH="${USTTRACE_DIR}/libmallocwrap/.libs/libmallocwrap.so" | |
16 | LIBUST_PATH="${USTTRACE_DIR}/libust/.libs/libust.so" | |
17 | else | |
18 | # Use the libraries that the dynamic link finds | |
19 | USTD="ustd" | |
63f16f2e PMF |
20 | if [ ! -x "$(which ustd 2>/dev/null)" ]; then |
21 | error "cannot find an executable ustd; make sure its location is in the PATH" | |
22 | exit 1 | |
23 | fi | |
6b22d5c1 JB |
24 | LIBINTERFORK_PATH="libinterfork.so" |
25 | LIBMALLOCWRAP_PATH="libmallocwrap.so" | |
26 | LIBUST_PATH="libust.so" | |
27 | fi | |
eb6adb25 | 28 | |
cd814711 | 29 | BASE_TRACE_DIR="${HOME}/.usttraces" |
eb6adb25 PMF |
30 | |
31 | function usage () { | |
b13ba584 PMF |
32 | echo "usage: $0 OPTIONS COMMAND" 2>/dev/stderr |
33 | echo "" 2>/dev/stderr | |
34 | echo "Options:" 2>/dev/stderr | |
35 | echo " -l Runtime link with UST library." 2>/dev/stderr | |
36 | echo " (Needed only if program was not linked at compile time with libust.)" 2>/dev/stderr | |
37 | echo " -L Add path to ust libraries to LD_LIBRARY_PATH." 2>/dev/stderr | |
38 | echo " -m Instrument malloc calls." 2>/dev/stderr | |
39 | echo " -f Also trace forked processes." 2>/dev/stderr | |
89a10f62 | 40 | echo " -s Use system-wide daemon instead of creating one for this session." 2>/dev/stderr |
eb6adb25 PMF |
41 | } |
42 | ||
89a10f62 | 43 | while getopts ":hlLmfs" options; do |
b13ba584 PMF |
44 | case $options in |
45 | l) arg_preload_libust=1;; | |
46 | L) arg_ld_std_ust=1;; | |
47 | m) arg_preload_malloc=1;; | |
48 | f) arg_preload_fork=1;; | |
89a10f62 | 49 | s) arg_syswide_daemon=1;; |
b13ba584 PMF |
50 | h) usage; |
51 | exit 0;; | |
2a3fba49 | 52 | \?) usage |
b13ba584 | 53 | exit 1;; |
2a3fba49 | 54 | *) usage |
b13ba584 PMF |
55 | exit 1;; |
56 | esac | |
57 | done | |
58 | shift $(($OPTIND - 1)) | |
59 | ||
eb6adb25 | 60 | # Prepare vars |
6b22d5c1 | 61 | CMD=$* |
eb6adb25 PMF |
62 | |
63 | # Validate input | |
64 | if [ -z "$HOME" ]; | |
65 | then | |
66 | error "no home specified" | |
67 | fi | |
68 | ||
69 | if [ -z "$CMD" ]; | |
70 | then | |
71 | error "no command specified" | |
72 | usage; | |
73 | exit 1 | |
74 | fi | |
75 | ||
76 | # Create directory for trace output | |
77 | DATESTRING="$(hostname)-$(date +%Y%m%d%H%M%S)" | |
78 | OUTDIR="$BASE_TRACE_DIR/$DATESTRING" | |
79 | mkdir -p "$OUTDIR" | |
80 | ||
81 | # Choose socket path | |
82 | SOCKPATH="/tmp/ust-sock-$$" | |
83 | ||
89a10f62 PMF |
84 | if [ "$arg_syswide_daemon" != "1" ]; |
85 | then | |
b924c127 | 86 | pidfilepath="/tmp/usttrace-$USER-$(date +%Y%m%d%H%M%S%N)-ustd-pid" |
8232f1db | 87 | mkfifo -m 0600 "$pidfilepath" |
89a10f62 | 88 | # Start daemon |
2b3c64a4 | 89 | $USTD --pidfile "$pidfilepath" -s "$SOCKPATH" -o "$OUTDIR" >"$OUTDIR/ustd.log" 2>&1 & |
0f3af9f0 PMF |
90 | # ustd sets up its server socket |
91 | # ustd opens the pidfile, blocks because no one has opened it | |
92 | # we open pidfile | |
93 | # we block reading pidfile | |
94 | # ustd writes to pidfile | |
95 | # ustd closes pidfile | |
96 | # we unblock reading pidfile | |
b924c127 | 97 | USTDPID="$(<$pidfilepath)" |
89a10f62 PMF |
98 | export UST_DAEMON_SOCKET="$SOCKPATH" |
99 | fi | |
100 | ||
eb6adb25 | 101 | # Establish the environment for the command |
6b22d5c1 JB |
102 | ( |
103 | export UST_TRACE=1 | |
104 | export UST_AUTOPROBE=1 | |
105 | ||
106 | if [ "$arg_preload_libust" = "1" ]; | |
107 | then | |
108 | if [ -n "${LIBUST_PATH%libust.so}" ] ; then | |
109 | export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${LIBUST_PATH%libust.so}" | |
110 | fi | |
111 | export LD_PRELOAD="$LD_PRELOAD:$LIBUST_PATH" | |
112 | fi | |
113 | ||
114 | if [ "$arg_ld_std_ust" = "1" ]; | |
115 | then | |
116 | if [ -n "$${LIBUST_PATH%libust.so}" ] ; then | |
117 | export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${LIBUST_PATH%libust.so}" | |
118 | fi | |
119 | fi | |
120 | ||
121 | if [ "$arg_preload_malloc" = "1" ]; | |
122 | then | |
123 | export LD_PRELOAD="$LD_PRELOAD:$LIBMALLOCWRAP_PATH" | |
124 | fi | |
125 | ||
126 | if [ "$arg_preload_fork" = "1" ]; | |
127 | then | |
89a10f62 | 128 | export LD_PRELOAD="$LD_PRELOAD:$LIBINTERFORK_PATH" |
6b22d5c1 | 129 | fi |
b13ba584 | 130 | |
89a10f62 PMF |
131 | # Install a handler for SIGIO. This is the signal that will be sent by ustd to |
132 | # the traced program to trigger the creation of its listener thread. However, | |
133 | # it is possible that the SIGIO will be sent after the shell fork, but before | |
134 | # the exec of the command. If this handler isn't there, bash might terminate | |
135 | # because of a unhandled signal. | |
b13ba584 | 136 | |
eb6adb25 | 137 | # Execute the command |
6b22d5c1 JB |
138 | $CMD 2>&1 |
139 | ) | tee "$OUTDIR/app.log" | |
eb6adb25 PMF |
140 | |
141 | ## Because of the keepalive mechanism, we're sure that by the time | |
142 | ## we get here, the daemon is connected to all the buffers that still exist. | |
143 | ## Therefore we can politely ask it to die when it's done. | |
144 | ||
89a10f62 PMF |
145 | if [ "$arg_syswide_daemon" != "1" ]; |
146 | then | |
147 | # Tell the daemon to die | |
148 | kill -SIGTERM "$USTDPID" | |
149 | ||
150 | echo "Waiting for ustd to shutdown..." | |
524a8072 | 151 | wait "$USTDPID" |
b924c127 PMF |
152 | |
153 | rm "$pidfilepath" | |
89a10f62 | 154 | fi |
eb6adb25 | 155 | |
89a10f62 | 156 | echo "Trace was output in: " $OUTDIR |