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
|
# process exec tests.
# value gets set later
set test_exepath ""
# "load" generation function for stap_run. It spawns our test
# executable, which execs our copy of /bin/sleep.
proc run_test_exe {} {
global test_exepath
global exepath
spawn $test_exepath $exepath
set exe_id $spawn_id
wait_n_secs 5
catch {close -i $exe_id}
catch {wait -i $exe_id}
return 0;
}
# Set up our own copy of /bin/sleep, to make testing for a particular
# executable easy. We can't use 'ln' here, since we might be creating
# a cross-device link. We can't use 'ln -s' here, since the kernel
# resolves the symbolic link and reports that /bin/sleep is being
# exec'ed (instead of our local copy).
set exepath "[pwd]/sleep_[pid]"
if {[catch {exec cp /bin/sleep $exepath} res]} {
fail "unable to copy /bin/sleep: $res"
return
}
# Note use of '%1$s' - the 'N$' is the 'argpos', the argument position
# passed to 'format'.
set test_script {
global output
global sleep_start, sleep_end
probe begin { printf("systemtap starting probe\n") }
probe process("%1$s").begin {
output .= sprintf("exe(%%d) begin\n", tid())
}
probe process("%1$s").thread.begin {
output .= sprintf("exe(%%d) thread begin\n", tid())
}
probe process("%1$s").end {
output .= sprintf("exe(%%d) end\n", tid())
}
probe process("%1$s").thread.end {
output .= sprintf("exe(%%d) thread end\n", tid())
}
probe process("%2$s").begin {
sleep_start = gettimeofday_s()
output .= sprintf("sleep(%%d) begin\n", tid())
}
probe process("%2$s").end {
output .= sprintf("sleep(%%d) end\n", tid())
sleep_end = gettimeofday_s()
}
probe end {
printf("systemtap ending probe\n%%s", output)
time_slept = sleep_end - sleep_start
if (time_slept >= 2 && time_slept <= 4)
printf("time slept: OK\n")
else
printf("time slept: ERROR (%%d)\n", time_slept)
}
}
#######
#
# Test a normal fork/exec pair.
#
set fork_exec_srcpath "$srcdir/systemtap.base/proc_fork_exec.c"
set fork_exec_exepath "[pwd]/proc_fork_exec_[pid]"
set fork_exec_flags ""
# We make sure the outputs looks like the following using regexp
# subexpressions:
# exe(PARENT_PID) begin
# exe(CHILD_PID) begin
# exe(CHILD_PID) end
# sleep(CHILD_PID) begin
# sleep(CHILD_PID) end
# exe(PARENT_PID) end
# time slept: OK
#
# Accept the 'sleep(CHILD_PID)' end and 'exe(PARENT_PID) end' lines in
# any order.
set fork_exec_script_output "exe\\((\\d+)\\) begin\r\nexe\\((\\d+)\\) begin\r\nexe\\(\\2\\) end\r\nsleep\\(\\2\\) begin\r\n(sleep\\(\\2\\)|exe\\(\\1\\)) end\r\n(sleep\\(\\2\\)|exe\\(\\1\\)) end\r\ntime slept: OK\r\n"
# Compile our program that forks/exec's /bin/sleep.
set test_exepath $fork_exec_exepath
set res [target_compile $fork_exec_srcpath $fork_exec_exepath executable $fork_exec_flags]
if { $res != "" } {
verbose "target_compile failed: $res" 2
fail "unable to compile $fork_exec_srcpath"
return
}
set TEST_NAME "PROC_EXEC_01"
if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
} else {
set script [format $test_script $fork_exec_exepath $exepath]
stap_run $TEST_NAME run_test_exe $fork_exec_script_output -e $script
}
#######
#
# Test a straight exec (no fork).
#
set exec_srcpath "$srcdir/systemtap.base/proc_exec.c"
set exec_exepath "[pwd]/proc_exec_[pid]"
set exec_flags ""
# We make sure the outputs looks like the following using regexp
# subexpressions:
# exe(PID) begin
# exe(PID) end
# sleep(PID) begin
# sleep(PID) end
# time slept: OK
set exec_script_output "exe\\((\\d+)\\) begin\r\nexe\\(\\1\\) end\r\nsleep\\(\\1\\) begin\r\nsleep\\(\\1\\) end\r\ntime slept: OK\r\n"
# Compile our program that exec's /bin/sleep.
set test_exepath $exec_exepath
set res [target_compile $exec_srcpath $exec_exepath executable $exec_flags]
if { $res != "" } {
verbose "target_compile failed: $res" 2
fail "unable to compile $exec_srcpath"
return
}
set TEST_NAME "PROC_EXEC_02"
if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
} else {
set script [format $test_script $exec_exepath $exepath]
stap_run $TEST_NAME run_test_exe $exec_script_output -e $script
}
#######
#
# Test a multi-threaded exec, which programs aren't supposed to do,
# but...
#
set thread_exec_srcpath "$srcdir/systemtap.base/proc_thread_exec.c"
set thread_exec_exepath "[pwd]/proc_thread_exec_[pid]"
set thread_exec_flags "libs=-lpthread"
# We make sure the outputs looks like the following using regexp
# subexpressions.
# exe(PID1) begin
# exe(PID2) thread begin
# exe(PID1) thread end
# exe(PID1) end
# sleep(PID1) begin
# sleep(PID1) end
# time slept: OK
#
# Why no PID2 thread end and why isn't sleep using PID2? When the
# thread calls exec (which it isn't supposed to do), the kernel has to
# clean up the best it can. It really kills the original task,
# promotes the thread to be the process group leader (and changes the
# thread's pid to the original process group leader's pid).
set thread_exec_script_output "exe\\((\\d+)\\) begin\r\nexe\\(\\d+\\) thread begin\r\nexe\\(\\1\\)( thread)? end\r\nexe\\(\\1\\) end\r\nsleep\\(\\1\\) begin\r\nsleep\\(\\1\\) end\r\ntime slept: OK\r\n"
# Compile our multi-threaded program that exec's /bin/sleep.
set test_exepath $thread_exec_exepath
set res [target_compile $thread_exec_srcpath $thread_exec_exepath executable $thread_exec_flags]
if { $res != "" } {
verbose "target_compile failed: $res" 2
fail "unable to compile $exec_srcpath"
return
}
set TEST_NAME "PROC_EXEC_03"
if {![utrace_p]} {
untested "$TEST_NAME : no kernel utrace support found"
} elseif {![installtest_p]} {
untested "$TEST_NAME"
} else {
set script [format $test_script $thread_exec_exepath $exepath]
stap_run $TEST_NAME run_test_exe $thread_exec_script_output -e $script
}
# Cleanup
exec rm -f $exepath $fork_exec_exepath $exec_exepath $thread_exec_exepath
|