]> sourceware.org Git - systemtap.git/commitdiff
testsuite/systemtap.base: add new testcase uprobes_filtering.exp
authorJonathan Lebon <jlebon@redhat.com>
Wed, 19 Jun 2013 14:12:48 +0000 (10:12 -0400)
committerJonathan Lebon <jlebon@redhat.com>
Wed, 19 Jun 2013 18:12:38 +0000 (14:12 -0400)
This new testcase uses the newly implemented define UPROBES_HITCOUNT
(see previous commit) to verify that uprobes filtering work as it
should.

If prefiltering is supported by the kernel (from 3.9), then it verifies
that UPROBE_HANDLER_REMOVE is obeyed and that the prehandler() is not
called over and over for unwanted processes, allowing the stap script
to run at full speed.

In both cases (whether or not prefiltering is supported), it also
verifies that the probe handlers are called only for the processes of
interest and no other (i.e. it makes sure that the filtering in
stapiu_probe_prehandler() works).

testsuite/systemtap.base/uprobes_filtering.exp [new file with mode: 0644]

diff --git a/testsuite/systemtap.base/uprobes_filtering.exp b/testsuite/systemtap.base/uprobes_filtering.exp
new file mode 100644 (file)
index 0000000..f043a86
--- /dev/null
@@ -0,0 +1,150 @@
+# This test has two purposes:
+# 1. To verify that uprobes is correctly filtering unwanted processes,
+#    allowing stap scripts to run at full speed
+# 2. To verify that stapiu_probe_prehandler() is correctly filtering
+#    unwanted processes
+# This is done by comparing the number of calls to
+# stapiu_probe_prehandler() and stapiu_probe_handler() using the
+# -DUPROBES_HITCOUNT define.added in commit 68561b3.
+
+# Note that this test relies on the basic assumption that there are no
+# other stap sessions or uprobes inserted in the benchmark inode of
+# stap. Otherwise, all hitcounts will be thrown off.
+
+# We need to actually run things
+if {! [installtest_p]} { return }
+
+# So that sudo stap works in case we're not running the test as root
+set installed_stap "$env(SYSTEMTAP_PATH)/stap"
+
+set test "uprobes_filtering"
+
+# Testing steps:
+# 1. check if we're root or user using id -u
+# 2. run mark("benchmark") w/ --privilege=stapusr
+# 3. run benchmark as user
+# 4. run benchmark as root
+# 5. stop process in 2.
+# 6. Check that the handler was called only for the right process
+# 7. Check that the wrong process was filtered out
+#    7a. First check if kernel prefiltering is supported
+#    7b. Verify hitcount results depending on prefiltering support
+
+# 1. Check if we're root or user
+set am_root [expr 0 == [exec id -u]]
+
+# 2. Start the background benchmark hitcounter
+spawn stap -DUPROBES_HITCOUNT --privilege=stapusr --vp 00003 \
+       -e "probe process(\"stap\").mark(\"benchmark\") \{ next \}"
+set stap_id $spawn_id
+set failed 1
+expect {
+       -timeout 30
+       -re {systemtap_module_init\(\)\ returned\ 0} { set failed 0 }
+       timeout {exec kill -s KILL -[exp_pid -i $stap_id]}
+}
+if {$failed} {
+       fail "$test (timeout: can't start benchmark monitor)"
+       return
+}
+
+# 3. Run benchmark as user
+set non_root_loops 11111111
+if {[as_non_root "$installed_stap \
+               --benchmark-sdt-loops=$non_root_loops"]} {
+       fail "$test (can't start non-root benchmark)"
+       return
+}
+
+# 4. Run benchmark as root
+set root_loops 10101010
+if {[as_root "$installed_stap --benchmark-sdt-loops=$root_loops"]} {
+       fail "$test (can't start root benchmark)"
+       return
+}
+
+# 5. Stop process from step 2
+exec kill -s TERM [exp_pid -i $stap_id]
+set prehandler_hitcount -1
+set handler_hitcount -1
+expect {
+       -timeout 30
+       -i $stap_id
+       -re {stapiu_probe_prehandler\(\)\ called\ ([0-9]+)\ times} {
+               set prehandler_hitcount $expect_out(1,string)
+               exp_continue
+       }
+       -re {stapiu_probe_handler\(\)\ called\ ([0-9]+)\ times} {
+               set handler_hitcount $expect_out(1,string)
+       }
+       timeout {
+               fail "$test (timeout: can't stop benchmark monitor)"
+               exec kill -s KILL -[exp_pid -i $stap_id]
+               return
+       }
+}
+
+if {$prehandler_hitcount == -1 || $handler_hitcount == -1} {
+       fail "$test (could not get prehandler/handler hitcount)"
+       verbose -log "this happens if stap doesn't support UPROBES_HITCOUNT"
+       return
+}
+
+# 6. Check that the handler was called only for the right process
+#    This means that if we're root, then handler() should have been
+#    called $root_loops times only, and vice-versa for not root
+if {(!$am_root && $handler_hitcount != $non_root_loops)
+               || ($am_root && $handler_hitcount != $root_loops)} {
+       fail "$test (handler was not called the right number of times)"
+       if {$am_root} {set n $root_loops} else {set n $non_root_loops}
+       verbose -log "expected number of calls: $n"
+       verbose -log "actual number of calls: $handler_hitcount"
+       return
+}
+
+# 7. Check that the wrong process was filtered out
+
+# 7a. First check if kernel prefiltering is supported
+
+# Relies on the fact that stap won't pass compilation if not supported
+# The ignorestderr is not strictly necessary since stap doesn't output
+# anything to stderr, but the intent is to only care about the exit code
+set prefilter_support [expr ![catch {exec stap -p4 -g \
+               -e "probe begin \{%\{UPROBE_HANDLER_REMOVE%\}\}" 2> /dev/null}]]
+verbose -log "kernel prefiltering support = $prefilter_support"
+
+# 7b. Verify hitcount results depending on prefiltering support
+
+# If prefiltering is not supported, then we expect the prehandler to
+# be called $root_loops + $non_root_loops times
+if {!$prefilter_support} {
+       set total [expr {$root_loops + $non_root_loops}]
+       if {$prehandler_hitcount != $total} {
+               fail "$test (prehandler was not called the right number of times)"
+               verbose -log "expected number of calls: $total"
+               verbose -log "actual number of calls: $prehandler_hitcount"
+               return
+       }
+} else {
+# Prefiltering is supported, so we expect the prehandler to be called
+# only one time more than handler.
+
+# TODO: Verify that it will always be only 1 greater. From a look at
+# kernel/events/uprobes.c, it seems that in the handler_chain() func,
+# after handler() returns, the next call is unapply_uprobe() (assuming
+# we are the only consumers for this probe), which will remove the
+# uprobe. Since the handler() call is wrapped in semaphores, we should
+# get no other calls before the first handler_chain() finishes.
+       set total [expr {$handler_hitcount + 1}]
+       if {$prehandler_hitcount != $total} {
+               fail "$test (prehandler was not called the right number of times)"
+               verbose -log "expected number of calls: $total"
+               verbose -log "actual number of calls: $prehandler_hitcount"
+               verbose -log "this can happen if other uprobes are inserted at\
+                       the same location"
+               return
+       }
+}
+
+pass $test
+
This page took 0.03693 seconds and 5 git commands to generate.