diff options
Diffstat (limited to 'testsuite/systemtap.base')
-rw-r--r-- | testsuite/systemtap.base/bz6850.c | 87 | ||||
-rw-r--r-- | testsuite/systemtap.base/bz6850.exp | 21 | ||||
-rw-r--r-- | testsuite/systemtap.base/bz6850.stp | 7 |
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()) +} |