summaryrefslogtreecommitdiffstats
path: root/testsuite/systemtap.base
diff options
context:
space:
mode:
Diffstat (limited to 'testsuite/systemtap.base')
-rw-r--r--testsuite/systemtap.base/bz6850.c87
-rw-r--r--testsuite/systemtap.base/bz6850.exp21
-rw-r--r--testsuite/systemtap.base/bz6850.stp7
3 files changed, 115 insertions, 0 deletions
diff --git a/testsuite/systemtap.base/bz6850.c b/testsuite/systemtap.base/bz6850.c
new file mode 100644
index 00000000..a8b78110
--- /dev/null
+++ b/testsuite/systemtap.base/bz6850.c
@@ -0,0 +1,87 @@
+/* Regression test for bugzilla 6850 */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#define PASS_MARKER "./bz6850_pass"
+
+/* All this in an attempt to defeat gcc's over-aggressive inlining... */
+typedef pid_t (*forker)(int);
+static forker call_chain[];
+
+/*
+ * Both parent and child return from fork2() and fork1(). Both
+ * processes will hit the uretprobe trampolines. The handlers should
+ * run in the parent. With the bug fix in place, the child will return
+ * correctly and do the exec (but won't run the handlers).
+ */
+static pid_t fork2(int ignored)
+{
+ return fork();
+}
+
+static pid_t fork1(int func_index)
+{
+ ++func_index;
+ return call_chain[func_index](func_index); /* fork2() */
+}
+
+static pid_t fork_and_exec2(int func_index)
+{
+ pid_t child;
+ ++func_index;
+ child = call_chain[func_index](func_index); /* fork1() */
+ if (child == 0) {
+ /* I'm the child. Create the marker file. */
+ char *child_args[] = { "/bin/touch", PASS_MARKER, NULL };
+ char *child_env[] = { NULL };
+ execve(child_args[0], child_args, child_env);
+ perror("execve");
+ fprintf(stderr, "FAIL: child couldn't exec.\n");
+ exit(2);
+ }
+ return child;
+}
+
+static pid_t fork_and_exec1(int func_index)
+{
+ ++func_index;
+ return call_chain[func_index](func_index); /* fork_and_exec2() */
+}
+
+static forker call_chain[] = {
+ fork_and_exec1,
+ fork_and_exec2,
+ fork1,
+ fork2,
+ NULL
+};
+
+main()
+{
+ pid_t child, wait_child;
+ int status = 0;
+
+ (void) unlink(PASS_MARKER);
+ child = call_chain[0](0); /* fork_and_exec1() */
+ if (child < 0) {
+ fprintf(stderr, "FAIL: fork_and_exec1() failed.\n");
+ exit(1);
+ }
+ wait_child = wait(&status);
+ if (wait_child != child) {
+ fprintf(stderr, "FAIL: waited for %d but got %d\n",
+ child, wait_child);
+ exit(1);
+ }
+ if (WEXITSTATUS(status) != 0) {
+ fprintf(stderr, "FAIL: child died with status = %d\n",
+ WEXITSTATUS(status));
+ exit(1);
+ }
+ exit(0);
+}
diff --git a/testsuite/systemtap.base/bz6850.exp b/testsuite/systemtap.base/bz6850.exp
new file mode 100644
index 00000000..cd56ddce
--- /dev/null
+++ b/testsuite/systemtap.base/bz6850.exp
@@ -0,0 +1,21 @@
+set test bz6850
+
+catch {exec gcc -g -o bz6850 $srcdir/$subdir/bz6850.c} err
+if {$err == "" && [file exists bz6850]} then { pass "$test compile" } else { fail "$test compile" }
+
+set rc [stap_run_batch $srcdir/$subdir/bz6850.stp]
+if {$rc == 0} then { pass "$test -p4" } else { fail "$test -p4" }
+
+if {! [installtest_p]} { untested "$test -p5"; return }
+
+spawn sudo stap $srcdir/$subdir/bz6850.stp -c ./bz6850
+expect {
+ -timeout 60
+ -re {[^\r\n]*called\r\n} { exp_continue }
+ -re {[^\r\n]*returns\r\n} { exp_continue }
+ timeout { fail "$test (timeout)" }
+ eof { }
+}
+wait
+if {[file exists bz6850_pass]} then { pass "$test -p5" } else { fail "$test -p5" }
+exec rm -f bz6850_pass bz6850
diff --git a/testsuite/systemtap.base/bz6850.stp b/testsuite/systemtap.base/bz6850.stp
new file mode 100644
index 00000000..d6f41862
--- /dev/null
+++ b/testsuite/systemtap.base/bz6850.stp
@@ -0,0 +1,7 @@
+#! stap -p4
+probe process("./bz6850").function("*").call {
+ printf("%s called\n", probefunc())
+}
+probe process("./bz6850").function("*").return {
+ printf("%s returns\n", probefunc())
+}