]>
Commit | Line | Data |
---|---|---|
814bc89d | 1 | load_lib site.exp |
744884cd | 2 | load_lib "compile_flags.exp" |
814bc89d FCE |
3 | |
4 | proc installtest_p {} { | |
5 | global TOOL_OPTIONS | |
23361495 | 6 | if {[info exists TOOL_OPTIONS] && [string match "*install*" $TOOL_OPTIONS]} { |
814bc89d FCE |
7 | return 1 |
8 | } else { return 0 } | |
9 | } | |
10 | ||
23361495 | 11 | |
c3e70cc8 JS |
12 | proc grep_kallsyms { pattern } { |
13 | if {! [catch {exec grep -q "$pattern" "/proc/kallsyms"} dummy]} { | |
75ebbc0d FCE |
14 | return 1 |
15 | } | |
16 | return 0 | |
17 | } | |
18 | ||
19 | ||
c3e70cc8 JS |
20 | # Test for kernel built-in utrace (CONFIG_UTRACE). |
21 | # Only original rhel5/6-era utrace need apply. | |
22 | proc utrace_orig_p {} { | |
23 | # We want utrace_attach (rhel5) or utrace_attach_task (rhel6), but don't | |
24 | # get confused by the private module version of any active stap module. | |
e5de04ab | 25 | return [expr [grep_kallsyms "T utrace_attach"] || [grep_kallsyms "T .utrace_attach_task"]] |
c3e70cc8 | 26 | } |
55352180 | 27 | |
55352180 | 28 | |
c3e70cc8 JS |
29 | # Test for tracepoint-based utrace, or rather the in-kernel |
30 | # facilities which enable our emulation of utrace. | |
31 | proc utrace_emu_p {} { | |
32 | # Check for the set of 5 tracepoints we need and task_work_add() | |
33 | # (see runtime/autoconf-utrace-via-tracepoints.c for details). | |
34 | return [expr [grep_kallsyms task_work_add] \ | |
35 | && [grep_kallsyms tracepoint_sched_process_fork] \ | |
36 | && [grep_kallsyms tracepoint_sched_process_exec] \ | |
37 | && [grep_kallsyms tracepoint_sched_process_exit] \ | |
38 | && [grep_kallsyms tracepoint_sys_enter] \ | |
39 | && [grep_kallsyms tracepoint_sys_exit] \ | |
40 | ] | |
83ff01c2 | 41 | } |
f249edcd JS |
42 | |
43 | ||
c3e70cc8 JS |
44 | # Test for utrace - any flavor will do... |
45 | proc utrace_p {} { | |
46 | return [expr [utrace_orig_p] || [utrace_emu_p] ] | |
47 | } | |
48 | ||
49 | ||
50 | proc classic_uprobes_p {} { | |
7d26ee02 JS |
51 | # If this is a utrace kernel, then we can use our version of uprobes. |
52 | # No need to build it now, stap will handle that itself. | |
55352180 | 53 | # |
c3e70cc8 JS |
54 | # Although ia64 has classical utrace, uprobes hasn't been |
55 | # ported there (PR7081). | |
56 | return [expr [utrace_orig_p] && ! [istarget ia64-*-*] ] | |
57 | } | |
fdb3f242 | 58 | |
c3e70cc8 JS |
59 | proc inode_uprobes_p {} { |
60 | # inode-uprobes (or unlikely compiled-in classical uprobes?) | |
fdb3f242 DS |
61 | # |
62 | # Note we're looking for " uprobe_register" to avoid finding | |
63 | # 'kallsyms_uprobe_register' from a loaded systemtap module. | |
53ce8435 JL |
64 | return [expr ([grep_kallsyms register_uprobe] \ |
65 | || [grep_kallsyms " uprobe_register"]) \ | |
66 | && ! [classic_uprobes_p] \ | |
c3e70cc8 | 67 | ] |
f249edcd | 68 | } |
dd466726 DS |
69 | |
70 | ||
c3e70cc8 JS |
71 | proc uprobes_p {} { |
72 | return [expr [classic_uprobes_p] || [inode_uprobes_p] ] | |
73 | } | |
dd466726 | 74 | |
c3e70cc8 JS |
75 | |
76 | proc classic_uretprobes_p {} { | |
77 | # Classic uprobes always has uretprobes | |
78 | return [classic_uprobes_p] | |
dd466726 | 79 | } |
83ff01c2 | 80 | |
c3e70cc8 JS |
81 | proc inode_uretprobes_p {} { |
82 | # inode-uprobes, now with return probes! Looking for any mention of | |
83 | # uretprobe, notably arch_uretprobe_hijack_return_addr | |
84 | return [expr [inode_uprobes_p] && [grep_kallsyms uretprobe] ] | |
85 | } | |
83ff01c2 | 86 | |
9c41fd2c | 87 | proc uretprobes_p {} { |
c3e70cc8 | 88 | return [expr [classic_uretprobes_p] || [inode_uretprobes_p] ] |
9c41fd2c FCE |
89 | } |
90 | ||
1cd0bda2 DS |
91 | proc plt_probes_p {} { |
92 | # .plt probes need uprobes and a supported arch (x86 and arm) | |
93 | return [expr [uprobes_p] \ | |
81acc574 | 94 | && [regexp "^(x86_64|i.86|arm.*|aarch64)$" $::tcl_platform(machine)] ] |
1cd0bda2 | 95 | } |
9c41fd2c | 96 | |
20810599 DS |
97 | proc perf_probes_p {} { |
98 | # perf probes need and exported perf_event_create_kernel_counter | |
99 | return [grep_kallsyms perf_event_create_kernel_counter] | |
100 | } | |
101 | ||
c1dfb8be JL |
102 | proc hwbkpt_probes_p {} { |
103 | global have_hw_breakpoint_p | |
104 | return $have_hw_breakpoint_p | |
105 | } | |
106 | ||
c66aa968 DS |
107 | proc readline_p {} { |
108 | global systemtap_readline_p | |
109 | return $systemtap_readline_p | |
110 | } | |
111 | ||
3742aa98 JL |
112 | # Callee probes require GCC v4.7 and stap compiled |
113 | # with elfutils 0.153 | |
114 | proc callee_probes_p {} { | |
115 | global GCC_Version ELF_Version | |
116 | return [expr [strverscmp $GCC_Version 4.7] >= 0 && \ | |
117 | [strverscmp $ELF_Version 0.153] >= 0] | |
118 | } | |
119 | ||
8c94efa7 | 120 | proc dyninst_p {} { |
cd3a2693 FCE |
121 | global systemtap_dyninst_p |
122 | return $systemtap_dyninst_p | |
123 | } | |
8c94efa7 | 124 | |
cd3a2693 FCE |
125 | proc nss_p {} { |
126 | global systemtap_nss_p | |
127 | return $systemtap_nss_p | |
8c94efa7 DS |
128 | } |
129 | ||
ca49ae2c DS |
130 | proc java_p {} { |
131 | global systemtap_java_p | |
132 | return $systemtap_java_p | |
133 | } | |
134 | ||
80363472 MC |
135 | proc bootprobing_p {} { |
136 | global Dracut_Version | |
137 | return [expr [strverscmp $Dracut_Version 025] >= 0 && \ | |
3ee1ccd7 | 138 | [file exists "/sbin/new-kernel-pkg"]] |
80363472 MC |
139 | } |
140 | ||
593655de JL |
141 | proc module_refresh_p {} { |
142 | return [min_kernel_vers_p 2.6.29] | |
143 | } | |
144 | ||
6ef13be0 JL |
145 | proc hrtimer_p {} { |
146 | return [min_kernel_vers_p 2.6.17] | |
147 | } | |
148 | ||
b1b8a605 JL |
149 | proc kprobes_disabling_p {} { |
150 | return [min_kernel_vers_p 2.6.30] | |
151 | } | |
152 | ||
593655de JL |
153 | # Returns 1 if kernel vers >= @min, 0 otherwise. The @min parameter must be in |
154 | # the format x.y.z (e.g. 2.6.18). | |
155 | proc min_kernel_vers_p {min} { | |
156 | ||
157 | # Check proper format | |
158 | if {![regexp {^[0-9]+(\.[0-9]+)*$} $min]} { | |
159 | error "$min is not a valid version number" | |
160 | } | |
161 | ||
162 | set uname [exec uname -r] | |
163 | ||
164 | if {![regexp {^([0-9]+\.[0-9]+\.[0-9]+).*} $uname dummy cur]} { | |
165 | error "can't parse version number from uname -r" | |
166 | } | |
167 | ||
168 | return [expr [strverscmp $cur $min] >= 0] | |
169 | } | |
8c94efa7 DS |
170 | |
171 | proc get_runtime_list {} { | |
172 | # Always return the default runtime. | |
173 | set runtime_list [list ""] | |
174 | ||
175 | if {[dyninst_p]} { | |
176 | lappend runtime_list "dyninst" | |
177 | } | |
178 | return $runtime_list | |
179 | } | |
180 | ||
181 | ||
814bc89d FCE |
182 | proc print_systemtap_version {} { |
183 | set version [exec /bin/uname -r] | |
184 | set location "/boot/vmlinux-$version" | |
185 | if {! [file exists $location]} { | |
186 | # try the debuginfo location | |
187 | set location "/usr/lib/debug/lib/modules/$version/vmlinux" | |
188 | if {! [file exists $location]} { set location "" } | |
189 | } | |
190 | ||
191 | print "kernel location: $location" | |
192 | print "kernel version: $version" | |
193 | ||
194 | set location [exec /usr/bin/which stap] | |
195 | regexp {version [^)]*} [exec stap -V 2>@ stdout] version | |
196 | ||
197 | print "systemtap location: $location" | |
198 | print "systemtap version: $version" | |
47561106 MW |
199 | |
200 | set location [exec /usr/bin/which gcc] | |
201 | set version [exec gcc --version | head -1] | |
202 | ||
203 | print "gcc location: $location" | |
204 | print "gcc version: $version" | |
814bc89d FCE |
205 | } |
206 | ||
207 | ||
208 | proc setup_systemtap_environment {} { | |
8093ef39 | 209 | global srcdir env server_pid systemtap_dyninst_p |
ca49ae2c | 210 | global systemtap_nss_p systemtap_java_p |
c66aa968 | 211 | global have_hw_breakpoint_p systemtap_readline_p |
0b872dd0 | 212 | global kill_needs_doubledash |
814bc89d FCE |
213 | |
214 | # need an absolute SRCDIR for the top-level src/ tree | |
5ba96b90 | 215 | # XXX: or, we could change nearby uses of ${SRCDIR}/testsuite to ${SRCDIR} |
99e1fb7a | 216 | set env(SRCDIR) [fullpath $srcdir/..] |
814bc89d | 217 | |
b8f96d36 JL |
218 | # pretend to be a dumb terminal so that coloring is always turned off |
219 | # otherwise, we will have problems with expect | |
220 | set env(TERM) dumb | |
221 | ||
0fbf54d6 MW |
222 | # Use a local systemtap directory and cache. Add user name so |
223 | # make check and sudo make check don't clobber each other. | |
574cf27a | 224 | set env(SYSTEMTAP_DIR) [pwd]/.systemtap-[exec whoami] |
75bde6fe | 225 | exec mkdir -p $env(SYSTEMTAP_DIR) |
5ba96b90 | 226 | |
aae091fc DB |
227 | # Start with fresh server certificates |
228 | exec rm -fr $env(SYSTEMTAP_DIR)/ssl | |
229 | ||
f1d4f431 FCE |
230 | # Remove the rc file |
231 | exec rm -f $env(SYSTEMTAP_DIR)/rc | |
232 | ||
233 | # All hail the prophet lockdep | |
234 | set chan [open $env(SYSTEMTAP_DIR)/rc w] | |
cb690174 MC |
235 | # Set the --rlimit-cpu just slightly under the 15 minutes, so that following |
236 | # two independent timeout mechanisms do not coincide. | |
237 | puts $chan "--rlimit-cpu=850" | |
572b45b2 | 238 | puts $chan "-E 'probe timer.s(900){error(\"probe timeout after 15 minutes\")}'" |
f1d4f431 FCE |
239 | close $chan |
240 | ||
7288f08e FCE |
241 | # Zap any previous uprobes, if any |
242 | catch { exec /sbin/rmmod uprobes } | |
243 | ||
8501d45c | 244 | # No compile-server started yet. |
7d54db1a | 245 | set server_pid 0 |
d5658775 | 246 | |
2e230f8a DS |
247 | # If the environment variable ARCH exists, this can throw off our |
248 | # custom module building (when set to the wrong value). To be | |
249 | # safe, remove it. | |
250 | if [info exists env(ARCH)] { | |
251 | verbose -log "clearing env ARCH (was $env(ARCH))" | |
252 | unset env(ARCH) | |
253 | } | |
254 | ||
5ba96b90 FCE |
255 | # PATH, SYSTEMTAP_TAPSET, SYSTEMTAP_RUNTIME, LD_LIBRARY_PATH are already set. |
256 | foreach var {PATH STAP SRCDIR SYSTEMTAP_TAPSET SYSTEMTAP_RUNTIME SYSTEMTAP_DIR LD_LIBRARY_PATH} { | |
257 | if [info exists env($var)] { | |
258 | verbose -log "env $var = $env($var)" | |
259 | } | |
260 | } | |
e26df1cb | 261 | |
752fd1e5 | 262 | # Remember if this very version of systemtap compiled with dyninst support |
8c94efa7 | 263 | if {! [catch {exec sh -c "stap -V 2>&1 | grep -q DYNINST"} dummy]} { |
cd3a2693 FCE |
264 | set systemtap_dyninst_p 1 |
265 | } else { | |
266 | set systemtap_dyninst_p 0 | |
267 | } | |
268 | ||
752fd1e5 | 269 | # Remember if this selfsame version of systemtap compiled with nss support |
cd3a2693 FCE |
270 | if {! [catch {exec sh -c "stap -V 2>&1 | grep -q NSS"} dummy]} { |
271 | set systemtap_nss_p 1 | |
272 | } else { | |
273 | set systemtap_nss_p 0 | |
8c94efa7 | 274 | } |
cd3a2693 | 275 | |
ca49ae2c DS |
276 | # Remember if this selfsame version of systemtap compiled with java support |
277 | if {! [catch {exec sh -c "stap -V 2>&1 | grep -q JAVA"} dummy]} { | |
278 | set systemtap_java_p 1 | |
279 | } else { | |
280 | set systemtap_java_p 0 | |
281 | } | |
0b872dd0 | 282 | |
0939a9fe JL |
283 | # Remember if this selfsame version of systemtap supports HW breakpoints |
284 | if {! [catch {exec stap -l {kernel.data(0x123).rw}}]} { | |
285 | set have_hw_breakpoint_p 1 | |
286 | } else { | |
287 | set have_hw_breakpoint_p 0 | |
288 | } | |
289 | ||
c66aa968 DS |
290 | # Remember if this selfsame version of systemtap compiled with |
291 | # readline support | |
292 | if {! [catch {exec sh -c "stap -V 2>&1 | grep -q READLINE"} dummy]} { | |
293 | set systemtap_readline_p 1 | |
294 | } else { | |
295 | set systemtap_readline_p 0 | |
296 | } | |
297 | ||
0b872dd0 JL |
298 | # There are some kill executables that had issues with -SIG -PID, thinking |
299 | # that the -PID was an option (procps-ng v3.3.2 and v3.3.3) and thus require | |
300 | # a -- before -PID. So check for those, otherwise, just assume that no -- is | |
301 | # needed. | |
302 | if {![catch {exec kill --version 2>@1} killver]} { | |
303 | if {[string match "*procps-ng 3.3.\[23\]" $killver]} { | |
304 | set kill_needs_doubledash 1 | |
305 | } else { | |
306 | # any other procps versions support the standard convention | |
307 | # and anything not procps (e.g. util-linux) supports both | |
308 | set kill_needs_doubledash 0 | |
309 | } | |
310 | } else { | |
311 | # kill doesn't support --version (e.g. busybox), just assume standard | |
312 | # convention | |
313 | set kill_needs_doubledash 0 | |
314 | } | |
315 | ||
e26df1cb | 316 | return 1 |
814bc89d FCE |
317 | } |
318 | ||
72629a44 DB |
319 | # Set up the environment so that tests will be performed using the systemtap |
320 | # client and server. | |
fc3d2b46 | 321 | proc setup_server { args } { |
0bdc958c | 322 | global srcdir env installed_stap logfile use_server server_spec avahi_ok_p |
72629a44 | 323 | |
250fb71a | 324 | # Start the server |
fc3d2b46 | 325 | if {! [start_server $args]} then { |
250fb71a DB |
326 | return 0 |
327 | } | |
328 | ||
8093ef39 MC |
329 | # Create a temporary log file |
330 | if {[catch {exec mktemp -t stap-list-servers-XXXXXX} tmpfile]} { | |
331 | verbose -log "Failed to create temporary log file: $tmpfile" | |
332 | exit 1 | |
333 | } | |
334 | ||
51c1bb7a | 335 | # Make sure that stap can find the server. |
c1531f3f | 336 | set waited 0 |
51c1bb7a | 337 | set use_server --use-server |
c1531f3f AJ |
338 | set res 0 |
339 | set listRes 1 | |
340 | while { $listRes != 0 && $waited < 15 } { | |
341 | exec sleep 1 | |
f5d91f1d | 342 | incr waited |
c1531f3f AJ |
343 | set res [catch { exec stap --list-servers=online,trusted,compatible >& stap-list-servers.out } seen_servers] |
344 | set listRes [catch { exec grep "^ host" stap-list-servers.out } looksee] | |
345 | } | |
2be2e486 | 346 | verbose -log "stap --list-servers returned: res==$res" |
c1531f3f | 347 | verbose -log $seen_servers[exec cat stap-list-servers.out] |
a7dbd06e | 348 | verbose -log "grep for servers returned: res==$res\n$looksee" |
2be2e486 | 349 | |
8093ef39 MC |
350 | # Delete the temporary log file |
351 | catch {exec rm $tmpfile} | |
352 | ||
0bdc958c DB |
353 | # Try to discover the port the server is listening on from the server log. |
354 | # We're matching a line of the form: | |
355 | # "Thu Jul 25 11:58:11 2013: Using network address <addr>:37804" | |
356 | set res [catch { exec /bin/cat $logfile | awk "/Using network address/ {print \$9}" } server_address] | |
357 | send_log "server_address=='$server_address'\n" | |
51c1bb7a | 358 | if {$res != 0} then { |
0bdc958c DB |
359 | verbose -log "Unable to discover the address used by the systemtap server" |
360 | shutdown_server | |
361 | return 0 | |
362 | } | |
363 | set res [regsub ".*:(\[0-9\]\[0-9\]*)\$" $server_address {\1} server_port] | |
364 | send_log "server_port=='$server_port'\n" | |
365 | if {$res != 1} then { | |
366 | verbose -log "Unable to discover the port used by the systemtap server" | |
367 | shutdown_server | |
368 | return 0 | |
369 | } | |
370 | set server_spec [info hostname]:$server_port | |
371 | send_log "server_spec=='$server_spec'\n" | |
372 | ||
373 | set avahi_ok_p 1 | |
374 | if {$listRes != 0} then { | |
2be2e486 | 375 | verbose -log "Unable to automatically find the systemtap server -- check firewall settings for mDNS" |
2d69ca83 | 376 | set avahi_ok_p 0 |
a7dbd06e | 377 | verbose -log "Client/Server tests will be run by contacting the server directly as $server_spec" |
51c1bb7a DB |
378 | |
379 | # Make sure stap can contact the server directly | |
380 | set use_server --use-server=$server_spec | |
381 | set res [catch {exec stap $use_server -p2 -e {probe begin {exit()}}} looksee] | |
382 | if {$res != 0} then { | |
a7dbd06e DB |
383 | verbose -log "Unable to contact the server at $server_spec directly" |
384 | shutdown_server | |
51c1bb7a DB |
385 | return 0 |
386 | } | |
387 | } | |
388 | ||
250fb71a DB |
389 | return 1 |
390 | } | |
391 | ||
fc3d2b46 | 392 | proc start_server { options } { |
aae091fc | 393 | global srcdir env server_pid installed_stap logfile |
250fb71a | 394 | |
cd3a2693 FCE |
395 | if {! [nss_p]} { return 0 } |
396 | ||
72629a44 DB |
397 | # Server management scripts and data are installed if this is an |
398 | # install test, otherwise there is some setup to do. | |
edecda6c | 399 | # Make sure the server management scripts and tools are on the $PATH. |
72629a44 | 400 | if {! [installtest_p]} then { |
574cf27a SC |
401 | set env(PATH) "$srcdir/..:[pwd]/..:$env(PATH)" |
402 | set installed_stap "[pwd]/../stap" | |
67c7a9ac | 403 | set env(SYSTEMTAP_SERVER_SCRIPTS) "$srcdir/.." |
edecda6c DB |
404 | } else { |
405 | set env(PATH) "$env(PKGLIBDIR):$env(PATH)" | |
ff86dcd5 | 406 | set installed_stap "$env(SYSTEMTAP_PATH)/stap" |
2bdb7139 | 407 | set env(SYSTEMTAP_SERVER_SCRIPTS) $env(PKGLIBDIR) |
72629a44 DB |
408 | } |
409 | ||
51c1bb7a | 410 | # Try to start the server. |
78cd5654 | 411 | set status 0 |
fc3d2b46 | 412 | if {[catch {eval {exec env STAP_PR11197_OVERRIDE=1 \ |
78cd5654 | 413 | env SYSTEMTAP_STAP=[exec which stap] stap-start-server \ |
fc3d2b46 | 414 | --log=$logfile} $options} server_pid]} { |
c26c10cb DS |
415 | if {[lindex $::errorCode 0] eq "CHILDSTATUS"} { |
416 | set status [lindex $::errorCode 2] | |
78cd5654 DS |
417 | } |
418 | } | |
419 | verbose -log "output: $server_pid" | |
420 | if { "$server_pid" == "" || $status != 0 } then { | |
a7dbd06e | 421 | verbose -log "Cannot start a systemtap server" |
72629a44 | 422 | set server_pid 0 |
e26df1cb | 423 | return 0 |
72629a44 | 424 | } else { |
543bcb4c | 425 | verbose -log "Started a systemtap server as PID==$server_pid" |
72629a44 DB |
426 | } |
427 | ||
e26df1cb | 428 | return 1 |
72629a44 DB |
429 | } |
430 | ||
431 | proc shutdown_server {} { | |
8501d45c | 432 | global server_pid |
72629a44 | 433 | if { $server_pid != 0 } then { |
543bcb4c | 434 | verbose -log "Stopping the systemtap server with PID==$server_pid" |
3793a797 | 435 | catch {exec stap-stop-server $server_pid} |
7d54db1a | 436 | set server_pid 0 |
72629a44 DB |
437 | } |
438 | ||
574cf27a | 439 | foreach module [glob -nocomplain [pwd]/stap_*.ko] { |
b2ca731b DB |
440 | exec /bin/rm -f $module |
441 | } | |
574cf27a | 442 | foreach sig [glob -nocomplain [pwd]/stap_*.ko.sgn] { |
250fb71a DB |
443 | exec /bin/rm -f $sig |
444 | } | |
72629a44 DB |
445 | } |
446 | ||
cd3a2693 | 447 | |
aa238e24 WC |
448 | proc normalize_arch { arch } { |
449 | if {$arch == "ppc64"} then {return "powerpc"} | |
450 | if {$arch == "s390x"} then {return "s390"} | |
451 | if {$arch == "i686"} then {return "i386"} | |
452 | if {$arch == "armv5tel"} then {return "arm"} | |
453 | if {$arch == "armv7l"} then {return "arm"} | |
454 | if {$arch == "armv7lh"} then {return "arm"} | |
d8faa2f7 | 455 | if {$arch == "aarch64"} then {return "arm64"} |
41016674 | 456 | if {$arch == "ppc64le"} then {return "powerpc"} |
aa238e24 WC |
457 | return $arch |
458 | } | |
459 | ||
99e1fb7a JS |
460 | proc fullpath { path } { |
461 | if {[string index $path 0] != "/"} then { | |
462 | # relative paths are anchored to the current directory | |
463 | return [pwd]/$path | |
464 | } else { | |
465 | return $path | |
466 | } | |
467 | } | |
468 | ||
9446a6d6 | 469 | proc get_system_info {} { |
80363472 | 470 | global Host Snapshot Distro GCC_Version GCC_FullVersion ELF_Version env SElinux Dracut_Version |
bf4ac953 RM |
471 | |
472 | set Host [exec /bin/uname -a] | |
05de43cb FCE |
473 | if [file exists ../SNAPSHOT] { |
474 | set Snapshot [exec /bin/cat ../SNAPSHOT] | |
475 | } elseif [file exists $env(SRCDIR)/../SNAPSHOT] { | |
9446a6d6 WH |
476 | set Snapshot [exec /bin/cat $env(SRCDIR)/../SNAPSHOT] |
477 | } else { | |
48a00e93 | 478 | regexp {version [^)]*} [exec stap -V 2>@ stdout] version |
172d72b3 | 479 | set Snapshot $version |
48a00e93 | 480 | } |
9446a6d6 | 481 | set Distro "Linux" |
268e8bdf DS |
482 | if {[file exists /usr/bin/lsb_release] \ |
483 | && ! [catch {exec /usr/bin/lsb_release -d} dummy]} { | |
172d72b3 FCE |
484 | # this produces one line of this format: |
485 | # Distribution:\tSTRING | |
268e8bdf | 486 | set Distro [lrange $dummy 1 end] |
172d72b3 FCE |
487 | } else { |
488 | foreach f {/etc/fedora-release /etc/enterprise-release /etc/redhat-release /etc/suse-release /etc/debian_version} { | |
489 | if [file exists $f] then {set Distro [exec /bin/cat $f]; break } | |
490 | } | |
23d89280 | 491 | } |
47561106 MW |
492 | # Easily parsable version first major minor patch level |
493 | set n [exec echo "__GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__" | cpp -P] | |
494 | set n [string map {" " "."} $n] | |
8e02c673 | 495 | set n [string map {"\n" ""} $n] |
22a05791 JL |
496 | set GCC_Version "$n" |
497 | # Plus full version between square brackets for GCC_FullVersion | |
47561106 | 498 | set full [exec gcc --version | head -1] |
22a05791 JL |
499 | set GCC_FullVersion "$n \[$full\]" |
500 | # Parse elfutils version stap was compiled with | |
501 | regexp {version [^/]*/([^,]*)} [exec stap -V 2>@ stdout] all ELF_Version | |
528296dc FCE |
502 | # selinux status |
503 | if [file exists /usr/sbin/getenforce] { | |
504 | set SElinux [exec /usr/sbin/getenforce] | |
505 | } else { | |
506 | set SElinux "unknown" | |
507 | } | |
80363472 MC |
508 | # Parse dracut version |
509 | regexp {\d[^\-]*} [exec sh -c "dracut --help 2>&1 | grep Version || echo 0"] Dracut_Version | |
9446a6d6 | 510 | } |
814bc89d | 511 | |
8093ef39 MC |
512 | proc environment_sanity_test {} { |
513 | # PR11798: die if kernel-devel is not sufficient to build any modules | |
514 | if {[catch {exec -ignorestderr stap -p4 -e {probe begin {exit()}}} result]} { | |
515 | puts "\n\n\n**** failed systemtap kernel-devel smoke test:\n" | |
516 | puts $result | |
517 | # puts "****\n" | |
518 | # puts $options | |
519 | puts "\n**** aborting testing.\n" | |
520 | cleanup | |
521 | exit 1 | |
522 | } | |
523 | ||
524 | # PR11798: die also if kernel-debuginfo is not available | |
525 | # NB: if one introduced a [kernel_debuginfo_p] proc like the | |
526 | # ones for uprobes/utrace above, and sprinkled it throughout, | |
527 | # then this wouldn't have to be a failing condition. | |
528 | # Note the --skip-badvars -w, we just care there is some debuginfo, | |
529 | # it is allowed have bad var location descriptors (which will cause | |
530 | # some tests to fail of course). Just test -p2, kernel-devel smoke | |
531 | # test above does a full module build, we don't need another one. | |
532 | if {[catch {exec -ignorestderr stap --skip-badvars -w -p2 -e {probe syscall.open {println (argstr)}}} result]} { | |
533 | puts "\n\n\n**** failed systemtap kernel-debuginfo smoke test:\n" | |
534 | puts $result | |
535 | # puts "****\n" | |
536 | # puts $options | |
537 | puts "\n**** aborting testing.\n" | |
538 | cleanup | |
539 | exit 1 | |
540 | } | |
541 | ||
542 | # Create a tempory directory. | |
543 | if {[catch {exec mktemp -d -t staptestXXXXXX-sanity-test} tmpdir]} { | |
544 | verbose -log "Failed to create temporary directory: $tmpdir" | |
545 | exit 1 | |
546 | } | |
547 | set curdir [pwd] | |
548 | cd ${tmpdir} | |
549 | ||
550 | # Make more likely that all development packages for the supported ABIs (-m64 -m32/-m31) | |
551 | # are installed by building a quick hello.c and hello.cxx program with both. | |
552 | set source "hello.c" | |
553 | set hello_file [open $source "w"] | |
554 | puts $hello_file "#include <stdio.h>" | |
555 | puts $hello_file "int main () { printf(\"Hello World!\"); return 0; }" | |
556 | close $hello_file | |
557 | for {set i 0} {$i < [arch_compile_flags]} {incr i} { | |
558 | set flags "additional_flags=-g compiler=gcc [arch_compile_flag $i]" | |
559 | set exe "hello-[arch_compile_flag_name $i]" | |
560 | set result [target_compile $source $exe executable $flags] | |
561 | if { $result != "" } { | |
562 | puts "\n\n\n**** failed gcc [arch_compile_flag_name $i] smoke test:\n" | |
563 | puts $result | |
564 | puts "Please install libgcc and glibc development packages for [arch_compile_flag_name $i]\n" | |
565 | } | |
566 | } | |
567 | set source "hello.cxx" | |
568 | set hello_file [open $source "w"] | |
569 | puts $hello_file "#include <iostream>" | |
570 | puts $hello_file "using namespace std;" | |
571 | puts $hello_file "int main () { cout << \"Hello World!\" << endl; return 0; }" | |
572 | close $hello_file | |
573 | for {set i 0} {$i < [arch_compile_flags]} {incr i} { | |
574 | set flags "additional_flags=-g compiler=g++ [arch_compile_flag $i]" | |
575 | set exe "hello-[arch_compile_flag_name $i]" | |
576 | set result [target_compile $source $exe executable $flags] | |
577 | if { $result != "" } { | |
578 | puts "\n\n\n**** failed g++ [arch_compile_flag_name $i] smoke test:\n" | |
579 | puts $result | |
580 | puts "Please install libstdc++-devel package for [arch_compile_flag_name $i]\n" | |
581 | } | |
582 | } | |
583 | ||
584 | cd ${curdir} | |
585 | catch {exec rm -rf $tmpdir} | |
586 | } | |
587 | ||
e26df1cb | 588 | if {! [setup_systemtap_environment]} then { |
51c1bb7a DB |
589 | cleanup |
590 | exit 1 | |
e26df1cb DB |
591 | } |
592 | ||
814bc89d | 593 | print_systemtap_version |
9446a6d6 | 594 | get_system_info |
814bc89d | 595 | |
8093ef39 MC |
596 | if { ! [info exists env(STAP_PARALLEL)] } { |
597 | environment_sanity_test | |
03712201 FCE |
598 | } |
599 | ||
8093ef39 MC |
600 | proc systemtap_init {args} { |
601 | global env srcdir artifactdir | |
602 | if {[info exists env(STAP_PARALLEL)] } { | |
603 | regsub {\.exp$} $args {} args | |
604 | regsub ${srcdir}/ $args {} args | |
605 | set artifactdir "$srcdir/artifacts/$args" | |
606 | if {[catch {exec mkdir -p $artifactdir} err_msg]} { | |
607 | verbose -log "Failed to create artifacts directory: $err_msg" | |
608 | exit 1 | |
609 | } | |
610 | # Switch to the artifacts directory before the testcase starts | |
611 | cd $artifactdir | |
612 | } | |
613 | } | |
614 | ||
615 | proc systemtap_finish {args} { | |
616 | global env srcdir | |
617 | if {[info exists env(STAP_PARALLEL)] } { | |
618 | # Return from the artifacts directory after the testcase finishes | |
619 | cd $srcdir | |
620 | } | |
03712201 FCE |
621 | } |
622 | ||
814bc89d | 623 | proc systemtap_version {} {} |
d5658775 | 624 | |
7d54db1a | 625 | proc cleanup {} { |
d5658775 | 626 | # Stop the stap server, if we started it. |
7d54db1a | 627 | shutdown_server |
d5658775 | 628 | } |
814bc89d | 629 | |
0ecbca4c | 630 | |
8c94efa7 DS |
631 | proc stap_run_batch {filename args} { |
632 | verbose -log "starting $filename $args" | |
5ba96b90 FCE |
633 | |
634 | # Many of our test cases use "#! stap ...". Since these lack | |
635 | # /full/paths, they are not really executable. (We can't have | |
636 | # /full/paths because the choice of systemtap interpreter is set | |
637 | # at "make check" time.) | |
638 | ||
639 | # So we cheat. If the file begins with "#! stap", we will spawn | |
640 | # stap manually here (relying on $PATH). Otherwise, we presume | |
641 | # the file properly executable. | |
642 | ||
8c94efa7 | 643 | set file [open $filename r] |
5ba96b90 FCE |
644 | set firstbits [gets $file] |
645 | close $file | |
646 | if [regexp -line {\#! stap (.*)} $firstbits -> stap_args] { | |
8c94efa7 | 647 | verbose -log "spawn1 stap $stap_args $filename $args" |
353cb874 MW |
648 | # Make sure we don't accidentially add an extra empty argument. |
649 | if {$args == ""} { | |
6b131ba7 | 650 | eval spawn stap $stap_args $filename |
353cb874 | 651 | } else { |
6b131ba7 | 652 | eval spawn stap $stap_args $filename $args |
353cb874 | 653 | } |
5ba96b90 | 654 | } else { |
8c94efa7 | 655 | verbose -log "spawn2 $filename $args" |
353cb874 MW |
656 | # Make sure we don't accidentially add an extra empty argument. |
657 | if {$args == ""} { | |
5c5f2389 | 658 | spawn $filename |
353cb874 | 659 | } else { |
5c5f2389 | 660 | spawn $filename $args |
353cb874 | 661 | } |
5ba96b90 FCE |
662 | } |
663 | ||
bf4ac953 | 664 | expect { |
59cbc061 | 665 | -timeout -1 |
14bdb164 | 666 | -re {[^\r\n]*\r\n} { exp_continue } |
bbbce017 | 667 | eof { } |
bbbce017 | 668 | } |
0ecbca4c FCE |
669 | set results [wait] |
670 | verbose -log "wait results: $results" | |
c2d92a15 MH |
671 | if {[llength $results] >= 5} { |
672 | # Unexpected output. stap must have crashed | |
673 | return -1 | |
674 | } else { | |
675 | return [lindex $results 3] | |
676 | } | |
68e7e59b | 677 | } |
14b31996 WC |
678 | |
679 | proc as_root { command } { | |
2b70fd78 | 680 | set effective_uid [exec /usr/bin/id -u] |
14b31996 | 681 | |
2b70fd78 DS |
682 | if {$effective_uid != 0} { |
683 | set command "sudo $command" | |
684 | } | |
685 | verbose -log "as_root $command" | |
686 | set res [catch {eval exec $command} value] | |
687 | verbose -log "OUT $value" | |
688 | verbose -log "RC $res" | |
689 | return $res | |
690 | } | |
bf4ac953 | 691 | |
005f34a8 | 692 | proc as_non_root { command } { |
2b70fd78 DS |
693 | set effective_uid [exec /usr/bin/id -u] |
694 | ||
695 | if {$effective_uid == 0} { | |
edb7542e DS |
696 | # If logname fails (which it can if we're not in a login |
697 | # shell) or if we're root, use user 'nobody'. | |
2b70fd78 DS |
698 | # |
699 | # Note that user 'nobody' can't use systemtap to load kernel | |
700 | # modules, since he isn't a member of the stapusr/stapdev | |
701 | # groups. But, 'nobody' can use systemtap to compile a kernel | |
702 | # module. | |
edb7542e DS |
703 | set logname "root" |
704 | if {[catch {exec /usr/bin/logname} logname] || $logname == "root"} { | |
2b70fd78 DS |
705 | set logname "nobody" |
706 | } | |
41029fd7 DS |
707 | |
708 | # User 'nobody' doesn't have a home directory, which means we | |
709 | # can't create ~nobody/.systemtap. So, temporarily override | |
710 | # SYSTEMTAP_DIR. | |
711 | if {$logname == "nobody"} { | |
712 | set stap_dir "/tmp/.systemtap-nobody" | |
713 | set command "su -s /bin/sh $logname -c \"SYSTEMTAP_DIR=$stap_dir $command\"" | |
714 | } else { | |
715 | set command "su -s /bin/sh $logname -c \"$command\"" | |
716 | } | |
2b70fd78 DS |
717 | } |
718 | verbose -log "as_non_root $command" | |
719 | set res [catch {eval exec $command} value] | |
41029fd7 DS |
720 | if {$effective_uid == 0 && $logname == "nobody"} { |
721 | # If we created a SYSTEMTAP_DIR for user 'nobody' above, we | |
722 | # can now remove it. | |
723 | catch {exec rm -rf $stap_dir} | |
724 | } | |
2b70fd78 DS |
725 | verbose -log "OUT $value" |
726 | verbose -log "RC $res" | |
727 | return $res | |
005f34a8 CM |
728 | } |
729 | ||
bf4ac953 | 730 | proc sdt_includes {} { |
6b51ee12 | 731 | global srcdir env |
bf4ac953 RM |
732 | |
733 | # The wrapper sys/sdt.h for testing STAP_SDT_V[12] is here. | |
734 | set dirs [list $srcdir] | |
735 | ||
736 | if {[installtest_p]} { | |
737 | # Use the installed <sys/sdt.h>. | |
738 | lappend dirs $env(SYSTEMTAP_INCLUDES) | |
739 | } else { | |
740 | # Find <sys/sdt.h> in the source tree. | |
741 | lappend dirs $srcdir/../includes | |
742 | # The uninstalled, configured sdt-config.h has to be found here. | |
831b13d6 | 743 | lappend dirs ../includes/sys |
bf4ac953 RM |
744 | } |
745 | ||
746 | set flags "" | |
747 | foreach dir $dirs { | |
831b13d6 | 748 | set flags "$flags additional_flags=-isystem${dir}" |
bf4ac953 RM |
749 | } |
750 | ||
751 | return $flags | |
752 | } | |
d9151131 DS |
753 | |
754 | proc stripped_p { EXE } { | |
755 | if { [catch {eval exec "file $EXE | grep -q \"not stripped\""} dummy] } { | |
756 | return 1 | |
757 | } | |
758 | return 0 | |
759 | } | |
ff579492 JS |
760 | |
761 | proc prelink_p {} { | |
762 | global prelink_bin | |
763 | set prelink_bin "/usr/sbin/prelink" | |
764 | return [file exists "$prelink_bin"] | |
765 | } | |
766 | ||
767 | # Run prelink via a temp file, so it can succeed even when running from an nfs | |
768 | # $HOME, for instance. Otherwise, prelink complains that it can't restore context. | |
769 | proc prelink { FILE ADDR } { | |
770 | global prelink_bin | |
771 | if {![prelink_p]} { | |
772 | verbose -log "Prelink is not found on this system" | |
773 | return 0 | |
774 | } | |
775 | if {[catch {exec mktemp -t staptestXXXXXX} tmpfile]} { | |
776 | verbose -log "Failed to create prelink temporary file: $tmpfile" | |
777 | return 0 | |
778 | } | |
779 | if {[catch {exec cp -a "$FILE" "$tmpfile"} result]} { | |
780 | verbose -log "Failed to copy file for prelink: $result" | |
781 | catch {exec rm -rf "$tmpfile"} | |
782 | return 0 | |
783 | } | |
784 | set prelink_cmd [concat "$prelink_bin" -vfNR -r "$ADDR" "$tmpfile"] | |
785 | send_log "Executing: $prelink_cmd\n" | |
786 | if {[catch {eval exec $prelink_cmd} result]} { | |
787 | verbose -log "Prelink failed: $result" | |
788 | catch {exec rm -rf "$tmpfile"} | |
789 | return 0 | |
790 | } | |
791 | if {[catch {exec mv "$tmpfile" "$FILE"} result]} { | |
792 | verbose -log "Failed to move prelinked file back: $result" | |
793 | catch {exec rm -rf "$tmpfile"} | |
794 | return 0 | |
795 | } | |
796 | return 1 | |
797 | } | |
0b872dd0 JL |
798 | |
799 | # Send signal SIG to PID. If KILL_TIMEOUT > 0, waits KILL_TIMEOUT seconds before | |
800 | # also sending a SIGKILL signal to PID. SIG can be with or without leading '-'. | |
801 | proc kill { SIG PID {KILL_TIMEOUT 0} } { | |
802 | global kill_needs_doubledash | |
803 | ||
804 | if {$kill_needs_doubledash} { | |
805 | set PID "-- $PID" | |
806 | } | |
807 | if {![string match -* $SIG]} { | |
808 | set SIG "-$SIG" | |
809 | } | |
810 | ||
811 | verbose -log "Executing: kill $SIG $PID" | |
930c871d JL |
812 | if {[catch {eval exec kill $SIG $PID} killout]} { |
813 | verbose -log "kill: $killout" | |
814 | } | |
0b872dd0 | 815 | |
3f11227f JL |
816 | if {$KILL_TIMEOUT > 0} { |
817 | while {$KILL_TIMEOUT > 0} { | |
818 | if {![file isdirectory /proc/$PID]} { | |
819 | return | |
820 | } | |
821 | sleep 1 | |
822 | incr KILL_TIMEOUT -1 | |
823 | } | |
0b872dd0 | 824 | verbose -log "Executing: kill -KILL $PID" |
930c871d JL |
825 | if {[catch {eval exec kill -KILL $PID} killout]} { |
826 | verbose -log "kill: $killout" | |
827 | } | |
0b872dd0 JL |
828 | } |
829 | } | |
6bcbab76 JL |
830 | |
831 | # Compares vers1 to vers2. Returns an integer less than, equal to, or greater | |
832 | # than zero if vers1 is before, equal, or after vers2. Similar to the GNU | |
833 | # extension strverscmp(3), but restricted to simple M.N... version numbers. | |
834 | proc strverscmp { vers1 vers2 } { | |
835 | ||
836 | # Check that both versions are valid M.N... format | |
837 | if {![regexp {^[0-9]+(\.[0-9]+)*$} $vers1]} { | |
838 | error "$vers1 is not a valid version number" | |
839 | } | |
840 | if {![regexp {^[0-9]+(\.[0-9]+)*$} $vers2]} { | |
841 | error "$vers2 is not a valid version number" | |
842 | } | |
843 | ||
844 | while {1} { | |
845 | ||
846 | # Get the next M for each as well as following N... | |
847 | regexp {^([0-9]+)(\.(.*))?} $vers1 dummy subvers1 dummy nextvers1 | |
848 | regexp {^([0-9]+)(\.(.*))?} $vers2 dummy subvers2 dummy nextvers2 | |
849 | ||
850 | # Compare M | |
851 | if {$subvers1 < $subvers2} { return -1 } | |
852 | if {$subvers1 > $subvers2} { return 1 } | |
853 | # The M parts are equal | |
854 | ||
855 | # Check if one (or both) of them don't have a next subversion | |
856 | if {![string length $nextvers1] \ | |
857 | && ![string length $nextvers2]} { return 0 } | |
858 | if {![string length $nextvers1] \ | |
859 | && [string length $nextvers2]} { return -1 } | |
860 | if {[string length $nextvers1] \ | |
861 | && ![string length $nextvers2]} { return 1 } | |
862 | ||
863 | # They both have a subversion following, let's re-iterate | |
864 | ||
865 | # Sanity check that we're making progress and not looping forever | |
866 | if {[string length $nextvers1] >= [string length $vers1]} \ | |
867 | { error "$vers1 not converging" } | |
868 | if {[string length $nextvers2] >= [string length $vers2]} \ | |
869 | { error "$vers2 not converging" } | |
870 | ||
871 | set vers1 $nextvers1 | |
872 | set vers2 $nextvers2 | |
873 | } | |
874 | } |