Changeset View
Standalone View
tests/sys/kern/ptrace_test.c
Show First 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | |||||
#include <sys/user.h> | #include <sys/user.h> | ||||
#include <sys/wait.h> | #include <sys/wait.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <machine/cpufunc.h> | #include <machine/cpufunc.h> | ||||
#include <pthread.h> | #include <pthread.h> | ||||
#include <sched.h> | #include <sched.h> | ||||
#include <semaphore.h> | #include <semaphore.h> | ||||
#include <signal.h> | #include <signal.h> | ||||
#include <stdarg.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <atf-c.h> | #include <atf-c.h> | ||||
/* | /* | ||||
* Architectures with a user-visible breakpoint(). | * Architectures with a user-visible breakpoint(). | ||||
*/ | */ | ||||
Show All 25 Lines | |||||
#endif | #endif | ||||
#endif | #endif | ||||
/* | /* | ||||
* A variant of ATF_REQUIRE that is suitable for use in child | * A variant of ATF_REQUIRE that is suitable for use in child | ||||
* processes. This only works if the parent process is tripped up by | * processes. This only works if the parent process is tripped up by | ||||
* the early exit and fails some requirement itself. | * the early exit and fails some requirement itself. | ||||
*/ | */ | ||||
#define CHILD_REQUIRE(exp) do { \ | #define CHILD_REQUIRE(exp) do { \ | ||||
if (!(exp)) \ | if (!(exp)) \ | ||||
child_fail_require(__FILE__, __LINE__, \ | child_fail_require(__FILE__, __LINE__, \ | ||||
#exp " not met"); \ | #exp " not met\n"); \ | ||||
} while (0) | } while (0) | ||||
#define CHILD_REQUIRE_EQ(actual, expected) do { \ | |||||
jhb: I would be tempted to drop the _INT suffix since you are using `__typeof__`, etc. I would… | |||||
Done Inline ActionsYeah I was thinking it means "any type that can meaningfully be cast to an integer". Will update the diff to remove the suffix shortly. arichardson: Yeah I was thinking it means "any type that can meaningfully be cast to an integer". Will… | |||||
__typeof__(expected) _e = expected; \ | |||||
__typeof__(actual) _a = actual; \ | |||||
if (_e != _a) \ | |||||
child_fail_require(__FILE__, __LINE__, #actual \ | |||||
" (%jd) == " #expected " (%jd) not met\n", \ | |||||
(intmax_t)_a, (intmax_t)_e); \ | |||||
Done Inline ActionsMaybe s/long long/intmax_t/? We tend to use [u]intmax_t and %j for printing arbitrary integers rather than long long. jhb: Maybe s/long long/intmax_t/? We tend to use [u]intmax_t and %j for printing arbitrary integers… | |||||
} while (0) | |||||
Done Inline ActionsPer style(9) every line after the #define should be deindented by one tab. markj: Per style(9) every line after the #define should be deindented by one tab. | |||||
Done Inline ActionsI tried to match the macro above, will remove one leading tab in both. arichardson: I tried to match the macro above, will remove one leading tab in both. | |||||
static __dead2 void | static __dead2 void | ||||
child_fail_require(const char *file, int line, const char *str) | child_fail_require(const char *file, int line, const char *fmt, ...) | ||||
{ | { | ||||
char buf[128]; | va_list ap; | ||||
char buf[1024]; | |||||
Done Inline Actionss/2/STDERR_FILENO/? Why not use fprintf(stderr)? markj: s/2/STDERR_FILENO/? Why not use fprintf(stderr)? | |||||
Done Inline ActionsI'm not sure why the previous code didn't use fprintf(). I just replaced the write(2, buf, strlen(buf)) with dprintf, but being able to use vfprintf() would be even simpler. I'll defer to @jhb who appears to have written this. arichardson: I'm not sure why the previous code didn't use fprintf(). I just replaced the `write(2, buf… | |||||
Done Inline ActionsThe reason it used write(2) previously was to avoid dealing with any unflushed stdio buffers after fork() I think. I feel like I got duplicate output previously as I probably wouldn't have resorted to that just due to paranoia. jhb: The reason it used write(2) previously was to avoid dealing with any unflushed stdio buffers… | |||||
snprintf(buf, sizeof(buf), "%s:%d: %s\n", file, line, str); | /* Use write() not fprintf() to avoid possible duplicate output. */ | ||||
write(2, buf, strlen(buf)); | snprintf(buf, sizeof(buf), "%s:%d: ", file, line); | ||||
write(STDERR_FILENO, buf, strlen(buf)); | |||||
va_start(ap, fmt); | |||||
vsnprintf(buf, sizeof(buf), fmt, ap); | |||||
write(STDERR_FILENO, buf, strlen(buf)); | |||||
va_end(ap); | |||||
_exit(32); | _exit(32); | ||||
} | } | ||||
#define REQUIRE_EQ(actual, expected) do { \ | |||||
Not Done Inline ActionsI think you still don't need this and can just use ATF_REQUIRE_EQ() directly instead? jhb: I think you still don't need this and can just use ATF_REQUIRE_EQ() directly instead? | |||||
Done Inline ActionsThe reason I did this is that ATF_REQUIRE_EQ is stupid and doesn't print any useful information. arichardson: The reason I did this is that ATF_REQUIRE_EQ is stupid and doesn't print any useful information. | |||||
Not Done Inline ActionsHumm, maybe we should fix those to include the values as well as the source name? I guess it is easy to convert these in the future if someone fixes that. A proper ATF_REQUIRE_EQ would have to do some switches on types though to use %p for pointers vs %jd for scalars and something else for floats. jhb: Humm, maybe we should fix those to include the values as well as the source name? I guess it… | |||||
__typeof__(expected) _e = expected; \ | |||||
__typeof__(actual) _a = actual; \ | |||||
ATF_REQUIRE_MSG(_e == _a, #actual " (%jd) == " \ | |||||
#expected " (%jd) not met", (intmax_t)_a, (intmax_t)_e); \ | |||||
} while (0) | |||||
Done Inline ActionsDitto. markj: Ditto. | |||||
static void | static void | ||||
trace_me(void) | trace_me(void) | ||||
{ | { | ||||
/* Attach the parent process as a tracer of this process. */ | /* Attach the parent process as a tracer of this process. */ | ||||
CHILD_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); | CHILD_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); | ||||
/* Trigger a stop. */ | /* Trigger a stop. */ | ||||
raise(SIGSTOP); | raise(SIGSTOP); | ||||
} | } | ||||
static void | static void | ||||
attach_child(pid_t pid) | attach_child(pid_t pid) | ||||
{ | { | ||||
pid_t wpid; | pid_t wpid; | ||||
int status; | int status; | ||||
ATF_REQUIRE(ptrace(PT_ATTACH, pid, NULL, 0) == 0); | REQUIRE_EQ(ptrace(PT_ATTACH, pid, NULL, 0), 0); | ||||
wpid = waitpid(pid, &status, 0); | wpid = waitpid(pid, &status, 0); | ||||
ATF_REQUIRE(wpid == pid); | REQUIRE_EQ(wpid, pid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
} | } | ||||
static void | static void | ||||
wait_for_zombie(pid_t pid) | wait_for_zombie(pid_t pid) | ||||
{ | { | ||||
/* | /* | ||||
* Wait for a process to exit. This is kind of gross, but | * Wait for a process to exit. This is kind of gross, but | ||||
Show All 9 Lines | for (;;) { | ||||
int mib[4]; | int mib[4]; | ||||
mib[0] = CTL_KERN; | mib[0] = CTL_KERN; | ||||
mib[1] = KERN_PROC; | mib[1] = KERN_PROC; | ||||
mib[2] = KERN_PROC_PID; | mib[2] = KERN_PROC_PID; | ||||
mib[3] = pid; | mib[3] = pid; | ||||
len = sizeof(kp); | len = sizeof(kp); | ||||
if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) { | if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) { | ||||
ATF_REQUIRE(errno == ESRCH); | REQUIRE_EQ(errno, ESRCH); | ||||
break; | break; | ||||
} | } | ||||
if (kp.ki_stat == SZOMB) | if (kp.ki_stat == SZOMB) | ||||
break; | break; | ||||
usleep(5000); | usleep(5000); | ||||
} | } | ||||
} | } | ||||
Show All 14 Lines | if (child == 0) { | ||||
_exit(1); | _exit(1); | ||||
} | } | ||||
/* Parent process. */ | /* Parent process. */ | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(child, &status, 0); | wpid = waitpid(child, &status, 0); | ||||
ATF_REQUIRE(wpid == child); | REQUIRE_EQ(wpid, child); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); | ||||
/* The second wait() should report the exit status. */ | /* The second wait() should report the exit status. */ | ||||
wpid = waitpid(child, &status, 0); | wpid = waitpid(child, &status, 0); | ||||
ATF_REQUIRE(wpid == child); | REQUIRE_EQ(wpid, child); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
/* The child should no longer exist. */ | /* The child should no longer exist. */ | ||||
wpid = waitpid(child, &status, 0); | wpid = waitpid(child, &status, 0); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that a parent debugger process "sees" the exit of a debugged | * Verify that a parent debugger process "sees" the exit of a debugged | ||||
* process exactly once when attached via PT_ATTACH. | * process exactly once when attached via PT_ATTACH. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_attach); | ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_attach); | ||||
ATF_TC_BODY(ptrace__parent_wait_after_attach, tc) | ATF_TC_BODY(ptrace__parent_wait_after_attach, tc) | ||||
{ | { | ||||
pid_t child, wpid; | pid_t child, wpid; | ||||
int cpipe[2], status; | int cpipe[2], status; | ||||
char c; | char c; | ||||
if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) | if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) | ||||
atf_tc_skip("https://bugs.freebsd.org/244055"); | atf_tc_skip("https://bugs.freebsd.org/244055"); | ||||
ATF_REQUIRE(pipe(cpipe) == 0); | REQUIRE_EQ(pipe(cpipe), 0); | ||||
ATF_REQUIRE((child = fork()) != -1); | ATF_REQUIRE((child = fork()) != -1); | ||||
if (child == 0) { | if (child == 0) { | ||||
/* Child process. */ | /* Child process. */ | ||||
close(cpipe[0]); | close(cpipe[0]); | ||||
/* Wait for the parent to attach. */ | /* Wait for the parent to attach. */ | ||||
CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == 0); | CHILD_REQUIRE_EQ(0, read(cpipe[1], &c, sizeof(c))); | ||||
_exit(1); | _exit(1); | ||||
} | } | ||||
close(cpipe[1]); | close(cpipe[1]); | ||||
/* Parent process. */ | /* Parent process. */ | ||||
/* Attach to the child process. */ | /* Attach to the child process. */ | ||||
attach_child(child); | attach_child(child); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); | ||||
/* Signal the child to exit. */ | /* Signal the child to exit. */ | ||||
close(cpipe[0]); | close(cpipe[0]); | ||||
/* The second wait() should report the exit status. */ | /* The second wait() should report the exit status. */ | ||||
wpid = waitpid(child, &status, 0); | wpid = waitpid(child, &status, 0); | ||||
ATF_REQUIRE(wpid == child); | REQUIRE_EQ(wpid, child); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
/* The child should no longer exist. */ | /* The child should no longer exist. */ | ||||
wpid = waitpid(child, &status, 0); | wpid = waitpid(child, &status, 0); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that a parent process "sees" the exit of a debugged process only | * Verify that a parent process "sees" the exit of a debugged process only | ||||
* after the debugger has seen it. | * after the debugger has seen it. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_child_debugger); | ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_child_debugger); | ||||
ATF_TC_BODY(ptrace__parent_sees_exit_after_child_debugger, tc) | ATF_TC_BODY(ptrace__parent_sees_exit_after_child_debugger, tc) | ||||
{ | { | ||||
pid_t child, debugger, wpid; | pid_t child, debugger, wpid; | ||||
int cpipe[2], dpipe[2], status; | int cpipe[2], dpipe[2], status; | ||||
char c; | char c; | ||||
if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) | if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) | ||||
atf_tc_skip("https://bugs.freebsd.org/239399"); | atf_tc_skip("https://bugs.freebsd.org/239399"); | ||||
ATF_REQUIRE(pipe(cpipe) == 0); | REQUIRE_EQ(pipe(cpipe), 0); | ||||
ATF_REQUIRE((child = fork()) != -1); | ATF_REQUIRE((child = fork()) != -1); | ||||
if (child == 0) { | if (child == 0) { | ||||
/* Child process. */ | /* Child process. */ | ||||
close(cpipe[0]); | close(cpipe[0]); | ||||
/* Wait for parent to be ready. */ | /* Wait for parent to be ready. */ | ||||
CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c)); | CHILD_REQUIRE_EQ(read(cpipe[1], &c, sizeof(c)), sizeof(c)); | ||||
_exit(1); | _exit(1); | ||||
} | } | ||||
close(cpipe[1]); | close(cpipe[1]); | ||||
ATF_REQUIRE(pipe(dpipe) == 0); | REQUIRE_EQ(pipe(dpipe), 0); | ||||
ATF_REQUIRE((debugger = fork()) != -1); | ATF_REQUIRE((debugger = fork()) != -1); | ||||
if (debugger == 0) { | if (debugger == 0) { | ||||
/* Debugger process. */ | /* Debugger process. */ | ||||
close(dpipe[0]); | close(dpipe[0]); | ||||
CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1); | CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1); | ||||
wpid = waitpid(child, &status, 0); | wpid = waitpid(child, &status, 0); | ||||
CHILD_REQUIRE(wpid == child); | CHILD_REQUIRE_EQ(wpid, child); | ||||
CHILD_REQUIRE(WIFSTOPPED(status)); | CHILD_REQUIRE(WIFSTOPPED(status)); | ||||
CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP); | CHILD_REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); | CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); | ||||
/* Signal parent that debugger is attached. */ | /* Signal parent that debugger is attached. */ | ||||
CHILD_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c)); | CHILD_REQUIRE_EQ(write(dpipe[1], &c, sizeof(c)), sizeof(c)); | ||||
/* Wait for parent's failed wait. */ | /* Wait for parent's failed wait. */ | ||||
CHILD_REQUIRE(read(dpipe[1], &c, sizeof(c)) == 0); | CHILD_REQUIRE_EQ(read(dpipe[1], &c, sizeof(c)), 0); | ||||
wpid = waitpid(child, &status, 0); | wpid = waitpid(child, &status, 0); | ||||
CHILD_REQUIRE(wpid == child); | CHILD_REQUIRE_EQ(wpid, child); | ||||
CHILD_REQUIRE(WIFEXITED(status)); | CHILD_REQUIRE(WIFEXITED(status)); | ||||
CHILD_REQUIRE(WEXITSTATUS(status) == 1); | CHILD_REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
_exit(0); | _exit(0); | ||||
} | } | ||||
close(dpipe[1]); | close(dpipe[1]); | ||||
/* Parent process. */ | /* Parent process. */ | ||||
/* Wait for the debugger to attach to the child. */ | /* Wait for the debugger to attach to the child. */ | ||||
ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c)); | REQUIRE_EQ(read(dpipe[0], &c, sizeof(c)), sizeof(c)); | ||||
/* Release the child. */ | /* Release the child. */ | ||||
ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c)); | REQUIRE_EQ(write(cpipe[0], &c, sizeof(c)), sizeof(c)); | ||||
ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0); | REQUIRE_EQ(read(cpipe[0], &c, sizeof(c)), 0); | ||||
close(cpipe[0]); | close(cpipe[0]); | ||||
wait_for_zombie(child); | wait_for_zombie(child); | ||||
/* | /* | ||||
* This wait should return a pid of 0 to indicate no status to | * This wait should return a pid of 0 to indicate no status to | ||||
* report. The parent should see the child as non-exited | * report. The parent should see the child as non-exited | ||||
* until the debugger sees the exit. | * until the debugger sees the exit. | ||||
*/ | */ | ||||
wpid = waitpid(child, &status, WNOHANG); | wpid = waitpid(child, &status, WNOHANG); | ||||
ATF_REQUIRE(wpid == 0); | REQUIRE_EQ(wpid, 0); | ||||
/* Signal the debugger to wait for the child. */ | /* Signal the debugger to wait for the child. */ | ||||
close(dpipe[0]); | close(dpipe[0]); | ||||
/* Wait for the debugger. */ | /* Wait for the debugger. */ | ||||
wpid = waitpid(debugger, &status, 0); | wpid = waitpid(debugger, &status, 0); | ||||
ATF_REQUIRE(wpid == debugger); | REQUIRE_EQ(wpid, debugger); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 0); | REQUIRE_EQ(WEXITSTATUS(status), 0); | ||||
/* The child process should now be ready. */ | /* The child process should now be ready. */ | ||||
wpid = waitpid(child, &status, WNOHANG); | wpid = waitpid(child, &status, WNOHANG); | ||||
ATF_REQUIRE(wpid == child); | REQUIRE_EQ(wpid, child); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
} | } | ||||
/* | /* | ||||
* Verify that a parent process "sees" the exit of a debugged process | * Verify that a parent process "sees" the exit of a debugged process | ||||
* only after a non-direct-child debugger has seen it. In particular, | * only after a non-direct-child debugger has seen it. In particular, | ||||
* various wait() calls in the parent must avoid failing with ESRCH by | * various wait() calls in the parent must avoid failing with ESRCH by | ||||
* checking the parent's orphan list for the debugee. | * checking the parent's orphan list for the debugee. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_unrelated_debugger); | ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_unrelated_debugger); | ||||
ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc) | ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc) | ||||
{ | { | ||||
pid_t child, debugger, fpid, wpid; | pid_t child, debugger, fpid, wpid; | ||||
int cpipe[2], dpipe[2], status; | int cpipe[2], dpipe[2], status; | ||||
char c; | char c; | ||||
ATF_REQUIRE(pipe(cpipe) == 0); | REQUIRE_EQ(pipe(cpipe), 0); | ||||
ATF_REQUIRE((child = fork()) != -1); | ATF_REQUIRE((child = fork()) != -1); | ||||
if (child == 0) { | if (child == 0) { | ||||
/* Child process. */ | /* Child process. */ | ||||
close(cpipe[0]); | close(cpipe[0]); | ||||
/* Wait for parent to be ready. */ | /* Wait for parent to be ready. */ | ||||
CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c)); | CHILD_REQUIRE_EQ(read(cpipe[1], &c, sizeof(c)), sizeof(c)); | ||||
_exit(1); | _exit(1); | ||||
} | } | ||||
close(cpipe[1]); | close(cpipe[1]); | ||||
ATF_REQUIRE(pipe(dpipe) == 0); | REQUIRE_EQ(pipe(dpipe), 0); | ||||
ATF_REQUIRE((debugger = fork()) != -1); | ATF_REQUIRE((debugger = fork()) != -1); | ||||
if (debugger == 0) { | if (debugger == 0) { | ||||
/* Debugger parent. */ | /* Debugger parent. */ | ||||
/* | /* | ||||
* Fork again and drop the debugger parent so that the | * Fork again and drop the debugger parent so that the | ||||
* debugger is not a child of the main parent. | * debugger is not a child of the main parent. | ||||
*/ | */ | ||||
CHILD_REQUIRE((fpid = fork()) != -1); | CHILD_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid != 0) | if (fpid != 0) | ||||
_exit(2); | _exit(2); | ||||
/* Debugger process. */ | /* Debugger process. */ | ||||
close(dpipe[0]); | close(dpipe[0]); | ||||
CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1); | CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1); | ||||
wpid = waitpid(child, &status, 0); | wpid = waitpid(child, &status, 0); | ||||
CHILD_REQUIRE(wpid == child); | CHILD_REQUIRE_EQ(wpid, child); | ||||
CHILD_REQUIRE(WIFSTOPPED(status)); | CHILD_REQUIRE(WIFSTOPPED(status)); | ||||
CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP); | CHILD_REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); | CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); | ||||
/* Signal parent that debugger is attached. */ | /* Signal parent that debugger is attached. */ | ||||
CHILD_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c)); | CHILD_REQUIRE_EQ(write(dpipe[1], &c, sizeof(c)), sizeof(c)); | ||||
/* Wait for parent's failed wait. */ | /* Wait for parent's failed wait. */ | ||||
CHILD_REQUIRE(read(dpipe[1], &c, sizeof(c)) == sizeof(c)); | CHILD_REQUIRE_EQ(read(dpipe[1], &c, sizeof(c)), sizeof(c)); | ||||
wpid = waitpid(child, &status, 0); | wpid = waitpid(child, &status, 0); | ||||
CHILD_REQUIRE(wpid == child); | CHILD_REQUIRE_EQ(wpid, child); | ||||
CHILD_REQUIRE(WIFEXITED(status)); | CHILD_REQUIRE(WIFEXITED(status)); | ||||
CHILD_REQUIRE(WEXITSTATUS(status) == 1); | CHILD_REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
_exit(0); | _exit(0); | ||||
} | } | ||||
close(dpipe[1]); | close(dpipe[1]); | ||||
/* Parent process. */ | /* Parent process. */ | ||||
/* Wait for the debugger parent process to exit. */ | /* Wait for the debugger parent process to exit. */ | ||||
wpid = waitpid(debugger, &status, 0); | wpid = waitpid(debugger, &status, 0); | ||||
ATF_REQUIRE(wpid == debugger); | REQUIRE_EQ(wpid, debugger); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 2); | REQUIRE_EQ(WEXITSTATUS(status), 2); | ||||
/* A WNOHANG wait here should see the non-exited child. */ | /* A WNOHANG wait here should see the non-exited child. */ | ||||
wpid = waitpid(child, &status, WNOHANG); | wpid = waitpid(child, &status, WNOHANG); | ||||
ATF_REQUIRE(wpid == 0); | REQUIRE_EQ(wpid, 0); | ||||
/* Wait for the debugger to attach to the child. */ | /* Wait for the debugger to attach to the child. */ | ||||
ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c)); | REQUIRE_EQ(read(dpipe[0], &c, sizeof(c)), sizeof(c)); | ||||
/* Release the child. */ | /* Release the child. */ | ||||
ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c)); | REQUIRE_EQ(write(cpipe[0], &c, sizeof(c)), sizeof(c)); | ||||
ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0); | REQUIRE_EQ(read(cpipe[0], &c, sizeof(c)), 0); | ||||
close(cpipe[0]); | close(cpipe[0]); | ||||
wait_for_zombie(child); | wait_for_zombie(child); | ||||
/* | /* | ||||
* This wait should return a pid of 0 to indicate no status to | * This wait should return a pid of 0 to indicate no status to | ||||
* report. The parent should see the child as non-exited | * report. The parent should see the child as non-exited | ||||
* until the debugger sees the exit. | * until the debugger sees the exit. | ||||
*/ | */ | ||||
wpid = waitpid(child, &status, WNOHANG); | wpid = waitpid(child, &status, WNOHANG); | ||||
ATF_REQUIRE(wpid == 0); | REQUIRE_EQ(wpid, 0); | ||||
/* Signal the debugger to wait for the child. */ | /* Signal the debugger to wait for the child. */ | ||||
ATF_REQUIRE(write(dpipe[0], &c, sizeof(c)) == sizeof(c)); | REQUIRE_EQ(write(dpipe[0], &c, sizeof(c)), sizeof(c)); | ||||
/* Wait for the debugger. */ | /* Wait for the debugger. */ | ||||
ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == 0); | REQUIRE_EQ(read(dpipe[0], &c, sizeof(c)), 0); | ||||
close(dpipe[0]); | close(dpipe[0]); | ||||
/* The child process should now be ready. */ | /* The child process should now be ready. */ | ||||
wpid = waitpid(child, &status, WNOHANG); | wpid = waitpid(child, &status, WNOHANG); | ||||
ATF_REQUIRE(wpid == child); | REQUIRE_EQ(wpid, child); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
} | } | ||||
/* | /* | ||||
* Make sure that we can collect the exit status of an orphaned process. | * Make sure that we can collect the exit status of an orphaned process. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__parent_exits_before_child); | ATF_TC_WITHOUT_HEAD(ptrace__parent_exits_before_child); | ||||
ATF_TC_BODY(ptrace__parent_exits_before_child, tc) | ATF_TC_BODY(ptrace__parent_exits_before_child, tc) | ||||
{ | { | ||||
ssize_t n; | ssize_t n; | ||||
int cpipe1[2], cpipe2[2], gcpipe[2], status; | int cpipe1[2], cpipe2[2], gcpipe[2], status; | ||||
pid_t child, gchild; | pid_t child, gchild; | ||||
if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) | if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) | ||||
atf_tc_skip("https://bugs.freebsd.org/244056"); | atf_tc_skip("https://bugs.freebsd.org/244056"); | ||||
ATF_REQUIRE(pipe(cpipe1) == 0); | REQUIRE_EQ(pipe(cpipe1), 0); | ||||
ATF_REQUIRE(pipe(cpipe2) == 0); | REQUIRE_EQ(pipe(cpipe2), 0); | ||||
ATF_REQUIRE(pipe(gcpipe) == 0); | REQUIRE_EQ(pipe(gcpipe), 0); | ||||
ATF_REQUIRE(procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) == 0); | REQUIRE_EQ(procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL), 0); | ||||
ATF_REQUIRE((child = fork()) != -1); | ATF_REQUIRE((child = fork()) != -1); | ||||
if (child == 0) { | if (child == 0) { | ||||
CHILD_REQUIRE((gchild = fork()) != -1); | CHILD_REQUIRE((gchild = fork()) != -1); | ||||
if (gchild == 0) { | if (gchild == 0) { | ||||
status = 1; | status = 1; | ||||
do { | do { | ||||
n = read(gcpipe[0], &status, sizeof(status)); | n = read(gcpipe[0], &status, sizeof(status)); | ||||
} while (n == -1 && errno == EINTR); | } while (n == -1 && errno == EINTR); | ||||
_exit(status); | _exit(status); | ||||
} | } | ||||
CHILD_REQUIRE(write(cpipe1[1], &gchild, sizeof(gchild)) == | CHILD_REQUIRE(write(cpipe1[1], &gchild, sizeof(gchild)) == | ||||
sizeof(gchild)); | sizeof(gchild)); | ||||
CHILD_REQUIRE(read(cpipe2[0], &status, sizeof(status)) == | CHILD_REQUIRE(read(cpipe2[0], &status, sizeof(status)) == | ||||
sizeof(status)); | sizeof(status)); | ||||
_exit(status); | _exit(status); | ||||
} | } | ||||
ATF_REQUIRE(read(cpipe1[0], &gchild, sizeof(gchild)) == sizeof(gchild)); | REQUIRE_EQ(read(cpipe1[0], &gchild, sizeof(gchild)), sizeof(gchild)); | ||||
ATF_REQUIRE(ptrace(PT_ATTACH, gchild, NULL, 0) == 0); | REQUIRE_EQ(ptrace(PT_ATTACH, gchild, NULL, 0), 0); | ||||
status = 0; | status = 0; | ||||
ATF_REQUIRE(write(cpipe2[1], &status, sizeof(status)) == | REQUIRE_EQ(write(cpipe2[1], &status, sizeof(status)), sizeof(status)); | ||||
sizeof(status)); | REQUIRE_EQ(waitpid(child, &status, 0), child); | ||||
ATF_REQUIRE(waitpid(child, &status, 0) == child); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 0); | REQUIRE_EQ(WEXITSTATUS(status), 0); | ||||
status = 0; | status = 0; | ||||
ATF_REQUIRE(write(gcpipe[1], &status, sizeof(status)) == | REQUIRE_EQ(write(gcpipe[1], &status, sizeof(status)), sizeof(status)); | ||||
sizeof(status)); | REQUIRE_EQ(waitpid(gchild, &status, 0), gchild); | ||||
ATF_REQUIRE(waitpid(gchild, &status, 0) == gchild); | |||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(ptrace(PT_DETACH, gchild, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_DETACH, gchild, (caddr_t)1, 0), 0); | ||||
ATF_REQUIRE(waitpid(gchild, &status, 0) == gchild); | REQUIRE_EQ(waitpid(gchild, &status, 0), gchild); | ||||
ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 0); | ATF_REQUIRE(WIFEXITED(status)); | ||||
REQUIRE_EQ(WEXITSTATUS(status), 0); | |||||
ATF_REQUIRE(close(cpipe1[0]) == 0); | REQUIRE_EQ(close(cpipe1[0]), 0); | ||||
ATF_REQUIRE(close(cpipe1[1]) == 0); | REQUIRE_EQ(close(cpipe1[1]), 0); | ||||
ATF_REQUIRE(close(cpipe2[0]) == 0); | REQUIRE_EQ(close(cpipe2[0]), 0); | ||||
ATF_REQUIRE(close(cpipe2[1]) == 0); | REQUIRE_EQ(close(cpipe2[1]), 0); | ||||
ATF_REQUIRE(close(gcpipe[0]) == 0); | REQUIRE_EQ(close(gcpipe[0]), 0); | ||||
ATF_REQUIRE(close(gcpipe[1]) == 0); | REQUIRE_EQ(close(gcpipe[1]), 0); | ||||
} | } | ||||
/* | /* | ||||
* The parent process should always act the same regardless of how the | * The parent process should always act the same regardless of how the | ||||
* debugger is attached to it. | * debugger is attached to it. | ||||
*/ | */ | ||||
static __dead2 void | static __dead2 void | ||||
follow_fork_parent(bool use_vfork) | follow_fork_parent(bool use_vfork) | ||||
{ | { | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int status; | int status; | ||||
if (use_vfork) | if (use_vfork) | ||||
CHILD_REQUIRE((fpid = vfork()) != -1); | CHILD_REQUIRE((fpid = vfork()) != -1); | ||||
else | else | ||||
CHILD_REQUIRE((fpid = fork()) != -1); | CHILD_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) | if (fpid == 0) | ||||
/* Child */ | /* Child */ | ||||
_exit(2); | _exit(2); | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
CHILD_REQUIRE(wpid == fpid); | CHILD_REQUIRE_EQ(wpid, fpid); | ||||
CHILD_REQUIRE(WIFEXITED(status)); | CHILD_REQUIRE(WIFEXITED(status)); | ||||
CHILD_REQUIRE(WEXITSTATUS(status) == 2); | CHILD_REQUIRE_EQ(WEXITSTATUS(status), 2); | ||||
_exit(1); | _exit(1); | ||||
} | } | ||||
/* | /* | ||||
* Helper routine for follow fork tests. This waits for two stops | * Helper routine for follow fork tests. This waits for two stops | ||||
* that report both "sides" of a fork. It returns the pid of the new | * that report both "sides" of a fork. It returns the pid of the new | ||||
* child process. | * child process. | ||||
Show All 23 Lines | for (i = 0; i < 2; i++) { | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ||||
sizeof(pl)) != -1); | sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & (PL_FLAG_FORKED | PL_FLAG_CHILD)) != | ATF_REQUIRE((pl.pl_flags & (PL_FLAG_FORKED | PL_FLAG_CHILD)) != | ||||
0); | 0); | ||||
ATF_REQUIRE((pl.pl_flags & (PL_FLAG_FORKED | PL_FLAG_CHILD)) != | ATF_REQUIRE((pl.pl_flags & (PL_FLAG_FORKED | PL_FLAG_CHILD)) != | ||||
(PL_FLAG_FORKED | PL_FLAG_CHILD)); | (PL_FLAG_FORKED | PL_FLAG_CHILD)); | ||||
if (pl.pl_flags & PL_FLAG_CHILD) { | if (pl.pl_flags & PL_FLAG_CHILD) { | ||||
ATF_REQUIRE(wpid != parent); | ATF_REQUIRE(wpid != parent); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(!fork_reported[1]); | ATF_REQUIRE(!fork_reported[1]); | ||||
if (child == -1) | if (child == -1) | ||||
child = wpid; | child = wpid; | ||||
else | else | ||||
ATF_REQUIRE(child == wpid); | REQUIRE_EQ(child, wpid); | ||||
if (ppl != NULL) | if (ppl != NULL) | ||||
ppl[1] = pl; | ppl[1] = pl; | ||||
fork_reported[1] = true; | fork_reported[1] = true; | ||||
} else { | } else { | ||||
ATF_REQUIRE(wpid == parent); | REQUIRE_EQ(wpid, parent); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(!fork_reported[0]); | ATF_REQUIRE(!fork_reported[0]); | ||||
if (child == -1) | if (child == -1) | ||||
child = pl.pl_child_pid; | child = pl.pl_child_pid; | ||||
else | else | ||||
ATF_REQUIRE(child == pl.pl_child_pid); | REQUIRE_EQ(child, pl.pl_child_pid); | ||||
if (ppl != NULL) | if (ppl != NULL) | ||||
ppl[0] = pl; | ppl[0] = pl; | ||||
fork_reported[0] = true; | fork_reported[0] = true; | ||||
} | } | ||||
} | } | ||||
return (child); | return (child); | ||||
} | } | ||||
Show All 15 Lines | if (fpid == 0) { | ||||
follow_fork_parent(false); | follow_fork_parent(false); | ||||
} | } | ||||
/* Parent process. */ | /* Parent process. */ | ||||
children[0] = fpid; | children[0] = fpid; | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(children[0], &status, 0); | wpid = waitpid(children[0], &status, 0); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
children[1] = handle_fork_events(children[0], NULL); | children[1] = handle_fork_events(children[0], NULL); | ||||
ATF_REQUIRE(children[1] > 0); | ATF_REQUIRE(children[1] > 0); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); | ||||
/* | /* | ||||
* The child can't exit until the grandchild reports status, so the | * The child can't exit until the grandchild reports status, so the | ||||
* grandchild should report its exit first to the debugger. | * grandchild should report its exit first to the debugger. | ||||
*/ | */ | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[1]); | REQUIRE_EQ(wpid, children[1]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 2); | REQUIRE_EQ(WEXITSTATUS(status), 2); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that a new child process is stopped after a followed fork | * Verify that a new child process is stopped after a followed fork | ||||
* and that the traced parent sees the exit of the child when the new | * and that the traced parent sees the exit of the child when the new | ||||
* child process is detached after it reports its fork. | * child process is detached after it reports its fork. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached); | ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached); | ||||
ATF_TC_BODY(ptrace__follow_fork_child_detached, tc) | ATF_TC_BODY(ptrace__follow_fork_child_detached, tc) | ||||
{ | { | ||||
pid_t children[2], fpid, wpid; | pid_t children[2], fpid, wpid; | ||||
int status; | int status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
follow_fork_parent(false); | follow_fork_parent(false); | ||||
} | } | ||||
/* Parent process. */ | /* Parent process. */ | ||||
children[0] = fpid; | children[0] = fpid; | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(children[0], &status, 0); | wpid = waitpid(children[0], &status, 0); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
children[1] = handle_fork_events(children[0], NULL); | children[1] = handle_fork_events(children[0], NULL); | ||||
ATF_REQUIRE(children[1] > 0); | ATF_REQUIRE(children[1] > 0); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
ATF_REQUIRE(ptrace(PT_DETACH, children[1], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_DETACH, children[1], (caddr_t)1, 0) != -1); | ||||
/* | /* | ||||
* Should not see any status from the grandchild now, only the | * Should not see any status from the grandchild now, only the | ||||
* child. | * child. | ||||
*/ | */ | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that a new child process is stopped after a followed fork | * Verify that a new child process is stopped after a followed fork | ||||
* and that the traced parent sees the exit of the child when the | * and that the traced parent sees the exit of the child when the | ||||
* traced parent is detached after the fork. | * traced parent is detached after the fork. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_parent_detached); | ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_parent_detached); | ||||
ATF_TC_BODY(ptrace__follow_fork_parent_detached, tc) | ATF_TC_BODY(ptrace__follow_fork_parent_detached, tc) | ||||
{ | { | ||||
pid_t children[2], fpid, wpid; | pid_t children[2], fpid, wpid; | ||||
int status; | int status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
follow_fork_parent(false); | follow_fork_parent(false); | ||||
} | } | ||||
/* Parent process. */ | /* Parent process. */ | ||||
children[0] = fpid; | children[0] = fpid; | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(children[0], &status, 0); | wpid = waitpid(children[0], &status, 0); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
children[1] = handle_fork_events(children[0], NULL); | children[1] = handle_fork_events(children[0], NULL); | ||||
ATF_REQUIRE(children[1] > 0); | ATF_REQUIRE(children[1] > 0); | ||||
ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); | ||||
/* | /* | ||||
* The child can't exit until the grandchild reports status, so the | * The child can't exit until the grandchild reports status, so the | ||||
* grandchild should report its exit first to the debugger. | * grandchild should report its exit first to the debugger. | ||||
* | * | ||||
* Even though the child process is detached, it is still a | * Even though the child process is detached, it is still a | ||||
* child of the debugger, so it will still report it's exit | * child of the debugger, so it will still report it's exit | ||||
* after the grandchild. | * after the grandchild. | ||||
*/ | */ | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[1]); | REQUIRE_EQ(wpid, children[1]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 2); | REQUIRE_EQ(WEXITSTATUS(status), 2); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
static void | static void | ||||
attach_fork_parent(int cpipe[2]) | attach_fork_parent(int cpipe[2]) | ||||
{ | { | ||||
pid_t fpid; | pid_t fpid; | ||||
close(cpipe[0]); | close(cpipe[0]); | ||||
/* Double-fork to disassociate from the debugger. */ | /* Double-fork to disassociate from the debugger. */ | ||||
CHILD_REQUIRE((fpid = fork()) != -1); | CHILD_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid != 0) | if (fpid != 0) | ||||
_exit(3); | _exit(3); | ||||
/* Send the pid of the disassociated child to the debugger. */ | /* Send the pid of the disassociated child to the debugger. */ | ||||
fpid = getpid(); | fpid = getpid(); | ||||
CHILD_REQUIRE(write(cpipe[1], &fpid, sizeof(fpid)) == sizeof(fpid)); | CHILD_REQUIRE_EQ(write(cpipe[1], &fpid, sizeof(fpid)), sizeof(fpid)); | ||||
/* Wait for the debugger to attach. */ | /* Wait for the debugger to attach. */ | ||||
CHILD_REQUIRE(read(cpipe[1], &fpid, sizeof(fpid)) == 0); | CHILD_REQUIRE_EQ(read(cpipe[1], &fpid, sizeof(fpid)), 0); | ||||
} | } | ||||
/* | /* | ||||
* Verify that a new child process is stopped after a followed fork and | * Verify that a new child process is stopped after a followed fork and | ||||
* that the traced parent sees the exit of the child after the debugger | * that the traced parent sees the exit of the child after the debugger | ||||
* when both processes remain attached to the debugger. In this test | * when both processes remain attached to the debugger. In this test | ||||
* the parent that forks is not a direct child of the debugger. | * the parent that forks is not a direct child of the debugger. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_both_attached_unrelated_debugger); | ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_both_attached_unrelated_debugger); | ||||
ATF_TC_BODY(ptrace__follow_fork_both_attached_unrelated_debugger, tc) | ATF_TC_BODY(ptrace__follow_fork_both_attached_unrelated_debugger, tc) | ||||
{ | { | ||||
pid_t children[2], fpid, wpid; | pid_t children[2], fpid, wpid; | ||||
int cpipe[2], status; | int cpipe[2], status; | ||||
if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) | if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) | ||||
atf_tc_skip("https://bugs.freebsd.org/239397"); | atf_tc_skip("https://bugs.freebsd.org/239397"); | ||||
ATF_REQUIRE(pipe(cpipe) == 0); | REQUIRE_EQ(pipe(cpipe), 0); | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
attach_fork_parent(cpipe); | attach_fork_parent(cpipe); | ||||
follow_fork_parent(false); | follow_fork_parent(false); | ||||
} | } | ||||
/* Parent process. */ | /* Parent process. */ | ||||
close(cpipe[1]); | close(cpipe[1]); | ||||
/* Wait for the direct child to exit. */ | /* Wait for the direct child to exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 3); | REQUIRE_EQ(WEXITSTATUS(status), 3); | ||||
/* Read the pid of the fork parent. */ | /* Read the pid of the fork parent. */ | ||||
ATF_REQUIRE(read(cpipe[0], &children[0], sizeof(children[0])) == | REQUIRE_EQ(read(cpipe[0], &children[0], sizeof(children[0])), | ||||
sizeof(children[0])); | sizeof(children[0])); | ||||
/* Attach to the fork parent. */ | /* Attach to the fork parent. */ | ||||
attach_child(children[0]); | attach_child(children[0]); | ||||
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ||||
/* Continue the fork parent ignoring the SIGSTOP. */ | /* Continue the fork parent ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
/* Signal the fork parent to continue. */ | /* Signal the fork parent to continue. */ | ||||
close(cpipe[0]); | close(cpipe[0]); | ||||
children[1] = handle_fork_events(children[0], NULL); | children[1] = handle_fork_events(children[0], NULL); | ||||
ATF_REQUIRE(children[1] > 0); | ATF_REQUIRE(children[1] > 0); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); | ||||
/* | /* | ||||
* The fork parent can't exit until the child reports status, | * The fork parent can't exit until the child reports status, | ||||
* so the child should report its exit first to the debugger. | * so the child should report its exit first to the debugger. | ||||
*/ | */ | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[1]); | REQUIRE_EQ(wpid, children[1]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 2); | REQUIRE_EQ(WEXITSTATUS(status), 2); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that a new child process is stopped after a followed fork | * Verify that a new child process is stopped after a followed fork | ||||
* and that the traced parent sees the exit of the child when the new | * and that the traced parent sees the exit of the child when the new | ||||
* child process is detached after it reports its fork. In this test | * child process is detached after it reports its fork. In this test | ||||
* the parent that forks is not a direct child of the debugger. | * the parent that forks is not a direct child of the debugger. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached_unrelated_debugger); | ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached_unrelated_debugger); | ||||
ATF_TC_BODY(ptrace__follow_fork_child_detached_unrelated_debugger, tc) | ATF_TC_BODY(ptrace__follow_fork_child_detached_unrelated_debugger, tc) | ||||
{ | { | ||||
pid_t children[2], fpid, wpid; | pid_t children[2], fpid, wpid; | ||||
int cpipe[2], status; | int cpipe[2], status; | ||||
if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) | if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) | ||||
atf_tc_skip("https://bugs.freebsd.org/239292"); | atf_tc_skip("https://bugs.freebsd.org/239292"); | ||||
ATF_REQUIRE(pipe(cpipe) == 0); | REQUIRE_EQ(pipe(cpipe), 0); | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
attach_fork_parent(cpipe); | attach_fork_parent(cpipe); | ||||
follow_fork_parent(false); | follow_fork_parent(false); | ||||
} | } | ||||
/* Parent process. */ | /* Parent process. */ | ||||
close(cpipe[1]); | close(cpipe[1]); | ||||
/* Wait for the direct child to exit. */ | /* Wait for the direct child to exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 3); | REQUIRE_EQ(WEXITSTATUS(status), 3); | ||||
/* Read the pid of the fork parent. */ | /* Read the pid of the fork parent. */ | ||||
ATF_REQUIRE(read(cpipe[0], &children[0], sizeof(children[0])) == | REQUIRE_EQ(read(cpipe[0], &children[0], sizeof(children[0])), | ||||
sizeof(children[0])); | sizeof(children[0])); | ||||
/* Attach to the fork parent. */ | /* Attach to the fork parent. */ | ||||
attach_child(children[0]); | attach_child(children[0]); | ||||
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ||||
/* Continue the fork parent ignoring the SIGSTOP. */ | /* Continue the fork parent ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
/* Signal the fork parent to continue. */ | /* Signal the fork parent to continue. */ | ||||
close(cpipe[0]); | close(cpipe[0]); | ||||
children[1] = handle_fork_events(children[0], NULL); | children[1] = handle_fork_events(children[0], NULL); | ||||
ATF_REQUIRE(children[1] > 0); | ATF_REQUIRE(children[1] > 0); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
ATF_REQUIRE(ptrace(PT_DETACH, children[1], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_DETACH, children[1], (caddr_t)1, 0) != -1); | ||||
/* | /* | ||||
* Should not see any status from the child now, only the fork | * Should not see any status from the child now, only the fork | ||||
* parent. | * parent. | ||||
*/ | */ | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that a new child process is stopped after a followed fork | * Verify that a new child process is stopped after a followed fork | ||||
* and that the traced parent sees the exit of the child when the | * and that the traced parent sees the exit of the child when the | ||||
* traced parent is detached after the fork. In this test the parent | * traced parent is detached after the fork. In this test the parent | ||||
* that forks is not a direct child of the debugger. | * that forks is not a direct child of the debugger. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_parent_detached_unrelated_debugger); | ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_parent_detached_unrelated_debugger); | ||||
ATF_TC_BODY(ptrace__follow_fork_parent_detached_unrelated_debugger, tc) | ATF_TC_BODY(ptrace__follow_fork_parent_detached_unrelated_debugger, tc) | ||||
{ | { | ||||
pid_t children[2], fpid, wpid; | pid_t children[2], fpid, wpid; | ||||
int cpipe[2], status; | int cpipe[2], status; | ||||
if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) | if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) | ||||
atf_tc_skip("https://bugs.freebsd.org/239425"); | atf_tc_skip("https://bugs.freebsd.org/239425"); | ||||
ATF_REQUIRE(pipe(cpipe) == 0); | REQUIRE_EQ(pipe(cpipe), 0); | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
attach_fork_parent(cpipe); | attach_fork_parent(cpipe); | ||||
follow_fork_parent(false); | follow_fork_parent(false); | ||||
} | } | ||||
/* Parent process. */ | /* Parent process. */ | ||||
close(cpipe[1]); | close(cpipe[1]); | ||||
/* Wait for the direct child to exit. */ | /* Wait for the direct child to exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 3); | REQUIRE_EQ(WEXITSTATUS(status), 3); | ||||
/* Read the pid of the fork parent. */ | /* Read the pid of the fork parent. */ | ||||
ATF_REQUIRE(read(cpipe[0], &children[0], sizeof(children[0])) == | REQUIRE_EQ(read(cpipe[0], &children[0], sizeof(children[0])), | ||||
sizeof(children[0])); | sizeof(children[0])); | ||||
/* Attach to the fork parent. */ | /* Attach to the fork parent. */ | ||||
attach_child(children[0]); | attach_child(children[0]); | ||||
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ||||
/* Continue the fork parent ignoring the SIGSTOP. */ | /* Continue the fork parent ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
/* Signal the fork parent to continue. */ | /* Signal the fork parent to continue. */ | ||||
close(cpipe[0]); | close(cpipe[0]); | ||||
children[1] = handle_fork_events(children[0], NULL); | children[1] = handle_fork_events(children[0], NULL); | ||||
ATF_REQUIRE(children[1] > 0); | ATF_REQUIRE(children[1] > 0); | ||||
ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); | ||||
/* | /* | ||||
* Should not see any status from the fork parent now, only | * Should not see any status from the fork parent now, only | ||||
* the child. | * the child. | ||||
*/ | */ | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[1]); | REQUIRE_EQ(wpid, children[1]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 2); | REQUIRE_EQ(WEXITSTATUS(status), 2); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that a child process does not see an unrelated debugger as its | * Verify that a child process does not see an unrelated debugger as its | ||||
* parent but sees its original parent process. | * parent but sees its original parent process. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__getppid); | ATF_TC_WITHOUT_HEAD(ptrace__getppid); | ||||
ATF_TC_BODY(ptrace__getppid, tc) | ATF_TC_BODY(ptrace__getppid, tc) | ||||
{ | { | ||||
pid_t child, debugger, ppid, wpid; | pid_t child, debugger, ppid, wpid; | ||||
int cpipe[2], dpipe[2], status; | int cpipe[2], dpipe[2], status; | ||||
char c; | char c; | ||||
if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) | if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false)) | ||||
atf_tc_skip("https://bugs.freebsd.org/240510"); | atf_tc_skip("https://bugs.freebsd.org/240510"); | ||||
REQUIRE_EQ(pipe(cpipe), 0); | |||||
ATF_REQUIRE(pipe(cpipe) == 0); | |||||
ATF_REQUIRE((child = fork()) != -1); | ATF_REQUIRE((child = fork()) != -1); | ||||
if (child == 0) { | if (child == 0) { | ||||
/* Child process. */ | /* Child process. */ | ||||
close(cpipe[0]); | close(cpipe[0]); | ||||
/* Wait for parent to be ready. */ | /* Wait for parent to be ready. */ | ||||
CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c)); | CHILD_REQUIRE_EQ(read(cpipe[1], &c, sizeof(c)), sizeof(c)); | ||||
/* Report the parent PID to the parent. */ | /* Report the parent PID to the parent. */ | ||||
ppid = getppid(); | ppid = getppid(); | ||||
CHILD_REQUIRE(write(cpipe[1], &ppid, sizeof(ppid)) == | CHILD_REQUIRE(write(cpipe[1], &ppid, sizeof(ppid)) == | ||||
sizeof(ppid)); | sizeof(ppid)); | ||||
_exit(1); | _exit(1); | ||||
} | } | ||||
close(cpipe[1]); | close(cpipe[1]); | ||||
ATF_REQUIRE(pipe(dpipe) == 0); | REQUIRE_EQ(pipe(dpipe), 0); | ||||
ATF_REQUIRE((debugger = fork()) != -1); | ATF_REQUIRE((debugger = fork()) != -1); | ||||
if (debugger == 0) { | if (debugger == 0) { | ||||
/* Debugger process. */ | /* Debugger process. */ | ||||
close(dpipe[0]); | close(dpipe[0]); | ||||
CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1); | CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1); | ||||
wpid = waitpid(child, &status, 0); | wpid = waitpid(child, &status, 0); | ||||
CHILD_REQUIRE(wpid == child); | CHILD_REQUIRE_EQ(wpid, child); | ||||
CHILD_REQUIRE(WIFSTOPPED(status)); | CHILD_REQUIRE(WIFSTOPPED(status)); | ||||
CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP); | CHILD_REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); | CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); | ||||
/* Signal parent that debugger is attached. */ | /* Signal parent that debugger is attached. */ | ||||
CHILD_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c)); | CHILD_REQUIRE_EQ(write(dpipe[1], &c, sizeof(c)), sizeof(c)); | ||||
/* Wait for traced child to exit. */ | /* Wait for traced child to exit. */ | ||||
wpid = waitpid(child, &status, 0); | wpid = waitpid(child, &status, 0); | ||||
CHILD_REQUIRE(wpid == child); | CHILD_REQUIRE_EQ(wpid, child); | ||||
CHILD_REQUIRE(WIFEXITED(status)); | CHILD_REQUIRE(WIFEXITED(status)); | ||||
CHILD_REQUIRE(WEXITSTATUS(status) == 1); | CHILD_REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
_exit(0); | _exit(0); | ||||
} | } | ||||
close(dpipe[1]); | close(dpipe[1]); | ||||
/* Parent process. */ | /* Parent process. */ | ||||
/* Wait for the debugger to attach to the child. */ | /* Wait for the debugger to attach to the child. */ | ||||
ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c)); | REQUIRE_EQ(read(dpipe[0], &c, sizeof(c)), sizeof(c)); | ||||
/* Release the child. */ | /* Release the child. */ | ||||
ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c)); | REQUIRE_EQ(write(cpipe[0], &c, sizeof(c)), sizeof(c)); | ||||
/* Read the parent PID from the child. */ | /* Read the parent PID from the child. */ | ||||
ATF_REQUIRE(read(cpipe[0], &ppid, sizeof(ppid)) == sizeof(ppid)); | REQUIRE_EQ(read(cpipe[0], &ppid, sizeof(ppid)), sizeof(ppid)); | ||||
close(cpipe[0]); | close(cpipe[0]); | ||||
ATF_REQUIRE(ppid == getpid()); | REQUIRE_EQ(ppid, getpid()); | ||||
/* Wait for the debugger. */ | /* Wait for the debugger. */ | ||||
wpid = waitpid(debugger, &status, 0); | wpid = waitpid(debugger, &status, 0); | ||||
ATF_REQUIRE(wpid == debugger); | REQUIRE_EQ(wpid, debugger); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 0); | REQUIRE_EQ(WEXITSTATUS(status), 0); | ||||
/* The child process should now be ready. */ | /* The child process should now be ready. */ | ||||
wpid = waitpid(child, &status, WNOHANG); | wpid = waitpid(child, &status, WNOHANG); | ||||
ATF_REQUIRE(wpid == child); | REQUIRE_EQ(wpid, child); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
} | } | ||||
/* | /* | ||||
* Verify that pl_syscall_code in struct ptrace_lwpinfo for a new | * Verify that pl_syscall_code in struct ptrace_lwpinfo for a new | ||||
* child process created via fork() reports the correct value. | * child process created via fork() reports the correct value. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_fork); | ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_fork); | ||||
ATF_TC_BODY(ptrace__new_child_pl_syscall_code_fork, tc) | ATF_TC_BODY(ptrace__new_child_pl_syscall_code_fork, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl[2]; | struct ptrace_lwpinfo pl[2]; | ||||
pid_t children[2], fpid, wpid; | pid_t children[2], fpid, wpid; | ||||
int status; | int status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
follow_fork_parent(false); | follow_fork_parent(false); | ||||
} | } | ||||
/* Parent process. */ | /* Parent process. */ | ||||
children[0] = fpid; | children[0] = fpid; | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(children[0], &status, 0); | wpid = waitpid(children[0], &status, 0); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
/* Wait for both halves of the fork event to get reported. */ | /* Wait for both halves of the fork event to get reported. */ | ||||
children[1] = handle_fork_events(children[0], pl); | children[1] = handle_fork_events(children[0], pl); | ||||
ATF_REQUIRE(children[1] > 0); | ATF_REQUIRE(children[1] > 0); | ||||
ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_SCX) != 0); | ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_SCX) != 0); | ||||
ATF_REQUIRE((pl[1].pl_flags & PL_FLAG_SCX) != 0); | ATF_REQUIRE((pl[1].pl_flags & PL_FLAG_SCX) != 0); | ||||
ATF_REQUIRE(pl[0].pl_syscall_code == SYS_fork); | REQUIRE_EQ(pl[0].pl_syscall_code, SYS_fork); | ||||
ATF_REQUIRE(pl[0].pl_syscall_code == pl[1].pl_syscall_code); | REQUIRE_EQ(pl[0].pl_syscall_code, pl[1].pl_syscall_code); | ||||
ATF_REQUIRE(pl[0].pl_syscall_narg == pl[1].pl_syscall_narg); | REQUIRE_EQ(pl[0].pl_syscall_narg, pl[1].pl_syscall_narg); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); | ||||
/* | /* | ||||
* The child can't exit until the grandchild reports status, so the | * The child can't exit until the grandchild reports status, so the | ||||
* grandchild should report its exit first to the debugger. | * grandchild should report its exit first to the debugger. | ||||
*/ | */ | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[1]); | REQUIRE_EQ(wpid, children[1]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 2); | REQUIRE_EQ(WEXITSTATUS(status), 2); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that pl_syscall_code in struct ptrace_lwpinfo for a new | * Verify that pl_syscall_code in struct ptrace_lwpinfo for a new | ||||
* child process created via vfork() reports the correct value. | * child process created via vfork() reports the correct value. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_vfork); | ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_vfork); | ||||
ATF_TC_BODY(ptrace__new_child_pl_syscall_code_vfork, tc) | ATF_TC_BODY(ptrace__new_child_pl_syscall_code_vfork, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl[2]; | struct ptrace_lwpinfo pl[2]; | ||||
pid_t children[2], fpid, wpid; | pid_t children[2], fpid, wpid; | ||||
int status; | int status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
follow_fork_parent(true); | follow_fork_parent(true); | ||||
} | } | ||||
/* Parent process. */ | /* Parent process. */ | ||||
children[0] = fpid; | children[0] = fpid; | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(children[0], &status, 0); | wpid = waitpid(children[0], &status, 0); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
/* Wait for both halves of the fork event to get reported. */ | /* Wait for both halves of the fork event to get reported. */ | ||||
children[1] = handle_fork_events(children[0], pl); | children[1] = handle_fork_events(children[0], pl); | ||||
ATF_REQUIRE(children[1] > 0); | ATF_REQUIRE(children[1] > 0); | ||||
ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_SCX) != 0); | ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_SCX) != 0); | ||||
ATF_REQUIRE((pl[1].pl_flags & PL_FLAG_SCX) != 0); | ATF_REQUIRE((pl[1].pl_flags & PL_FLAG_SCX) != 0); | ||||
ATF_REQUIRE(pl[0].pl_syscall_code == SYS_vfork); | REQUIRE_EQ(pl[0].pl_syscall_code, SYS_vfork); | ||||
ATF_REQUIRE(pl[0].pl_syscall_code == pl[1].pl_syscall_code); | REQUIRE_EQ(pl[0].pl_syscall_code, pl[1].pl_syscall_code); | ||||
ATF_REQUIRE(pl[0].pl_syscall_narg == pl[1].pl_syscall_narg); | REQUIRE_EQ(pl[0].pl_syscall_narg, pl[1].pl_syscall_narg); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); | ||||
/* | /* | ||||
* The child can't exit until the grandchild reports status, so the | * The child can't exit until the grandchild reports status, so the | ||||
* grandchild should report its exit first to the debugger. | * grandchild should report its exit first to the debugger. | ||||
*/ | */ | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[1]); | REQUIRE_EQ(wpid, children[1]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 2); | REQUIRE_EQ(WEXITSTATUS(status), 2); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
static void * | static void * | ||||
simple_thread(void *arg __unused) | simple_thread(void *arg __unused) | ||||
{ | { | ||||
pthread_exit(NULL); | pthread_exit(NULL); | ||||
} | } | ||||
static __dead2 void | static __dead2 void | ||||
simple_thread_main(void) | simple_thread_main(void) | ||||
{ | { | ||||
pthread_t thread; | pthread_t thread; | ||||
CHILD_REQUIRE(pthread_create(&thread, NULL, simple_thread, NULL) == 0); | CHILD_REQUIRE_EQ(pthread_create(&thread, NULL, simple_thread, NULL), 0); | ||||
CHILD_REQUIRE(pthread_join(thread, NULL) == 0); | CHILD_REQUIRE_EQ(pthread_join(thread, NULL), 0); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* | /* | ||||
* Verify that pl_syscall_code in struct ptrace_lwpinfo for a new | * Verify that pl_syscall_code in struct ptrace_lwpinfo for a new | ||||
* thread reports the correct value. | * thread reports the correct value. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_thread); | ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_thread); | ||||
ATF_TC_BODY(ptrace__new_child_pl_syscall_code_thread, tc) | ATF_TC_BODY(ptrace__new_child_pl_syscall_code_thread, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
lwpid_t mainlwp; | lwpid_t mainlwp; | ||||
int status; | int status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
simple_thread_main(); | simple_thread_main(); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ||||
sizeof(pl)) != -1); | sizeof(pl)) != -1); | ||||
mainlwp = pl.pl_lwpid; | mainlwp = pl.pl_lwpid; | ||||
/* | /* | ||||
* Continue the child ignoring the SIGSTOP and tracing all | * Continue the child ignoring the SIGSTOP and tracing all | ||||
* system call exits. | * system call exits. | ||||
*/ | */ | ||||
ATF_REQUIRE(ptrace(PT_TO_SCX, fpid, (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_TO_SCX, fpid, (caddr_t)1, 0) != -1); | ||||
/* | /* | ||||
* Wait for the new thread to arrive. pthread_create() might | * Wait for the new thread to arrive. pthread_create() might | ||||
* invoke any number of system calls. For now we just wait | * invoke any number of system calls. For now we just wait | ||||
* for the new thread to arrive and make sure it reports a | * for the new thread to arrive and make sure it reports a | ||||
* valid system call code. If ptrace grows thread event | * valid system call code. If ptrace grows thread event | ||||
* reporting then this test can be made more precise. | * reporting then this test can be made more precise. | ||||
*/ | */ | ||||
for (;;) { | for (;;) { | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ||||
sizeof(pl)) != -1); | sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & PL_FLAG_SCX) != 0); | ATF_REQUIRE((pl.pl_flags & PL_FLAG_SCX) != 0); | ||||
ATF_REQUIRE(pl.pl_syscall_code != 0); | ATF_REQUIRE(pl.pl_syscall_code != 0); | ||||
if (pl.pl_lwpid != mainlwp) | if (pl.pl_lwpid != mainlwp) | ||||
/* New thread seen. */ | /* New thread seen. */ | ||||
break; | break; | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
} | } | ||||
/* Wait for the child to exit. */ | /* Wait for the child to exit. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
for (;;) { | for (;;) { | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
if (WIFEXITED(status)) | if (WIFEXITED(status)) | ||||
break; | break; | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
} | } | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that the expected LWP events are reported for a child thread. | * Verify that the expected LWP events are reported for a child thread. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__lwp_events); | ATF_TC_WITHOUT_HEAD(ptrace__lwp_events); | ||||
ATF_TC_BODY(ptrace__lwp_events, tc) | ATF_TC_BODY(ptrace__lwp_events, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
lwpid_t lwps[2]; | lwpid_t lwps[2]; | ||||
int status; | int status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
simple_thread_main(); | simple_thread_main(); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ||||
sizeof(pl)) != -1); | sizeof(pl)) != -1); | ||||
lwps[0] = pl.pl_lwpid; | lwps[0] = pl.pl_lwpid; | ||||
ATF_REQUIRE(ptrace(PT_LWP_EVENTS, wpid, NULL, 1) == 0); | REQUIRE_EQ(ptrace(PT_LWP_EVENTS, wpid, NULL, 1), 0); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The first event should be for the child thread's birth. */ | /* The first event should be for the child thread's birth. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)) == | REQUIRE_EQ((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)), | ||||
(PL_FLAG_BORN | PL_FLAG_SCX)); | (PL_FLAG_BORN | PL_FLAG_SCX)); | ||||
ATF_REQUIRE(pl.pl_lwpid != lwps[0]); | ATF_REQUIRE(pl.pl_lwpid != lwps[0]); | ||||
lwps[1] = pl.pl_lwpid; | lwps[1] = pl.pl_lwpid; | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The next event should be for the child thread's death. */ | /* The next event should be for the child thread's death. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXITED | PL_FLAG_SCE)) == | REQUIRE_EQ((pl.pl_flags & (PL_FLAG_EXITED | PL_FLAG_SCE)), | ||||
(PL_FLAG_EXITED | PL_FLAG_SCE)); | (PL_FLAG_EXITED | PL_FLAG_SCE)); | ||||
ATF_REQUIRE(pl.pl_lwpid == lwps[1]); | REQUIRE_EQ(pl.pl_lwpid, lwps[1]); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The last event should be for the child process's exit. */ | /* The last event should be for the child process's exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
static void * | static void * | ||||
exec_thread(void *arg __unused) | exec_thread(void *arg __unused) | ||||
{ | { | ||||
execl("/usr/bin/true", "true", NULL); | execl("/usr/bin/true", "true", NULL); | ||||
exit(127); | exit(127); | ||||
} | } | ||||
static __dead2 void | static __dead2 void | ||||
exec_thread_main(void) | exec_thread_main(void) | ||||
{ | { | ||||
pthread_t thread; | pthread_t thread; | ||||
CHILD_REQUIRE(pthread_create(&thread, NULL, exec_thread, NULL) == 0); | CHILD_REQUIRE_EQ(pthread_create(&thread, NULL, exec_thread, NULL), 0); | ||||
for (;;) | for (;;) | ||||
sleep(60); | sleep(60); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* | /* | ||||
* Verify that the expected LWP events are reported for a multithreaded | * Verify that the expected LWP events are reported for a multithreaded | ||||
* process that calls execve(2). | * process that calls execve(2). | ||||
Show All 9 Lines | ATF_TC_BODY(ptrace__lwp_events_exec, tc) | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
exec_thread_main(); | exec_thread_main(); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ||||
sizeof(pl)) != -1); | sizeof(pl)) != -1); | ||||
lwps[0] = pl.pl_lwpid; | lwps[0] = pl.pl_lwpid; | ||||
ATF_REQUIRE(ptrace(PT_LWP_EVENTS, wpid, NULL, 1) == 0); | REQUIRE_EQ(ptrace(PT_LWP_EVENTS, wpid, NULL, 1), 0); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The first event should be for the child thread's birth. */ | /* The first event should be for the child thread's birth. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)) == | REQUIRE_EQ((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)), | ||||
(PL_FLAG_BORN | PL_FLAG_SCX)); | (PL_FLAG_BORN | PL_FLAG_SCX)); | ||||
ATF_REQUIRE(pl.pl_lwpid != lwps[0]); | ATF_REQUIRE(pl.pl_lwpid != lwps[0]); | ||||
lwps[1] = pl.pl_lwpid; | lwps[1] = pl.pl_lwpid; | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* | /* | ||||
* The next event should be for the main thread's death due to | * The next event should be for the main thread's death due to | ||||
* single threading from execve(). | * single threading from execve(). | ||||
*/ | */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXITED | PL_FLAG_SCE)) == | REQUIRE_EQ((pl.pl_flags & (PL_FLAG_EXITED | PL_FLAG_SCE)), | ||||
(PL_FLAG_EXITED)); | (PL_FLAG_EXITED)); | ||||
ATF_REQUIRE(pl.pl_lwpid == lwps[0]); | REQUIRE_EQ(pl.pl_lwpid, lwps[0]); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The next event should be for the child process's exec. */ | /* The next event should be for the child process's exec. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)) == | REQUIRE_EQ((pl.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)), | ||||
(PL_FLAG_EXEC | PL_FLAG_SCX)); | (PL_FLAG_EXEC | PL_FLAG_SCX)); | ||||
ATF_REQUIRE(pl.pl_lwpid == lwps[1]); | REQUIRE_EQ(pl.pl_lwpid, lwps[1]); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The last event should be for the child process's exit. */ | /* The last event should be for the child process's exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 0); | REQUIRE_EQ(WEXITSTATUS(status), 0); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
static void | static void | ||||
handler(int sig __unused) | handler(int sig __unused) | ||||
{ | { | ||||
} | } | ||||
static void | static void | ||||
Show All 18 Lines | ATF_TC_BODY(ptrace__siginfo, tc) | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
signal_main(); | signal_main(); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The next event should be for the SIGINFO. */ | /* The next event should be for the SIGINFO. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGINFO); | REQUIRE_EQ(WSTOPSIG(status), SIGINFO); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_event == PL_EVENT_SIGNAL); | REQUIRE_EQ(pl.pl_event, PL_EVENT_SIGNAL); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_code == SI_LWP); | REQUIRE_EQ(pl.pl_siginfo.si_code, SI_LWP); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_pid == wpid); | REQUIRE_EQ(pl.pl_siginfo.si_pid, wpid); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The last event should be for the child process's exit. */ | /* The last event should be for the child process's exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 0); | REQUIRE_EQ(WEXITSTATUS(status), 0); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that the expected ptrace events are reported for PTRACE_EXEC. | * Verify that the expected ptrace events are reported for PTRACE_EXEC. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__ptrace_exec_disable); | ATF_TC_WITHOUT_HEAD(ptrace__ptrace_exec_disable); | ||||
ATF_TC_BODY(ptrace__ptrace_exec_disable, tc) | ATF_TC_BODY(ptrace__ptrace_exec_disable, tc) | ||||
{ | { | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int events, status; | int events, status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
exec_thread(NULL); | exec_thread(NULL); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
events = 0; | events = 0; | ||||
ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events, | ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events, | ||||
sizeof(events)) == 0); | sizeof(events)) == 0); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* Should get one event at exit. */ | /* Should get one event at exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 0); | REQUIRE_EQ(WEXITSTATUS(status), 0); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
ATF_TC_WITHOUT_HEAD(ptrace__ptrace_exec_enable); | ATF_TC_WITHOUT_HEAD(ptrace__ptrace_exec_enable); | ||||
ATF_TC_BODY(ptrace__ptrace_exec_enable, tc) | ATF_TC_BODY(ptrace__ptrace_exec_enable, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int events, status; | int events, status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
exec_thread(NULL); | exec_thread(NULL); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
events = PTRACE_EXEC; | events = PTRACE_EXEC; | ||||
ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events, | ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events, | ||||
sizeof(events)) == 0); | sizeof(events)) == 0); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The next event should be for the child process's exec. */ | /* The next event should be for the child process's exec. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)) == | REQUIRE_EQ((pl.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)), | ||||
(PL_FLAG_EXEC | PL_FLAG_SCX)); | (PL_FLAG_EXEC | PL_FLAG_SCX)); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The last event should be for the child process's exit. */ | /* The last event should be for the child process's exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 0); | REQUIRE_EQ(WEXITSTATUS(status), 0); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
ATF_TC_WITHOUT_HEAD(ptrace__event_mask); | ATF_TC_WITHOUT_HEAD(ptrace__event_mask); | ||||
ATF_TC_BODY(ptrace__event_mask, tc) | ATF_TC_BODY(ptrace__event_mask, tc) | ||||
{ | { | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int events, status; | int events, status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
exit(0); | exit(0); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* PT_FOLLOW_FORK should toggle the state of PTRACE_FORK. */ | /* PT_FOLLOW_FORK should toggle the state of PTRACE_FORK. */ | ||||
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, fpid, NULL, 1) != -1); | ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, fpid, NULL, 1) != -1); | ||||
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events, | ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events, | ||||
sizeof(events)) == 0); | sizeof(events)) == 0); | ||||
ATF_REQUIRE(events & PTRACE_FORK); | ATF_REQUIRE(events & PTRACE_FORK); | ||||
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, fpid, NULL, 0) != -1); | ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, fpid, NULL, 0) != -1); | ||||
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events, | ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events, | ||||
sizeof(events)) == 0); | sizeof(events)) == 0); | ||||
ATF_REQUIRE(!(events & PTRACE_FORK)); | ATF_REQUIRE(!(events & PTRACE_FORK)); | ||||
/* PT_LWP_EVENTS should toggle the state of PTRACE_LWP. */ | /* PT_LWP_EVENTS should toggle the state of PTRACE_LWP. */ | ||||
ATF_REQUIRE(ptrace(PT_LWP_EVENTS, fpid, NULL, 1) != -1); | ATF_REQUIRE(ptrace(PT_LWP_EVENTS, fpid, NULL, 1) != -1); | ||||
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events, | ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events, | ||||
sizeof(events)) == 0); | sizeof(events)) == 0); | ||||
ATF_REQUIRE(events & PTRACE_LWP); | ATF_REQUIRE(events & PTRACE_LWP); | ||||
ATF_REQUIRE(ptrace(PT_LWP_EVENTS, fpid, NULL, 0) != -1); | ATF_REQUIRE(ptrace(PT_LWP_EVENTS, fpid, NULL, 0) != -1); | ||||
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events, | ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events, | ||||
sizeof(events)) == 0); | sizeof(events)) == 0); | ||||
ATF_REQUIRE(!(events & PTRACE_LWP)); | ATF_REQUIRE(!(events & PTRACE_LWP)); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* Should get one event at exit. */ | /* Should get one event at exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 0); | REQUIRE_EQ(WEXITSTATUS(status), 0); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that the expected ptrace events are reported for PTRACE_VFORK. | * Verify that the expected ptrace events are reported for PTRACE_VFORK. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__ptrace_vfork); | ATF_TC_WITHOUT_HEAD(ptrace__ptrace_vfork); | ||||
ATF_TC_BODY(ptrace__ptrace_vfork, tc) | ATF_TC_BODY(ptrace__ptrace_vfork, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int events, status; | int events, status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
follow_fork_parent(true); | follow_fork_parent(true); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events, | ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events, | ||||
sizeof(events)) == 0); | sizeof(events)) == 0); | ||||
events |= PTRACE_VFORK; | events |= PTRACE_VFORK; | ||||
ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events, | ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events, | ||||
sizeof(events)) == 0); | sizeof(events)) == 0); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) != -1); | ||||
/* The next event should report the end of the vfork. */ | /* The next event should report the end of the vfork. */ | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & PL_FLAG_VFORK_DONE) != 0); | ATF_REQUIRE((pl.pl_flags & PL_FLAG_VFORK_DONE) != 0); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) != -1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
ATF_TC_WITHOUT_HEAD(ptrace__ptrace_vfork_follow); | ATF_TC_WITHOUT_HEAD(ptrace__ptrace_vfork_follow); | ||||
ATF_TC_BODY(ptrace__ptrace_vfork_follow, tc) | ATF_TC_BODY(ptrace__ptrace_vfork_follow, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl[2]; | struct ptrace_lwpinfo pl[2]; | ||||
pid_t children[2], fpid, wpid; | pid_t children[2], fpid, wpid; | ||||
int events, status; | int events, status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
follow_fork_parent(true); | follow_fork_parent(true); | ||||
} | } | ||||
/* Parent process. */ | /* Parent process. */ | ||||
children[0] = fpid; | children[0] = fpid; | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(children[0], &status, 0); | wpid = waitpid(children[0], &status, 0); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, children[0], (caddr_t)&events, | ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, children[0], (caddr_t)&events, | ||||
sizeof(events)) == 0); | sizeof(events)) == 0); | ||||
events |= PTRACE_FORK | PTRACE_VFORK; | events |= PTRACE_FORK | PTRACE_VFORK; | ||||
ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, children[0], (caddr_t)&events, | ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, children[0], (caddr_t)&events, | ||||
sizeof(events)) == 0); | sizeof(events)) == 0); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
/* Wait for both halves of the fork event to get reported. */ | /* Wait for both halves of the fork event to get reported. */ | ||||
children[1] = handle_fork_events(children[0], pl); | children[1] = handle_fork_events(children[0], pl); | ||||
ATF_REQUIRE(children[1] > 0); | ATF_REQUIRE(children[1] > 0); | ||||
ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_VFORKED) != 0); | ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_VFORKED) != 0); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); | ||||
/* | /* | ||||
* The child can't exit until the grandchild reports status, so the | * The child can't exit until the grandchild reports status, so the | ||||
* grandchild should report its exit first to the debugger. | * grandchild should report its exit first to the debugger. | ||||
*/ | */ | ||||
wpid = waitpid(children[1], &status, 0); | wpid = waitpid(children[1], &status, 0); | ||||
ATF_REQUIRE(wpid == children[1]); | REQUIRE_EQ(wpid, children[1]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 2); | REQUIRE_EQ(WEXITSTATUS(status), 2); | ||||
/* | /* | ||||
* The child should report it's vfork() completion before it | * The child should report it's vfork() completion before it | ||||
* exits. | * exits. | ||||
*/ | */ | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl[0], sizeof(pl[0])) != | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl[0], sizeof(pl[0])) != | ||||
-1); | -1); | ||||
ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_VFORK_DONE) != 0); | ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_VFORK_DONE) != 0); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == children[0]); | REQUIRE_EQ(wpid, children[0]); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
#ifdef HAVE_BREAKPOINT | #ifdef HAVE_BREAKPOINT | ||||
/* | /* | ||||
* Verify that no more events are reported after PT_KILL except for the | * Verify that no more events are reported after PT_KILL except for the | ||||
* process exit when stopped due to a breakpoint trap. | * process exit when stopped due to a breakpoint trap. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__PT_KILL_breakpoint); | ATF_TC_WITHOUT_HEAD(ptrace__PT_KILL_breakpoint); | ||||
ATF_TC_BODY(ptrace__PT_KILL_breakpoint, tc) | ATF_TC_BODY(ptrace__PT_KILL_breakpoint, tc) | ||||
{ | { | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int status; | int status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
breakpoint(); | breakpoint(); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The second wait() should report hitting the breakpoint. */ | /* The second wait() should report hitting the breakpoint. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
/* Kill the child process. */ | /* Kill the child process. */ | ||||
ATF_REQUIRE(ptrace(PT_KILL, fpid, 0, 0) == 0); | REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0); | ||||
/* The last wait() should report the SIGKILL. */ | /* The last wait() should report the SIGKILL. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSIGNALED(status)); | ATF_REQUIRE(WIFSIGNALED(status)); | ||||
ATF_REQUIRE(WTERMSIG(status) == SIGKILL); | REQUIRE_EQ(WTERMSIG(status), SIGKILL); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
#endif /* HAVE_BREAKPOINT */ | #endif /* HAVE_BREAKPOINT */ | ||||
/* | /* | ||||
* Verify that no more events are reported after PT_KILL except for the | * Verify that no more events are reported after PT_KILL except for the | ||||
* process exit when stopped inside of a system call. | * process exit when stopped inside of a system call. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__PT_KILL_system_call); | ATF_TC_WITHOUT_HEAD(ptrace__PT_KILL_system_call); | ||||
ATF_TC_BODY(ptrace__PT_KILL_system_call, tc) | ATF_TC_BODY(ptrace__PT_KILL_system_call, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int status; | int status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
getpid(); | getpid(); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Continue the child ignoring the SIGSTOP and tracing system calls. */ | /* Continue the child ignoring the SIGSTOP and tracing system calls. */ | ||||
ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0); | ||||
/* The second wait() should report a system call entry for getpid(). */ | /* The second wait() should report a system call entry for getpid(). */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ||||
/* Kill the child process. */ | /* Kill the child process. */ | ||||
ATF_REQUIRE(ptrace(PT_KILL, fpid, 0, 0) == 0); | REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0); | ||||
/* The last wait() should report the SIGKILL. */ | /* The last wait() should report the SIGKILL. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSIGNALED(status)); | ATF_REQUIRE(WIFSIGNALED(status)); | ||||
ATF_REQUIRE(WTERMSIG(status) == SIGKILL); | REQUIRE_EQ(WTERMSIG(status), SIGKILL); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that no more events are reported after PT_KILL except for the | * Verify that no more events are reported after PT_KILL except for the | ||||
* process exit when killing a multithreaded process. | * process exit when killing a multithreaded process. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__PT_KILL_threads); | ATF_TC_WITHOUT_HEAD(ptrace__PT_KILL_threads); | ||||
ATF_TC_BODY(ptrace__PT_KILL_threads, tc) | ATF_TC_BODY(ptrace__PT_KILL_threads, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
lwpid_t main_lwp; | lwpid_t main_lwp; | ||||
int status; | int status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
simple_thread_main(); | simple_thread_main(); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ||||
sizeof(pl)) != -1); | sizeof(pl)) != -1); | ||||
main_lwp = pl.pl_lwpid; | main_lwp = pl.pl_lwpid; | ||||
ATF_REQUIRE(ptrace(PT_LWP_EVENTS, wpid, NULL, 1) == 0); | REQUIRE_EQ(ptrace(PT_LWP_EVENTS, wpid, NULL, 1), 0); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The first event should be for the child thread's birth. */ | /* The first event should be for the child thread's birth. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)) == | REQUIRE_EQ((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)), | ||||
(PL_FLAG_BORN | PL_FLAG_SCX)); | (PL_FLAG_BORN | PL_FLAG_SCX)); | ||||
ATF_REQUIRE(pl.pl_lwpid != main_lwp); | ATF_REQUIRE(pl.pl_lwpid != main_lwp); | ||||
/* Kill the child process. */ | /* Kill the child process. */ | ||||
ATF_REQUIRE(ptrace(PT_KILL, fpid, 0, 0) == 0); | REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0); | ||||
/* The last wait() should report the SIGKILL. */ | /* The last wait() should report the SIGKILL. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSIGNALED(status)); | ATF_REQUIRE(WIFSIGNALED(status)); | ||||
ATF_REQUIRE(WTERMSIG(status) == SIGKILL); | REQUIRE_EQ(WTERMSIG(status), SIGKILL); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
static void * | static void * | ||||
mask_usr1_thread(void *arg) | mask_usr1_thread(void *arg) | ||||
{ | { | ||||
pthread_barrier_t *pbarrier; | pthread_barrier_t *pbarrier; | ||||
sigset_t sigmask; | sigset_t sigmask; | ||||
pbarrier = (pthread_barrier_t*)arg; | pbarrier = (pthread_barrier_t*)arg; | ||||
sigemptyset(&sigmask); | sigemptyset(&sigmask); | ||||
sigaddset(&sigmask, SIGUSR1); | sigaddset(&sigmask, SIGUSR1); | ||||
CHILD_REQUIRE(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == 0); | CHILD_REQUIRE_EQ(pthread_sigmask(SIG_BLOCK, &sigmask, NULL), 0); | ||||
/* Sync up with other thread after sigmask updated. */ | /* Sync up with other thread after sigmask updated. */ | ||||
pthread_barrier_wait(pbarrier); | pthread_barrier_wait(pbarrier); | ||||
for (;;) | for (;;) | ||||
sleep(60); | sleep(60); | ||||
return (NULL); | return (NULL); | ||||
Show All 19 Lines | ATF_TC_BODY(ptrace__PT_KILL_competing_signal, tc) | ||||
struct sched_param sched_param; | struct sched_param sched_param; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
/* Bind to one CPU so only one thread at a time will run. */ | /* Bind to one CPU so only one thread at a time will run. */ | ||||
CPU_ZERO(&setmask); | CPU_ZERO(&setmask); | ||||
CPU_SET(0, &setmask); | CPU_SET(0, &setmask); | ||||
cpusetid_t setid; | cpusetid_t setid; | ||||
CHILD_REQUIRE(cpuset(&setid) == 0); | CHILD_REQUIRE_EQ(cpuset(&setid), 0); | ||||
CHILD_REQUIRE(cpuset_setaffinity(CPU_LEVEL_CPUSET, | CHILD_REQUIRE(cpuset_setaffinity(CPU_LEVEL_CPUSET, | ||||
CPU_WHICH_CPUSET, setid, sizeof(setmask), &setmask) == 0); | CPU_WHICH_CPUSET, setid, sizeof(setmask), &setmask) == 0); | ||||
CHILD_REQUIRE(pthread_barrier_init(&barrier, NULL, 2) == 0); | CHILD_REQUIRE_EQ(pthread_barrier_init(&barrier, NULL, 2), 0); | ||||
CHILD_REQUIRE(pthread_create(&t, NULL, mask_usr1_thread, | CHILD_REQUIRE(pthread_create(&t, NULL, mask_usr1_thread, | ||||
(void*)&barrier) == 0); | (void*)&barrier) == 0); | ||||
/* | /* | ||||
* Give the main thread higher priority. The test always | * Give the main thread higher priority. The test always | ||||
* assumes that, if both threads are able to run, the main | * assumes that, if both threads are able to run, the main | ||||
* thread runs first. | * thread runs first. | ||||
*/ | */ | ||||
sched_param.sched_priority = | sched_param.sched_priority = | ||||
(sched_get_priority_max(SCHED_FIFO) + | (sched_get_priority_max(SCHED_FIFO) + | ||||
sched_get_priority_min(SCHED_FIFO)) / 2; | sched_get_priority_min(SCHED_FIFO)) / 2; | ||||
CHILD_REQUIRE(pthread_setschedparam(pthread_self(), | CHILD_REQUIRE(pthread_setschedparam(pthread_self(), | ||||
SCHED_FIFO, &sched_param) == 0); | SCHED_FIFO, &sched_param) == 0); | ||||
sched_param.sched_priority -= RQ_PPQ; | sched_param.sched_priority -= RQ_PPQ; | ||||
CHILD_REQUIRE(pthread_setschedparam(t, SCHED_FIFO, | CHILD_REQUIRE(pthread_setschedparam(t, SCHED_FIFO, | ||||
&sched_param) == 0); | &sched_param) == 0); | ||||
sigset_t sigmask; | sigset_t sigmask; | ||||
sigemptyset(&sigmask); | sigemptyset(&sigmask); | ||||
sigaddset(&sigmask, SIGUSR2); | sigaddset(&sigmask, SIGUSR2); | ||||
CHILD_REQUIRE(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == 0); | CHILD_REQUIRE_EQ(pthread_sigmask(SIG_BLOCK, &sigmask, NULL), 0); | ||||
/* Sync up with other thread after sigmask updated. */ | /* Sync up with other thread after sigmask updated. */ | ||||
pthread_barrier_wait(&barrier); | pthread_barrier_wait(&barrier); | ||||
trace_me(); | trace_me(); | ||||
for (;;) | for (;;) | ||||
sleep(60); | sleep(60); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* Send a signal that only the second thread can handle. */ | /* Send a signal that only the second thread can handle. */ | ||||
ATF_REQUIRE(kill(fpid, SIGUSR2) == 0); | REQUIRE_EQ(kill(fpid, SIGUSR2), 0); | ||||
/* The second wait() should report the SIGUSR2. */ | /* The second wait() should report the SIGUSR2. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGUSR2); | REQUIRE_EQ(WSTOPSIG(status), SIGUSR2); | ||||
/* Send a signal that only the first thread can handle. */ | /* Send a signal that only the first thread can handle. */ | ||||
ATF_REQUIRE(kill(fpid, SIGUSR1) == 0); | REQUIRE_EQ(kill(fpid, SIGUSR1), 0); | ||||
/* Replace the SIGUSR2 with a kill. */ | /* Replace the SIGUSR2 with a kill. */ | ||||
ATF_REQUIRE(ptrace(PT_KILL, fpid, 0, 0) == 0); | REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0); | ||||
/* The last wait() should report the SIGKILL (not the SIGUSR signal). */ | /* The last wait() should report the SIGKILL (not the SIGUSR signal). */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSIGNALED(status)); | ATF_REQUIRE(WIFSIGNALED(status)); | ||||
ATF_REQUIRE(WTERMSIG(status) == SIGKILL); | REQUIRE_EQ(WTERMSIG(status), SIGKILL); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that the SIGKILL from PT_KILL takes priority over other stop events | * Verify that the SIGKILL from PT_KILL takes priority over other stop events | ||||
* and prevents spurious stops caused by those events. | * and prevents spurious stops caused by those events. | ||||
*/ | */ | ||||
ATF_TC(ptrace__PT_KILL_competing_stop); | ATF_TC(ptrace__PT_KILL_competing_stop); | ||||
ATF_TC_HEAD(ptrace__PT_KILL_competing_stop, tc) | ATF_TC_HEAD(ptrace__PT_KILL_competing_stop, tc) | ||||
Show All 18 Lines | ATF_TC_BODY(ptrace__PT_KILL_competing_stop, tc) | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
/* Bind to one CPU so only one thread at a time will run. */ | /* Bind to one CPU so only one thread at a time will run. */ | ||||
CPU_ZERO(&setmask); | CPU_ZERO(&setmask); | ||||
CPU_SET(0, &setmask); | CPU_SET(0, &setmask); | ||||
cpusetid_t setid; | cpusetid_t setid; | ||||
CHILD_REQUIRE(cpuset(&setid) == 0); | CHILD_REQUIRE_EQ(cpuset(&setid), 0); | ||||
CHILD_REQUIRE(cpuset_setaffinity(CPU_LEVEL_CPUSET, | CHILD_REQUIRE(cpuset_setaffinity(CPU_LEVEL_CPUSET, | ||||
CPU_WHICH_CPUSET, setid, sizeof(setmask), &setmask) == 0); | CPU_WHICH_CPUSET, setid, sizeof(setmask), &setmask) == 0); | ||||
CHILD_REQUIRE(pthread_barrier_init(&barrier, NULL, 2) == 0); | CHILD_REQUIRE_EQ(pthread_barrier_init(&barrier, NULL, 2), 0); | ||||
CHILD_REQUIRE(pthread_create(&t, NULL, mask_usr1_thread, | CHILD_REQUIRE(pthread_create(&t, NULL, mask_usr1_thread, | ||||
(void*)&barrier) == 0); | (void*)&barrier) == 0); | ||||
/* | /* | ||||
* Give the main thread higher priority. The test always | * Give the main thread higher priority. The test always | ||||
* assumes that, if both threads are able to run, the main | * assumes that, if both threads are able to run, the main | ||||
* thread runs first. | * thread runs first. | ||||
*/ | */ | ||||
sched_param.sched_priority = | sched_param.sched_priority = | ||||
(sched_get_priority_max(SCHED_FIFO) + | (sched_get_priority_max(SCHED_FIFO) + | ||||
sched_get_priority_min(SCHED_FIFO)) / 2; | sched_get_priority_min(SCHED_FIFO)) / 2; | ||||
CHILD_REQUIRE(pthread_setschedparam(pthread_self(), | CHILD_REQUIRE(pthread_setschedparam(pthread_self(), | ||||
SCHED_FIFO, &sched_param) == 0); | SCHED_FIFO, &sched_param) == 0); | ||||
sched_param.sched_priority -= RQ_PPQ; | sched_param.sched_priority -= RQ_PPQ; | ||||
CHILD_REQUIRE(pthread_setschedparam(t, SCHED_FIFO, | CHILD_REQUIRE(pthread_setschedparam(t, SCHED_FIFO, | ||||
&sched_param) == 0); | &sched_param) == 0); | ||||
sigset_t sigmask; | sigset_t sigmask; | ||||
sigemptyset(&sigmask); | sigemptyset(&sigmask); | ||||
sigaddset(&sigmask, SIGUSR2); | sigaddset(&sigmask, SIGUSR2); | ||||
CHILD_REQUIRE(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == 0); | CHILD_REQUIRE_EQ(pthread_sigmask(SIG_BLOCK, &sigmask, NULL), 0); | ||||
/* Sync up with other thread after sigmask updated. */ | /* Sync up with other thread after sigmask updated. */ | ||||
pthread_barrier_wait(&barrier); | pthread_barrier_wait(&barrier); | ||||
/* Sync up with the test before doing the getpid(). */ | /* Sync up with the test before doing the getpid(). */ | ||||
raise(SIGSTOP); | raise(SIGSTOP); | ||||
getpid(); | getpid(); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
main_lwp = pl.pl_lwpid; | main_lwp = pl.pl_lwpid; | ||||
/* Continue the child ignoring the SIGSTOP and tracing system calls. */ | /* Continue the child ignoring the SIGSTOP and tracing system calls. */ | ||||
ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0); | ||||
/* | /* | ||||
* Continue until child is done with setup, which is indicated with | * Continue until child is done with setup, which is indicated with | ||||
* SIGSTOP. Ignore system calls in the meantime. | * SIGSTOP. Ignore system calls in the meantime. | ||||
*/ | */ | ||||
for (;;) { | for (;;) { | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
if (WSTOPSIG(status) == SIGTRAP) { | if (WSTOPSIG(status) == SIGTRAP) { | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ||||
sizeof(pl)) != -1); | sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)); | ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)); | ||||
} else { | } else { | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
break; | break; | ||||
} | } | ||||
ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0); | ||||
} | } | ||||
/* Proceed, allowing main thread to hit syscall entry for getpid(). */ | /* Proceed, allowing main thread to hit syscall entry for getpid(). */ | ||||
ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0); | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ||||
sizeof(pl)) != -1); | sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_lwpid == main_lwp); | REQUIRE_EQ(pl.pl_lwpid, main_lwp); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ||||
/* Prevent the main thread from hitting its syscall exit for now. */ | /* Prevent the main thread from hitting its syscall exit for now. */ | ||||
ATF_REQUIRE(ptrace(PT_SUSPEND, main_lwp, 0, 0) == 0); | REQUIRE_EQ(ptrace(PT_SUSPEND, main_lwp, 0, 0), 0); | ||||
/* | /* | ||||
* Proceed, allowing second thread to hit syscall exit for | * Proceed, allowing second thread to hit syscall exit for | ||||
* pthread_barrier_wait(). | * pthread_barrier_wait(). | ||||
*/ | */ | ||||
ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0); | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ||||
sizeof(pl)) != -1); | sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_lwpid != main_lwp); | ATF_REQUIRE(pl.pl_lwpid != main_lwp); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX); | ||||
/* Send a signal that only the second thread can handle. */ | /* Send a signal that only the second thread can handle. */ | ||||
ATF_REQUIRE(kill(fpid, SIGUSR2) == 0); | REQUIRE_EQ(kill(fpid, SIGUSR2), 0); | ||||
ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0); | ||||
/* The next wait() should report the SIGUSR2. */ | /* The next wait() should report the SIGUSR2. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGUSR2); | REQUIRE_EQ(WSTOPSIG(status), SIGUSR2); | ||||
/* Allow the main thread to try to finish its system call. */ | /* Allow the main thread to try to finish its system call. */ | ||||
ATF_REQUIRE(ptrace(PT_RESUME, main_lwp, 0, 0) == 0); | REQUIRE_EQ(ptrace(PT_RESUME, main_lwp, 0, 0), 0); | ||||
/* | /* | ||||
* At this point, the main thread is in the middle of a system call and | * At this point, the main thread is in the middle of a system call and | ||||
* has been resumed. The second thread has taken a SIGUSR2 which will | * has been resumed. The second thread has taken a SIGUSR2 which will | ||||
* be replaced with a SIGKILL below. The main thread will get to run | * be replaced with a SIGKILL below. The main thread will get to run | ||||
* first. It should notice the kill request (even though the signal | * first. It should notice the kill request (even though the signal | ||||
* replacement occurred in the other thread) and exit accordingly. It | * replacement occurred in the other thread) and exit accordingly. It | ||||
* should not stop for the system call exit event. | * should not stop for the system call exit event. | ||||
*/ | */ | ||||
/* Replace the SIGUSR2 with a kill. */ | /* Replace the SIGUSR2 with a kill. */ | ||||
ATF_REQUIRE(ptrace(PT_KILL, fpid, 0, 0) == 0); | REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0); | ||||
/* The last wait() should report the SIGKILL (not a syscall exit). */ | /* The last wait() should report the SIGKILL (not a syscall exit). */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSIGNALED(status)); | ATF_REQUIRE(WIFSIGNALED(status)); | ||||
ATF_REQUIRE(WTERMSIG(status) == SIGKILL); | REQUIRE_EQ(WTERMSIG(status), SIGKILL); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
static void | static void | ||||
sigusr1_handler(int sig) | sigusr1_handler(int sig) | ||||
{ | { | ||||
CHILD_REQUIRE(sig == SIGUSR1); | CHILD_REQUIRE_EQ(sig, SIGUSR1); | ||||
_exit(2); | _exit(2); | ||||
} | } | ||||
/* | /* | ||||
* Verify that even if the signal queue is full for a child process, | * Verify that even if the signal queue is full for a child process, | ||||
* a PT_KILL will kill the process. | * a PT_KILL will kill the process. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__PT_KILL_with_signal_full_sigqueue); | ATF_TC_WITHOUT_HEAD(ptrace__PT_KILL_with_signal_full_sigqueue); | ||||
Show All 10 Lines | ATF_TC_BODY(ptrace__PT_KILL_with_signal_full_sigqueue, tc) | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
len = sizeof(max_pending_per_proc); | len = sizeof(max_pending_per_proc); | ||||
ATF_REQUIRE(sysctlbyname("kern.sigqueue.max_pending_per_proc", | ATF_REQUIRE(sysctlbyname("kern.sigqueue.max_pending_per_proc", | ||||
&max_pending_per_proc, &len, NULL, 0) == 0); | &max_pending_per_proc, &len, NULL, 0) == 0); | ||||
/* Fill the signal queue. */ | /* Fill the signal queue. */ | ||||
for (i = 0; i < max_pending_per_proc; ++i) | for (i = 0; i < max_pending_per_proc; ++i) | ||||
ATF_REQUIRE(kill(fpid, SIGUSR1) == 0); | REQUIRE_EQ(kill(fpid, SIGUSR1), 0); | ||||
/* Kill the child process. */ | /* Kill the child process. */ | ||||
ATF_REQUIRE(ptrace(PT_KILL, fpid, 0, 0) == 0); | REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0); | ||||
/* The last wait() should report the SIGKILL. */ | /* The last wait() should report the SIGKILL. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSIGNALED(status)); | ATF_REQUIRE(WIFSIGNALED(status)); | ||||
ATF_REQUIRE(WTERMSIG(status) == SIGKILL); | REQUIRE_EQ(WTERMSIG(status), SIGKILL); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that when stopped at a system call entry, a signal can be | * Verify that when stopped at a system call entry, a signal can be | ||||
* requested with PT_CONTINUE which will be delivered once the system | * requested with PT_CONTINUE which will be delivered once the system | ||||
* call is complete. | * call is complete. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_system_call_entry); | ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_system_call_entry); | ||||
Show All 9 Lines | ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_system_call_entry, tc) | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
getpid(); | getpid(); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Continue the child ignoring the SIGSTOP and tracing system calls. */ | /* Continue the child ignoring the SIGSTOP and tracing system calls. */ | ||||
ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0); | ||||
/* The second wait() should report a system call entry for getpid(). */ | /* The second wait() should report a system call entry for getpid(). */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ||||
/* Continue the child process with a signal. */ | /* Continue the child process with a signal. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0); | ||||
for (;;) { | for (;;) { | ||||
/* | /* | ||||
* The last wait() should report exit 2, i.e., a normal _exit | * The last wait() should report exit 2, i.e., a normal _exit | ||||
* from the signal handler. In the meantime, catch and proceed | * from the signal handler. In the meantime, catch and proceed | ||||
* past any syscall stops. | * past any syscall stops. | ||||
*/ | */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { | if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)); | ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
} else { | } else { | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 2); | REQUIRE_EQ(WEXITSTATUS(status), 2); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
static void | static void | ||||
sigusr1_counting_handler(int sig) | sigusr1_counting_handler(int sig) | ||||
{ | { | ||||
static int counter = 0; | static int counter = 0; | ||||
CHILD_REQUIRE(sig == SIGUSR1); | CHILD_REQUIRE_EQ(sig, SIGUSR1); | ||||
counter++; | counter++; | ||||
if (counter == 2) | if (counter == 2) | ||||
_exit(2); | _exit(2); | ||||
} | } | ||||
/* | /* | ||||
* Verify that, when continuing from a stop at system call entry and exit, | * Verify that, when continuing from a stop at system call entry and exit, | ||||
* a signal can be requested from both stops, and both will be delivered when | * a signal can be requested from both stops, and both will be delivered when | ||||
Show All 12 Lines | ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_system_call_entry_and_exit, tc) | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
getpid(); | getpid(); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Continue the child ignoring the SIGSTOP and tracing system calls. */ | /* Continue the child ignoring the SIGSTOP and tracing system calls. */ | ||||
ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0); | ||||
/* The second wait() should report a system call entry for getpid(). */ | /* The second wait() should report a system call entry for getpid(). */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ||||
/* Continue the child process with a signal. */ | /* Continue the child process with a signal. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0); | ||||
/* The third wait() should report a system call exit for getpid(). */ | /* The third wait() should report a system call exit for getpid(). */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX); | ||||
/* Continue the child process with a signal. */ | /* Continue the child process with a signal. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0); | ||||
for (;;) { | for (;;) { | ||||
/* | /* | ||||
* The last wait() should report exit 2, i.e., a normal _exit | * The last wait() should report exit 2, i.e., a normal _exit | ||||
* from the signal handler. In the meantime, catch and proceed | * from the signal handler. In the meantime, catch and proceed | ||||
* past any syscall stops. | * past any syscall stops. | ||||
*/ | */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { | if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)); | ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
} else { | } else { | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 2); | REQUIRE_EQ(WEXITSTATUS(status), 2); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that even if the signal queue is full for a child process, | * Verify that even if the signal queue is full for a child process, | ||||
* a PT_CONTINUE with a signal will not result in loss of that signal. | * a PT_CONTINUE with a signal will not result in loss of that signal. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_full_sigqueue); | ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_full_sigqueue); | ||||
ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_full_sigqueue, tc) | ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_full_sigqueue, tc) | ||||
Show All 10 Lines | ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_full_sigqueue, tc) | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
len = sizeof(max_pending_per_proc); | len = sizeof(max_pending_per_proc); | ||||
ATF_REQUIRE(sysctlbyname("kern.sigqueue.max_pending_per_proc", | ATF_REQUIRE(sysctlbyname("kern.sigqueue.max_pending_per_proc", | ||||
&max_pending_per_proc, &len, NULL, 0) == 0); | &max_pending_per_proc, &len, NULL, 0) == 0); | ||||
/* Fill the signal queue. */ | /* Fill the signal queue. */ | ||||
for (i = 0; i < max_pending_per_proc; ++i) | for (i = 0; i < max_pending_per_proc; ++i) | ||||
ATF_REQUIRE(kill(fpid, SIGUSR2) == 0); | REQUIRE_EQ(kill(fpid, SIGUSR2), 0); | ||||
/* Continue with signal. */ | /* Continue with signal. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0); | ||||
for (;;) { | for (;;) { | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
if (WIFSTOPPED(status)) { | if (WIFSTOPPED(status)) { | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGUSR2); | REQUIRE_EQ(WSTOPSIG(status), SIGUSR2); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
} else { | } else { | ||||
/* | /* | ||||
* The last wait() should report normal _exit from the | * The last wait() should report normal _exit from the | ||||
* SIGUSR1 handler. | * SIGUSR1 handler. | ||||
*/ | */ | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 2); | REQUIRE_EQ(WEXITSTATUS(status), 2); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
static sem_t sigusr1_sem; | static sem_t sigusr1_sem; | ||||
static int got_usr1; | static int got_usr1; | ||||
static void | static void | ||||
sigusr1_sempost_handler(int sig __unused) | sigusr1_sempost_handler(int sig __unused) | ||||
{ | { | ||||
got_usr1++; | got_usr1++; | ||||
CHILD_REQUIRE(sem_post(&sigusr1_sem) == 0); | CHILD_REQUIRE_EQ(sem_post(&sigusr1_sem), 0); | ||||
} | } | ||||
/* | /* | ||||
* Verify that even if the signal queue is full for a child process, | * Verify that even if the signal queue is full for a child process, | ||||
* and the signal is masked, a PT_CONTINUE with a signal will not | * and the signal is masked, a PT_CONTINUE with a signal will not | ||||
* result in loss of that signal. | * result in loss of that signal. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_masked_full_sigqueue); | ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_masked_full_sigqueue); | ||||
ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_masked_full_sigqueue, tc) | ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_masked_full_sigqueue, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int status, err; | int status, err; | ||||
int max_pending_per_proc; | int max_pending_per_proc; | ||||
size_t len; | size_t len; | ||||
int i; | int i; | ||||
sigset_t sigmask; | sigset_t sigmask; | ||||
ATF_REQUIRE(signal(SIGUSR2, handler) != SIG_ERR); | ATF_REQUIRE(signal(SIGUSR2, handler) != SIG_ERR); | ||||
ATF_REQUIRE(sem_init(&sigusr1_sem, 0, 0) == 0); | REQUIRE_EQ(sem_init(&sigusr1_sem, 0, 0), 0); | ||||
ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR); | ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR); | ||||
got_usr1 = 0; | got_usr1 = 0; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
CHILD_REQUIRE(sigemptyset(&sigmask) == 0); | CHILD_REQUIRE_EQ(sigemptyset(&sigmask), 0); | ||||
CHILD_REQUIRE(sigaddset(&sigmask, SIGUSR1) == 0); | CHILD_REQUIRE_EQ(sigaddset(&sigmask, SIGUSR1), 0); | ||||
CHILD_REQUIRE(sigprocmask(SIG_BLOCK, &sigmask, NULL) == 0); | CHILD_REQUIRE_EQ(sigprocmask(SIG_BLOCK, &sigmask, NULL), 0); | ||||
trace_me(); | trace_me(); | ||||
CHILD_REQUIRE(got_usr1 == 0); | CHILD_REQUIRE_EQ(got_usr1, 0); | ||||
/* Allow the pending SIGUSR1 in now. */ | /* Allow the pending SIGUSR1 in now. */ | ||||
CHILD_REQUIRE(sigprocmask(SIG_UNBLOCK, &sigmask, NULL) == 0); | CHILD_REQUIRE_EQ(sigprocmask(SIG_UNBLOCK, &sigmask, NULL), 0); | ||||
/* Wait to receive the SIGUSR1. */ | /* Wait to receive the SIGUSR1. */ | ||||
do { | do { | ||||
err = sem_wait(&sigusr1_sem); | err = sem_wait(&sigusr1_sem); | ||||
CHILD_REQUIRE(err == 0 || errno == EINTR); | CHILD_REQUIRE(err == 0 || errno == EINTR); | ||||
} while (err != 0 && errno == EINTR); | } while (err != 0 && errno == EINTR); | ||||
CHILD_REQUIRE(got_usr1 == 1); | CHILD_REQUIRE_EQ(got_usr1, 1); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
len = sizeof(max_pending_per_proc); | len = sizeof(max_pending_per_proc); | ||||
ATF_REQUIRE(sysctlbyname("kern.sigqueue.max_pending_per_proc", | ATF_REQUIRE(sysctlbyname("kern.sigqueue.max_pending_per_proc", | ||||
&max_pending_per_proc, &len, NULL, 0) == 0); | &max_pending_per_proc, &len, NULL, 0) == 0); | ||||
/* Fill the signal queue. */ | /* Fill the signal queue. */ | ||||
for (i = 0; i < max_pending_per_proc; ++i) | for (i = 0; i < max_pending_per_proc; ++i) | ||||
ATF_REQUIRE(kill(fpid, SIGUSR2) == 0); | REQUIRE_EQ(kill(fpid, SIGUSR2), 0); | ||||
/* Continue with signal. */ | /* Continue with signal. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0); | ||||
/* Collect and ignore all of the SIGUSR2. */ | /* Collect and ignore all of the SIGUSR2. */ | ||||
for (i = 0; i < max_pending_per_proc; ++i) { | for (i = 0; i < max_pending_per_proc; ++i) { | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGUSR2); | REQUIRE_EQ(WSTOPSIG(status), SIGUSR2); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
} | } | ||||
/* Now our PT_CONTINUE'd SIGUSR1 should cause a stop after unmask. */ | /* Now our PT_CONTINUE'd SIGUSR1 should cause a stop after unmask. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGUSR1); | REQUIRE_EQ(WSTOPSIG(status), SIGUSR1); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGUSR1); | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGUSR1); | ||||
/* Continue the child, ignoring the SIGUSR1. */ | /* Continue the child, ignoring the SIGUSR1. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The last wait() should report exit after receiving SIGUSR1. */ | /* The last wait() should report exit after receiving SIGUSR1. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that, after stopping due to a signal, that signal can be | * Verify that, after stopping due to a signal, that signal can be | ||||
* replaced with another signal. | * replaced with another signal. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_change_sig); | ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_change_sig); | ||||
ATF_TC_BODY(ptrace__PT_CONTINUE_change_sig, tc) | ATF_TC_BODY(ptrace__PT_CONTINUE_change_sig, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int status; | int status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
sleep(20); | sleep(20); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* Send a signal without ptrace. */ | /* Send a signal without ptrace. */ | ||||
ATF_REQUIRE(kill(fpid, SIGINT) == 0); | REQUIRE_EQ(kill(fpid, SIGINT), 0); | ||||
/* The second wait() should report a SIGINT was received. */ | /* The second wait() should report a SIGINT was received. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGINT); | REQUIRE_EQ(WSTOPSIG(status), SIGINT); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGINT); | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGINT); | ||||
/* Continue the child process with a different signal. */ | /* Continue the child process with a different signal. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGTERM) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGTERM), 0); | ||||
/* | /* | ||||
* The last wait() should report having died due to the new | * The last wait() should report having died due to the new | ||||
* signal, SIGTERM. | * signal, SIGTERM. | ||||
*/ | */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSIGNALED(status)); | ATF_REQUIRE(WIFSIGNALED(status)); | ||||
ATF_REQUIRE(WTERMSIG(status) == SIGTERM); | REQUIRE_EQ(WTERMSIG(status), SIGTERM); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that a signal can be passed through to the child even when there | * Verify that a signal can be passed through to the child even when there | ||||
* was no true signal originally. Such cases arise when a SIGTRAP is | * was no true signal originally. Such cases arise when a SIGTRAP is | ||||
* invented for e.g, system call stops. | * invented for e.g, system call stops. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_sigtrap_system_call_entry); | ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_sigtrap_system_call_entry); | ||||
ATF_TC_BODY(ptrace__PT_CONTINUE_with_sigtrap_system_call_entry, tc) | ATF_TC_BODY(ptrace__PT_CONTINUE_with_sigtrap_system_call_entry, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
struct rlimit rl; | struct rlimit rl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int status; | int status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
/* SIGTRAP expected to cause exit on syscall entry. */ | /* SIGTRAP expected to cause exit on syscall entry. */ | ||||
rl.rlim_cur = rl.rlim_max = 0; | rl.rlim_cur = rl.rlim_max = 0; | ||||
ATF_REQUIRE(setrlimit(RLIMIT_CORE, &rl) == 0); | REQUIRE_EQ(setrlimit(RLIMIT_CORE, &rl), 0); | ||||
getpid(); | getpid(); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Continue the child ignoring the SIGSTOP and tracing system calls. */ | /* Continue the child ignoring the SIGSTOP and tracing system calls. */ | ||||
ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0); | ||||
/* The second wait() should report a system call entry for getpid(). */ | /* The second wait() should report a system call entry for getpid(). */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ||||
/* Continue the child process with a SIGTRAP. */ | /* Continue the child process with a SIGTRAP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGTRAP) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGTRAP), 0); | ||||
for (;;) { | for (;;) { | ||||
/* | /* | ||||
* The last wait() should report exit due to SIGTRAP. In the | * The last wait() should report exit due to SIGTRAP. In the | ||||
* meantime, catch and proceed past any syscall stops. | * meantime, catch and proceed past any syscall stops. | ||||
*/ | */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { | if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)); | ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
} else { | } else { | ||||
ATF_REQUIRE(WIFSIGNALED(status)); | ATF_REQUIRE(WIFSIGNALED(status)); | ||||
ATF_REQUIRE(WTERMSIG(status) == SIGTRAP); | REQUIRE_EQ(WTERMSIG(status), SIGTRAP); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* A mixed bag PT_CONTINUE with signal test. | * A mixed bag PT_CONTINUE with signal test. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_mix); | ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_mix); | ||||
ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_mix, tc) | ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_mix, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int status; | int status; | ||||
ATF_REQUIRE(signal(SIGUSR1, sigusr1_counting_handler) != SIG_ERR); | ATF_REQUIRE(signal(SIGUSR1, sigusr1_counting_handler) != SIG_ERR); | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
getpid(); | getpid(); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Continue the child ignoring the SIGSTOP and tracing system calls. */ | /* Continue the child ignoring the SIGSTOP and tracing system calls. */ | ||||
ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0); | ||||
/* The second wait() should report a system call entry for getpid(). */ | /* The second wait() should report a system call entry for getpid(). */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ||||
/* Continue with the first SIGUSR1. */ | /* Continue with the first SIGUSR1. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0); | ||||
/* The next wait() should report a system call exit for getpid(). */ | /* The next wait() should report a system call exit for getpid(). */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX); | ||||
/* Send an ABRT without ptrace. */ | /* Send an ABRT without ptrace. */ | ||||
ATF_REQUIRE(kill(fpid, SIGABRT) == 0); | REQUIRE_EQ(kill(fpid, SIGABRT), 0); | ||||
/* Continue normally. */ | /* Continue normally. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The next wait() should report the SIGABRT. */ | /* The next wait() should report the SIGABRT. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGABRT); | REQUIRE_EQ(WSTOPSIG(status), SIGABRT); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGABRT); | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGABRT); | ||||
/* Continue, replacing the SIGABRT with another SIGUSR1. */ | /* Continue, replacing the SIGABRT with another SIGUSR1. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0); | ||||
for (;;) { | for (;;) { | ||||
/* | /* | ||||
* The last wait() should report exit 2, i.e., a normal _exit | * The last wait() should report exit 2, i.e., a normal _exit | ||||
* from the signal handler. In the meantime, catch and proceed | * from the signal handler. In the meantime, catch and proceed | ||||
* past any syscall stops. | * past any syscall stops. | ||||
*/ | */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { | if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) { | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)); | ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
} else { | } else { | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 2); | REQUIRE_EQ(WEXITSTATUS(status), 2); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify a signal delivered by ptrace is noticed by kevent(2). | * Verify a signal delivered by ptrace is noticed by kevent(2). | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_kqueue); | ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_kqueue); | ||||
ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_kqueue, tc) | ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_kqueue, tc) | ||||
{ | { | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int status, kq, nevents; | int status, kq, nevents; | ||||
struct kevent kev; | struct kevent kev; | ||||
ATF_REQUIRE(signal(SIGUSR1, SIG_IGN) != SIG_ERR); | ATF_REQUIRE(signal(SIGUSR1, SIG_IGN) != SIG_ERR); | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
CHILD_REQUIRE((kq = kqueue()) > 0); | CHILD_REQUIRE((kq = kqueue()) > 0); | ||||
EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); | EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); | ||||
CHILD_REQUIRE(kevent(kq, &kev, 1, NULL, 0, NULL) == 0); | CHILD_REQUIRE_EQ(kevent(kq, &kev, 1, NULL, 0, NULL), 0); | ||||
trace_me(); | trace_me(); | ||||
for (;;) { | for (;;) { | ||||
nevents = kevent(kq, NULL, 0, &kev, 1, NULL); | nevents = kevent(kq, NULL, 0, &kev, 1, NULL); | ||||
if (nevents == -1 && errno == EINTR) | if (nevents == -1 && errno == EINTR) | ||||
continue; | continue; | ||||
CHILD_REQUIRE(nevents > 0); | CHILD_REQUIRE(nevents > 0); | ||||
CHILD_REQUIRE(kev.filter == EVFILT_SIGNAL); | CHILD_REQUIRE_EQ(kev.filter, EVFILT_SIGNAL); | ||||
CHILD_REQUIRE(kev.ident == SIGUSR1); | CHILD_REQUIRE_EQ(kev.ident, SIGUSR1); | ||||
break; | break; | ||||
} | } | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Continue with the SIGUSR1. */ | /* Continue with the SIGUSR1. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0); | ||||
/* | /* | ||||
* The last wait() should report normal exit with code 1. | * The last wait() should report normal exit with code 1. | ||||
*/ | */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
static void * | static void * | ||||
signal_thread(void *arg) | signal_thread(void *arg) | ||||
{ | { | ||||
int err; | int err; | ||||
sigset_t sigmask; | sigset_t sigmask; | ||||
pthread_barrier_t *pbarrier = (pthread_barrier_t*)arg; | pthread_barrier_t *pbarrier = (pthread_barrier_t*)arg; | ||||
/* Wait for this thread to receive a SIGUSR1. */ | /* Wait for this thread to receive a SIGUSR1. */ | ||||
do { | do { | ||||
err = sem_wait(&sigusr1_sem); | err = sem_wait(&sigusr1_sem); | ||||
CHILD_REQUIRE(err == 0 || errno == EINTR); | CHILD_REQUIRE(err == 0 || errno == EINTR); | ||||
} while (err != 0 && errno == EINTR); | } while (err != 0 && errno == EINTR); | ||||
/* Free our companion thread from the barrier. */ | /* Free our companion thread from the barrier. */ | ||||
pthread_barrier_wait(pbarrier); | pthread_barrier_wait(pbarrier); | ||||
/* | /* | ||||
* Swap ignore duties; the next SIGUSR1 should go to the | * Swap ignore duties; the next SIGUSR1 should go to the | ||||
* other thread. | * other thread. | ||||
*/ | */ | ||||
CHILD_REQUIRE(sigemptyset(&sigmask) == 0); | CHILD_REQUIRE_EQ(sigemptyset(&sigmask), 0); | ||||
CHILD_REQUIRE(sigaddset(&sigmask, SIGUSR1) == 0); | CHILD_REQUIRE_EQ(sigaddset(&sigmask, SIGUSR1), 0); | ||||
CHILD_REQUIRE(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == 0); | CHILD_REQUIRE_EQ(pthread_sigmask(SIG_BLOCK, &sigmask, NULL), 0); | ||||
/* Sync up threads after swapping signal masks. */ | /* Sync up threads after swapping signal masks. */ | ||||
pthread_barrier_wait(pbarrier); | pthread_barrier_wait(pbarrier); | ||||
/* Wait until our companion has received its SIGUSR1. */ | /* Wait until our companion has received its SIGUSR1. */ | ||||
pthread_barrier_wait(pbarrier); | pthread_barrier_wait(pbarrier); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
/* | /* | ||||
* Verify that a traced process with blocked signal received the | * Verify that a traced process with blocked signal received the | ||||
* signal from kill() once unmasked. | * signal from kill() once unmasked. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__killed_with_sigmask); | ATF_TC_WITHOUT_HEAD(ptrace__killed_with_sigmask); | ||||
ATF_TC_BODY(ptrace__killed_with_sigmask, tc) | ATF_TC_BODY(ptrace__killed_with_sigmask, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int status, err; | int status, err; | ||||
sigset_t sigmask; | sigset_t sigmask; | ||||
ATF_REQUIRE(sem_init(&sigusr1_sem, 0, 0) == 0); | REQUIRE_EQ(sem_init(&sigusr1_sem, 0, 0), 0); | ||||
ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR); | ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR); | ||||
got_usr1 = 0; | got_usr1 = 0; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
CHILD_REQUIRE(sigemptyset(&sigmask) == 0); | CHILD_REQUIRE_EQ(sigemptyset(&sigmask), 0); | ||||
CHILD_REQUIRE(sigaddset(&sigmask, SIGUSR1) == 0); | CHILD_REQUIRE_EQ(sigaddset(&sigmask, SIGUSR1), 0); | ||||
CHILD_REQUIRE(sigprocmask(SIG_BLOCK, &sigmask, NULL) == 0); | CHILD_REQUIRE_EQ(sigprocmask(SIG_BLOCK, &sigmask, NULL), 0); | ||||
trace_me(); | trace_me(); | ||||
CHILD_REQUIRE(got_usr1 == 0); | CHILD_REQUIRE_EQ(got_usr1, 0); | ||||
/* Allow the pending SIGUSR1 in now. */ | /* Allow the pending SIGUSR1 in now. */ | ||||
CHILD_REQUIRE(sigprocmask(SIG_UNBLOCK, &sigmask, NULL) == 0); | CHILD_REQUIRE_EQ(sigprocmask(SIG_UNBLOCK, &sigmask, NULL), 0); | ||||
/* Wait to receive a SIGUSR1. */ | /* Wait to receive a SIGUSR1. */ | ||||
do { | do { | ||||
err = sem_wait(&sigusr1_sem); | err = sem_wait(&sigusr1_sem); | ||||
CHILD_REQUIRE(err == 0 || errno == EINTR); | CHILD_REQUIRE(err == 0 || errno == EINTR); | ||||
} while (err != 0 && errno == EINTR); | } while (err != 0 && errno == EINTR); | ||||
CHILD_REQUIRE(got_usr1 == 1); | CHILD_REQUIRE_EQ(got_usr1, 1); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGSTOP); | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGSTOP); | ||||
/* Send blocked SIGUSR1 which should cause a stop. */ | /* Send blocked SIGUSR1 which should cause a stop. */ | ||||
ATF_REQUIRE(kill(fpid, SIGUSR1) == 0); | REQUIRE_EQ(kill(fpid, SIGUSR1), 0); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The next wait() should report the kill(SIGUSR1) was received. */ | /* The next wait() should report the kill(SIGUSR1) was received. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGUSR1); | REQUIRE_EQ(WSTOPSIG(status), SIGUSR1); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGUSR1); | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGUSR1); | ||||
/* Continue the child, allowing in the SIGUSR1. */ | /* Continue the child, allowing in the SIGUSR1. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0); | ||||
/* The last wait() should report normal exit with code 1. */ | /* The last wait() should report normal exit with code 1. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that a traced process with blocked signal received the | * Verify that a traced process with blocked signal received the | ||||
* signal from PT_CONTINUE once unmasked. | * signal from PT_CONTINUE once unmasked. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_sigmask); | ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_sigmask); | ||||
ATF_TC_BODY(ptrace__PT_CONTINUE_with_sigmask, tc) | ATF_TC_BODY(ptrace__PT_CONTINUE_with_sigmask, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int status, err; | int status, err; | ||||
sigset_t sigmask; | sigset_t sigmask; | ||||
ATF_REQUIRE(sem_init(&sigusr1_sem, 0, 0) == 0); | REQUIRE_EQ(sem_init(&sigusr1_sem, 0, 0), 0); | ||||
ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR); | ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR); | ||||
got_usr1 = 0; | got_usr1 = 0; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
CHILD_REQUIRE(sigemptyset(&sigmask) == 0); | CHILD_REQUIRE_EQ(sigemptyset(&sigmask), 0); | ||||
CHILD_REQUIRE(sigaddset(&sigmask, SIGUSR1) == 0); | CHILD_REQUIRE_EQ(sigaddset(&sigmask, SIGUSR1), 0); | ||||
CHILD_REQUIRE(sigprocmask(SIG_BLOCK, &sigmask, NULL) == 0); | CHILD_REQUIRE_EQ(sigprocmask(SIG_BLOCK, &sigmask, NULL), 0); | ||||
trace_me(); | trace_me(); | ||||
CHILD_REQUIRE(got_usr1 == 0); | CHILD_REQUIRE_EQ(got_usr1, 0); | ||||
/* Allow the pending SIGUSR1 in now. */ | /* Allow the pending SIGUSR1 in now. */ | ||||
CHILD_REQUIRE(sigprocmask(SIG_UNBLOCK, &sigmask, NULL) == 0); | CHILD_REQUIRE_EQ(sigprocmask(SIG_UNBLOCK, &sigmask, NULL), 0); | ||||
/* Wait to receive a SIGUSR1. */ | /* Wait to receive a SIGUSR1. */ | ||||
do { | do { | ||||
err = sem_wait(&sigusr1_sem); | err = sem_wait(&sigusr1_sem); | ||||
CHILD_REQUIRE(err == 0 || errno == EINTR); | CHILD_REQUIRE(err == 0 || errno == EINTR); | ||||
} while (err != 0 && errno == EINTR); | } while (err != 0 && errno == EINTR); | ||||
CHILD_REQUIRE(got_usr1 == 1); | CHILD_REQUIRE_EQ(got_usr1, 1); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGSTOP); | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGSTOP); | ||||
/* Continue the child replacing SIGSTOP with SIGUSR1. */ | /* Continue the child replacing SIGSTOP with SIGUSR1. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0); | ||||
/* The next wait() should report the SIGUSR1 was received. */ | /* The next wait() should report the SIGUSR1 was received. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGUSR1); | REQUIRE_EQ(WSTOPSIG(status), SIGUSR1); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGUSR1); | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGUSR1); | ||||
/* Continue the child, ignoring the SIGUSR1. */ | /* Continue the child, ignoring the SIGUSR1. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The last wait() should report normal exit with code 1. */ | /* The last wait() should report normal exit with code 1. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that if ptrace stops due to a signal but continues with | * Verify that if ptrace stops due to a signal but continues with | ||||
* a different signal that the new signal is routed to a thread | * a different signal that the new signal is routed to a thread | ||||
* that can accept it, and that the thread is awakened by the signal | * that can accept it, and that the thread is awakened by the signal | ||||
* in a timely manner. | * in a timely manner. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_thread_sigmask); | ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_thread_sigmask); | ||||
ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_thread_sigmask, tc) | ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_thread_sigmask, tc) | ||||
{ | { | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int status, err; | int status, err; | ||||
pthread_t t; | pthread_t t; | ||||
sigset_t sigmask; | sigset_t sigmask; | ||||
pthread_barrier_t barrier; | pthread_barrier_t barrier; | ||||
ATF_REQUIRE(pthread_barrier_init(&barrier, NULL, 2) == 0); | REQUIRE_EQ(pthread_barrier_init(&barrier, NULL, 2), 0); | ||||
ATF_REQUIRE(sem_init(&sigusr1_sem, 0, 0) == 0); | REQUIRE_EQ(sem_init(&sigusr1_sem, 0, 0), 0); | ||||
ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR); | ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR); | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
CHILD_REQUIRE(pthread_create(&t, NULL, signal_thread, (void*)&barrier) == 0); | CHILD_REQUIRE_EQ(pthread_create(&t, NULL, signal_thread, | ||||
(void *)&barrier), 0); | |||||
/* The other thread should receive the first SIGUSR1. */ | /* The other thread should receive the first SIGUSR1. */ | ||||
CHILD_REQUIRE(sigemptyset(&sigmask) == 0); | CHILD_REQUIRE_EQ(sigemptyset(&sigmask), 0); | ||||
CHILD_REQUIRE(sigaddset(&sigmask, SIGUSR1) == 0); | CHILD_REQUIRE_EQ(sigaddset(&sigmask, SIGUSR1), 0); | ||||
CHILD_REQUIRE(pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == 0); | CHILD_REQUIRE_EQ(pthread_sigmask(SIG_BLOCK, &sigmask, NULL), 0); | ||||
trace_me(); | trace_me(); | ||||
/* Wait until other thread has received its SIGUSR1. */ | /* Wait until other thread has received its SIGUSR1. */ | ||||
pthread_barrier_wait(&barrier); | pthread_barrier_wait(&barrier); | ||||
/* | /* | ||||
* Swap ignore duties; the next SIGUSR1 should go to this | * Swap ignore duties; the next SIGUSR1 should go to this | ||||
* thread. | * thread. | ||||
*/ | */ | ||||
CHILD_REQUIRE(pthread_sigmask(SIG_UNBLOCK, &sigmask, NULL) == 0); | CHILD_REQUIRE_EQ(pthread_sigmask(SIG_UNBLOCK, &sigmask, NULL), | ||||
0); | |||||
/* Sync up threads after swapping signal masks. */ | /* Sync up threads after swapping signal masks. */ | ||||
pthread_barrier_wait(&barrier); | pthread_barrier_wait(&barrier); | ||||
/* | /* | ||||
* Sync up with test code; we're ready for the next SIGUSR1 | * Sync up with test code; we're ready for the next SIGUSR1 | ||||
* now. | * now. | ||||
*/ | */ | ||||
raise(SIGSTOP); | raise(SIGSTOP); | ||||
/* Wait for this thread to receive a SIGUSR1. */ | /* Wait for this thread to receive a SIGUSR1. */ | ||||
do { | do { | ||||
err = sem_wait(&sigusr1_sem); | err = sem_wait(&sigusr1_sem); | ||||
CHILD_REQUIRE(err == 0 || errno == EINTR); | CHILD_REQUIRE(err == 0 || errno == EINTR); | ||||
} while (err != 0 && errno == EINTR); | } while (err != 0 && errno == EINTR); | ||||
/* Free the other thread from the barrier. */ | /* Free the other thread from the barrier. */ | ||||
pthread_barrier_wait(&barrier); | pthread_barrier_wait(&barrier); | ||||
CHILD_REQUIRE(pthread_join(t, NULL) == 0); | CHILD_REQUIRE_EQ(pthread_join(t, NULL), 0); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* | /* | ||||
* Send a signal without ptrace that either thread will accept (USR2, | * Send a signal without ptrace that either thread will accept (USR2, | ||||
* in this case). | * in this case). | ||||
*/ | */ | ||||
ATF_REQUIRE(kill(fpid, SIGUSR2) == 0); | REQUIRE_EQ(kill(fpid, SIGUSR2), 0); | ||||
/* The second wait() should report a SIGUSR2 was received. */ | /* The second wait() should report a SIGUSR2 was received. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGUSR2); | REQUIRE_EQ(WSTOPSIG(status), SIGUSR2); | ||||
/* Continue the child, changing the signal to USR1. */ | /* Continue the child, changing the signal to USR1. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0); | ||||
/* The next wait() should report the stop from SIGSTOP. */ | /* The next wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
ATF_REQUIRE(kill(fpid, SIGUSR2) == 0); | REQUIRE_EQ(kill(fpid, SIGUSR2), 0); | ||||
/* The next wait() should report a SIGUSR2 was received. */ | /* The next wait() should report a SIGUSR2 was received. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGUSR2); | REQUIRE_EQ(WSTOPSIG(status), SIGUSR2); | ||||
/* Continue the child, changing the signal to USR1. */ | /* Continue the child, changing the signal to USR1. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0); | ||||
/* The last wait() should report normal exit with code 1. */ | /* The last wait() should report normal exit with code 1. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
static void * | static void * | ||||
raise_sigstop_thread(void *arg __unused) | raise_sigstop_thread(void *arg __unused) | ||||
{ | { | ||||
raise(SIGSTOP); | raise(SIGSTOP); | ||||
return NULL; | return NULL; | ||||
Show All 15 Lines | terminate_with_pending_sigstop(bool sigstop_from_main_thread) | ||||
cpuset_t setmask; | cpuset_t setmask; | ||||
cpusetid_t setid; | cpusetid_t setid; | ||||
pthread_t t; | pthread_t t; | ||||
/* | /* | ||||
* Become the reaper for this process tree. We need to be able to check | * Become the reaper for this process tree. We need to be able to check | ||||
* that both child and grandchild have died. | * that both child and grandchild have died. | ||||
*/ | */ | ||||
ATF_REQUIRE(procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) == 0); | REQUIRE_EQ(procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL), 0); | ||||
fpid = fork(); | fpid = fork(); | ||||
ATF_REQUIRE(fpid >= 0); | ATF_REQUIRE(fpid >= 0); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
fpid = fork(); | fpid = fork(); | ||||
CHILD_REQUIRE(fpid >= 0); | CHILD_REQUIRE(fpid >= 0); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
/* Pin to CPU 0 to serialize thread execution. */ | /* Pin to CPU 0 to serialize thread execution. */ | ||||
CPU_ZERO(&setmask); | CPU_ZERO(&setmask); | ||||
CPU_SET(0, &setmask); | CPU_SET(0, &setmask); | ||||
CHILD_REQUIRE(cpuset(&setid) == 0); | CHILD_REQUIRE_EQ(cpuset(&setid), 0); | ||||
CHILD_REQUIRE(cpuset_setaffinity(CPU_LEVEL_CPUSET, | CHILD_REQUIRE(cpuset_setaffinity(CPU_LEVEL_CPUSET, | ||||
CPU_WHICH_CPUSET, setid, | CPU_WHICH_CPUSET, setid, | ||||
sizeof(setmask), &setmask) == 0); | sizeof(setmask), &setmask) == 0); | ||||
if (sigstop_from_main_thread) { | if (sigstop_from_main_thread) { | ||||
/* | /* | ||||
* We expect the SIGKILL sent when our parent | * We expect the SIGKILL sent when our parent | ||||
* dies to be delivered to the new thread. | * dies to be delivered to the new thread. | ||||
Show All 14 Lines | if (fpid == 0) { | ||||
raise_sigstop_thread, NULL) == 0); | raise_sigstop_thread, NULL) == 0); | ||||
sleep(60); | sleep(60); | ||||
} | } | ||||
exit(0); | exit(0); | ||||
} | } | ||||
/* First stop is trace_me() immediately after fork. */ | /* First stop is trace_me() immediately after fork. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
CHILD_REQUIRE(wpid == fpid); | CHILD_REQUIRE_EQ(wpid, fpid); | ||||
CHILD_REQUIRE(WIFSTOPPED(status)); | CHILD_REQUIRE(WIFSTOPPED(status)); | ||||
CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP); | CHILD_REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
CHILD_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | CHILD_REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* Second stop is from the raise(SIGSTOP). */ | /* Second stop is from the raise(SIGSTOP). */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
CHILD_REQUIRE(wpid == fpid); | CHILD_REQUIRE_EQ(wpid, fpid); | ||||
CHILD_REQUIRE(WIFSTOPPED(status)); | CHILD_REQUIRE(WIFSTOPPED(status)); | ||||
CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP); | CHILD_REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* | /* | ||||
* Terminate tracing process without detaching. Our child | * Terminate tracing process without detaching. Our child | ||||
* should be killed. | * should be killed. | ||||
*/ | */ | ||||
exit(0); | exit(0); | ||||
} | } | ||||
/* | /* | ||||
* We should get a normal exit from our immediate child and a SIGKILL | * We should get a normal exit from our immediate child and a SIGKILL | ||||
* exit from our grandchild. The latter case is the interesting one. | * exit from our grandchild. The latter case is the interesting one. | ||||
* Our grandchild should not have stopped due to the SIGSTOP that was | * Our grandchild should not have stopped due to the SIGSTOP that was | ||||
* left dangling when its parent died. | * left dangling when its parent died. | ||||
*/ | */ | ||||
for (i = 0; i < 2; ++i) { | for (i = 0; i < 2; ++i) { | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
if (wpid == fpid) | if (wpid == fpid) { | ||||
ATF_REQUIRE(WIFEXITED(status) && | ATF_REQUIRE(WIFEXITED(status)); | ||||
WEXITSTATUS(status) == 0); | REQUIRE_EQ(WEXITSTATUS(status), 0); | ||||
else | } else { | ||||
ATF_REQUIRE(WIFSIGNALED(status) && | ATF_REQUIRE(WIFSIGNALED(status)); | ||||
WTERMSIG(status) == SIGKILL); | REQUIRE_EQ(WTERMSIG(status), SIGKILL); | ||||
} | } | ||||
} | } | ||||
} | |||||
/* | /* | ||||
* These two tests ensure that if the tracing process exits without detaching | * These two tests ensure that if the tracing process exits without detaching | ||||
* just after the child received a SIGSTOP, the child is cleanly killed and | * just after the child received a SIGSTOP, the child is cleanly killed and | ||||
* doesn't go to sleep due to the SIGSTOP. The parent's death will send a | * doesn't go to sleep due to the SIGSTOP. The parent's death will send a | ||||
* SIGKILL to the child. If the SIGKILL and the SIGSTOP are handled by | * SIGKILL to the child. If the SIGKILL and the SIGSTOP are handled by | ||||
* different threads, the SIGKILL must win. There are two variants of this | * different threads, the SIGKILL must win. There are two variants of this | ||||
* test, designed to catch the case where the SIGKILL is delivered to the | * test, designed to catch the case where the SIGKILL is delivered to the | ||||
Show All 40 Lines | ATF_TC_BODY(ptrace__event_mask_sigkill_discard, tc) | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
raise(SIGSTOP); | raise(SIGSTOP); | ||||
exit(0); | exit(0); | ||||
} | } | ||||
/* The first wait() should report the stop from trace_me(). */ | /* The first wait() should report the stop from trace_me(). */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Set several unobtrusive event bits. */ | /* Set several unobtrusive event bits. */ | ||||
event_mask = PTRACE_EXEC | PTRACE_FORK | PTRACE_LWP; | event_mask = PTRACE_EXEC | PTRACE_FORK | PTRACE_LWP; | ||||
ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, wpid, (caddr_t)&event_mask, | ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, wpid, (caddr_t)&event_mask, | ||||
sizeof(event_mask)) == 0); | sizeof(event_mask)) == 0); | ||||
/* Send a SIGKILL without using ptrace. */ | /* Send a SIGKILL without using ptrace. */ | ||||
ATF_REQUIRE(kill(fpid, SIGKILL) == 0); | REQUIRE_EQ(kill(fpid, SIGKILL), 0); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The next stop should be due to the SIGKILL. */ | /* The next stop should be due to the SIGKILL. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGKILL); | REQUIRE_EQ(WSTOPSIG(status), SIGKILL); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGKILL); | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGKILL); | ||||
/* Continue the child ignoring the SIGKILL. */ | /* Continue the child ignoring the SIGKILL. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The next wait() should report the stop from SIGSTOP. */ | /* The next wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Check the current event mask. It should not have changed. */ | /* Check the current event mask. It should not have changed. */ | ||||
new_event_mask = 0; | new_event_mask = 0; | ||||
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, wpid, (caddr_t)&new_event_mask, | ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, wpid, (caddr_t)&new_event_mask, | ||||
sizeof(new_event_mask)) == 0); | sizeof(new_event_mask)) == 0); | ||||
ATF_REQUIRE(event_mask == new_event_mask); | REQUIRE_EQ(event_mask, new_event_mask); | ||||
/* Continue the child to let it exit. */ | /* Continue the child to let it exit. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The last event should be for the child process's exit. */ | /* The last event should be for the child process's exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 0); | REQUIRE_EQ(WEXITSTATUS(status), 0); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
static void * | static void * | ||||
flock_thread(void *arg) | flock_thread(void *arg) | ||||
{ | { | ||||
int fd; | int fd; | ||||
fd = *(int *)arg; | fd = *(int *)arg; | ||||
Show All 11 Lines | |||||
ATF_TC_BODY(ptrace__PT_ATTACH_with_SBDRY_thread, tc) | ATF_TC_BODY(ptrace__PT_ATTACH_with_SBDRY_thread, tc) | ||||
{ | { | ||||
pthread_barrier_t barrier; | pthread_barrier_t barrier; | ||||
pthread_barrierattr_t battr; | pthread_barrierattr_t battr; | ||||
char tmpfile[64]; | char tmpfile[64]; | ||||
pid_t child, wpid; | pid_t child, wpid; | ||||
int error, fd, i, status; | int error, fd, i, status; | ||||
ATF_REQUIRE(pthread_barrierattr_init(&battr) == 0); | REQUIRE_EQ(pthread_barrierattr_init(&battr), 0); | ||||
ATF_REQUIRE(pthread_barrierattr_setpshared(&battr, | ATF_REQUIRE(pthread_barrierattr_setpshared(&battr, | ||||
PTHREAD_PROCESS_SHARED) == 0); | PTHREAD_PROCESS_SHARED) == 0); | ||||
ATF_REQUIRE(pthread_barrier_init(&barrier, &battr, 2) == 0); | REQUIRE_EQ(pthread_barrier_init(&barrier, &battr, 2), 0); | ||||
(void)snprintf(tmpfile, sizeof(tmpfile), "./ptrace.XXXXXX"); | (void)snprintf(tmpfile, sizeof(tmpfile), "./ptrace.XXXXXX"); | ||||
fd = mkstemp(tmpfile); | fd = mkstemp(tmpfile); | ||||
ATF_REQUIRE(fd >= 0); | ATF_REQUIRE(fd >= 0); | ||||
ATF_REQUIRE((child = fork()) != -1); | ATF_REQUIRE((child = fork()) != -1); | ||||
if (child == 0) { | if (child == 0) { | ||||
pthread_t t[2]; | pthread_t t[2]; | ||||
Show All 18 Lines | if (pthread_create(&t[1], NULL, flock_thread, &cfd) != 0) | ||||
_exit(1); | _exit(1); | ||||
if (pthread_join(t[0], NULL) != 0) | if (pthread_join(t[0], NULL) != 0) | ||||
_exit(1); | _exit(1); | ||||
if (pthread_join(t[1], NULL) != 0) | if (pthread_join(t[1], NULL) != 0) | ||||
_exit(1); | _exit(1); | ||||
_exit(0); | _exit(0); | ||||
} | } | ||||
ATF_REQUIRE(flock(fd, LOCK_EX) == 0); | REQUIRE_EQ(flock(fd, LOCK_EX), 0); | ||||
error = pthread_barrier_wait(&barrier); | error = pthread_barrier_wait(&barrier); | ||||
ATF_REQUIRE(error == 0 || error == PTHREAD_BARRIER_SERIAL_THREAD); | ATF_REQUIRE(error == 0 || error == PTHREAD_BARRIER_SERIAL_THREAD); | ||||
/* | /* | ||||
* Give the child some time to block. Is there a better way to do this? | * Give the child some time to block. Is there a better way to do this? | ||||
*/ | */ | ||||
sleep(1); | sleep(1); | ||||
/* | /* | ||||
* Attach and give the child 3 seconds to stop. | * Attach and give the child 3 seconds to stop. | ||||
*/ | */ | ||||
ATF_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) == 0); | REQUIRE_EQ(ptrace(PT_ATTACH, child, NULL, 0), 0); | ||||
for (i = 0; i < 3; i++) { | for (i = 0; i < 3; i++) { | ||||
wpid = waitpid(child, &status, WNOHANG); | wpid = waitpid(child, &status, WNOHANG); | ||||
if (wpid == child && WIFSTOPPED(status) && | if (wpid == child && WIFSTOPPED(status) && | ||||
WSTOPSIG(status) == SIGSTOP) | WSTOPSIG(status) == SIGSTOP) | ||||
break; | break; | ||||
sleep(1); | sleep(1); | ||||
} | } | ||||
ATF_REQUIRE_MSG(i < 3, "failed to stop child process after PT_ATTACH"); | ATF_REQUIRE_MSG(i < 3, "failed to stop child process after PT_ATTACH"); | ||||
ATF_REQUIRE(ptrace(PT_DETACH, child, NULL, 0) == 0); | REQUIRE_EQ(ptrace(PT_DETACH, child, NULL, 0), 0); | ||||
ATF_REQUIRE(flock(fd, LOCK_UN) == 0); | REQUIRE_EQ(flock(fd, LOCK_UN), 0); | ||||
ATF_REQUIRE(unlink(tmpfile) == 0); | REQUIRE_EQ(unlink(tmpfile), 0); | ||||
ATF_REQUIRE(close(fd) == 0); | REQUIRE_EQ(close(fd), 0); | ||||
} | } | ||||
static void | static void | ||||
sigusr1_step_handler(int sig) | sigusr1_step_handler(int sig) | ||||
{ | { | ||||
CHILD_REQUIRE(sig == SIGUSR1); | CHILD_REQUIRE_EQ(sig, SIGUSR1); | ||||
raise(SIGABRT); | raise(SIGABRT); | ||||
} | } | ||||
/* | /* | ||||
* Verify that PT_STEP with a signal invokes the signal before | * Verify that PT_STEP with a signal invokes the signal before | ||||
* stepping the next instruction (and that the next instruction is | * stepping the next instruction (and that the next instruction is | ||||
* stepped correctly). | * stepped correctly). | ||||
*/ | */ | ||||
Show All 9 Lines | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
signal(SIGUSR1, sigusr1_step_handler); | signal(SIGUSR1, sigusr1_step_handler); | ||||
raise(SIGABRT); | raise(SIGABRT); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The next stop should report the SIGABRT in the child body. */ | /* The next stop should report the SIGABRT in the child body. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGABRT); | REQUIRE_EQ(WSTOPSIG(status), SIGABRT); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGABRT); | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGABRT); | ||||
/* Step the child process inserting SIGUSR1. */ | /* Step the child process inserting SIGUSR1. */ | ||||
ATF_REQUIRE(ptrace(PT_STEP, fpid, (caddr_t)1, SIGUSR1) == 0); | REQUIRE_EQ(ptrace(PT_STEP, fpid, (caddr_t)1, SIGUSR1), 0); | ||||
/* The next stop should report the SIGABRT in the signal handler. */ | /* The next stop should report the SIGABRT in the signal handler. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGABRT); | REQUIRE_EQ(WSTOPSIG(status), SIGABRT); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGABRT); | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGABRT); | ||||
/* Continue the child process discarding the signal. */ | /* Continue the child process discarding the signal. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The next stop should report a trace trap from PT_STEP. */ | /* The next stop should report a trace trap from PT_STEP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGTRAP); | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGTRAP); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_code == TRAP_TRACE); | REQUIRE_EQ(pl.pl_siginfo.si_code, TRAP_TRACE); | ||||
/* Continue the child to let it exit. */ | /* Continue the child to let it exit. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The last event should be for the child process's exit. */ | /* The last event should be for the child process's exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
#ifdef HAVE_BREAKPOINT | #ifdef HAVE_BREAKPOINT | ||||
/* | /* | ||||
* Verify that a SIGTRAP event with the TRAP_BRKPT code is reported | * Verify that a SIGTRAP event with the TRAP_BRKPT code is reported | ||||
* for a breakpoint trap. | * for a breakpoint trap. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__breakpoint_siginfo); | ATF_TC_WITHOUT_HEAD(ptrace__breakpoint_siginfo); | ||||
ATF_TC_BODY(ptrace__breakpoint_siginfo, tc) | ATF_TC_BODY(ptrace__breakpoint_siginfo, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int status; | int status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
breakpoint(); | breakpoint(); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The second wait() should report hitting the breakpoint. */ | /* The second wait() should report hitting the breakpoint. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & PL_FLAG_SI) != 0); | ATF_REQUIRE((pl.pl_flags & PL_FLAG_SI) != 0); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGTRAP); | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGTRAP); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_code == TRAP_BRKPT); | REQUIRE_EQ(pl.pl_siginfo.si_code, TRAP_BRKPT); | ||||
/* Kill the child process. */ | /* Kill the child process. */ | ||||
ATF_REQUIRE(ptrace(PT_KILL, fpid, 0, 0) == 0); | REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0); | ||||
/* The last wait() should report the SIGKILL. */ | /* The last wait() should report the SIGKILL. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSIGNALED(status)); | ATF_REQUIRE(WIFSIGNALED(status)); | ||||
ATF_REQUIRE(WTERMSIG(status) == SIGKILL); | REQUIRE_EQ(WTERMSIG(status), SIGKILL); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
#endif /* HAVE_BREAKPOINT */ | #endif /* HAVE_BREAKPOINT */ | ||||
/* | /* | ||||
* Verify that a SIGTRAP event with the TRAP_TRACE code is reported | * Verify that a SIGTRAP event with the TRAP_TRACE code is reported | ||||
* for a single-step trap from PT_STEP. | * for a single-step trap from PT_STEP. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__step_siginfo); | ATF_TC_WITHOUT_HEAD(ptrace__step_siginfo); | ||||
ATF_TC_BODY(ptrace__step_siginfo, tc) | ATF_TC_BODY(ptrace__step_siginfo, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int status; | int status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Step the child ignoring the SIGSTOP. */ | /* Step the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_STEP, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_STEP, fpid, (caddr_t)1, 0), 0); | ||||
/* The second wait() should report a single-step trap. */ | /* The second wait() should report a single-step trap. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & PL_FLAG_SI) != 0); | ATF_REQUIRE((pl.pl_flags & PL_FLAG_SI) != 0); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGTRAP); | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGTRAP); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_code == TRAP_TRACE); | REQUIRE_EQ(pl.pl_siginfo.si_code, TRAP_TRACE); | ||||
/* Continue the child process. */ | /* Continue the child process. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The last event should be for the child process's exit. */ | /* The last event should be for the child process's exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
#if defined(HAVE_BREAKPOINT) && defined(SKIP_BREAK) | #if defined(HAVE_BREAKPOINT) && defined(SKIP_BREAK) | ||||
static void * | static void * | ||||
continue_thread(void *arg __unused) | continue_thread(void *arg __unused) | ||||
{ | { | ||||
breakpoint(); | breakpoint(); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
static __dead2 void | static __dead2 void | ||||
continue_thread_main(void) | continue_thread_main(void) | ||||
{ | { | ||||
pthread_t threads[2]; | pthread_t threads[2]; | ||||
CHILD_REQUIRE(pthread_create(&threads[0], NULL, continue_thread, | CHILD_REQUIRE(pthread_create(&threads[0], NULL, continue_thread, | ||||
NULL) == 0); | NULL) == 0); | ||||
CHILD_REQUIRE(pthread_create(&threads[1], NULL, continue_thread, | CHILD_REQUIRE(pthread_create(&threads[1], NULL, continue_thread, | ||||
NULL) == 0); | NULL) == 0); | ||||
CHILD_REQUIRE(pthread_join(threads[0], NULL) == 0); | CHILD_REQUIRE_EQ(pthread_join(threads[0], NULL), 0); | ||||
CHILD_REQUIRE(pthread_join(threads[1], NULL) == 0); | CHILD_REQUIRE_EQ(pthread_join(threads[1], NULL), 0); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* | /* | ||||
* Ensure that PT_CONTINUE clears the status of the thread that | * Ensure that PT_CONTINUE clears the status of the thread that | ||||
* triggered the stop even if a different thread's LWP was passed to | * triggered the stop even if a different thread's LWP was passed to | ||||
* PT_CONTINUE. | * PT_CONTINUE. | ||||
*/ | */ | ||||
Show All 10 Lines | ATF_TC_BODY(ptrace__PT_CONTINUE_different_thread, tc) | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
continue_thread_main(); | continue_thread_main(); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ||||
sizeof(pl)) != -1); | sizeof(pl)) != -1); | ||||
ATF_REQUIRE(ptrace(PT_LWP_EVENTS, wpid, NULL, 1) == 0); | REQUIRE_EQ(ptrace(PT_LWP_EVENTS, wpid, NULL, 1), 0); | ||||
/* Continue the child ignoring the SIGSTOP. */ | /* Continue the child ignoring the SIGSTOP. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* One of the new threads should report it's birth. */ | /* One of the new threads should report it's birth. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)) == | REQUIRE_EQ((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)), | ||||
(PL_FLAG_BORN | PL_FLAG_SCX)); | (PL_FLAG_BORN | PL_FLAG_SCX)); | ||||
lwps[0] = pl.pl_lwpid; | lwps[0] = pl.pl_lwpid; | ||||
/* | /* | ||||
* Suspend this thread to ensure both threads are alive before | * Suspend this thread to ensure both threads are alive before | ||||
* hitting the breakpoint. | * hitting the breakpoint. | ||||
*/ | */ | ||||
ATF_REQUIRE(ptrace(PT_SUSPEND, lwps[0], NULL, 0) != -1); | ATF_REQUIRE(ptrace(PT_SUSPEND, lwps[0], NULL, 0) != -1); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* Second thread should report it's birth. */ | /* Second thread should report it's birth. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)) == | REQUIRE_EQ((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)), | ||||
(PL_FLAG_BORN | PL_FLAG_SCX)); | (PL_FLAG_BORN | PL_FLAG_SCX)); | ||||
ATF_REQUIRE(pl.pl_lwpid != lwps[0]); | ATF_REQUIRE(pl.pl_lwpid != lwps[0]); | ||||
lwps[1] = pl.pl_lwpid; | lwps[1] = pl.pl_lwpid; | ||||
/* Resume both threads waiting for breakpoint events. */ | /* Resume both threads waiting for breakpoint events. */ | ||||
hit_break[0] = hit_break[1] = false; | hit_break[0] = hit_break[1] = false; | ||||
ATF_REQUIRE(ptrace(PT_RESUME, lwps[0], NULL, 0) != -1); | ATF_REQUIRE(ptrace(PT_RESUME, lwps[0], NULL, 0) != -1); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* One thread should report a breakpoint. */ | /* One thread should report a breakpoint. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE((pl.pl_flags & PL_FLAG_SI) != 0); | ATF_REQUIRE((pl.pl_flags & PL_FLAG_SI) != 0); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGTRAP && | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGTRAP); | ||||
pl.pl_siginfo.si_code == TRAP_BRKPT); | REQUIRE_EQ(pl.pl_siginfo.si_code, TRAP_BRKPT); | ||||
if (pl.pl_lwpid == lwps[0]) | if (pl.pl_lwpid == lwps[0]) | ||||
i = 0; | i = 0; | ||||
else | else | ||||
i = 1; | i = 1; | ||||
hit_break[i] = true; | hit_break[i] = true; | ||||
ATF_REQUIRE(ptrace(PT_GETREGS, pl.pl_lwpid, (caddr_t)®, 0) != -1); | ATF_REQUIRE(ptrace(PT_GETREGS, pl.pl_lwpid, (caddr_t)®, 0) != -1); | ||||
SKIP_BREAK(®); | SKIP_BREAK(®); | ||||
ATF_REQUIRE(ptrace(PT_SETREGS, pl.pl_lwpid, (caddr_t)®, 0) != -1); | ATF_REQUIRE(ptrace(PT_SETREGS, pl.pl_lwpid, (caddr_t)®, 0) != -1); | ||||
/* | /* | ||||
* Resume both threads but pass the other thread's LWPID to | * Resume both threads but pass the other thread's LWPID to | ||||
* PT_CONTINUE. | * PT_CONTINUE. | ||||
*/ | */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, lwps[i ^ 1], (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, lwps[i ^ 1], (caddr_t)1, 0), 0); | ||||
/* | /* | ||||
* Will now get two thread exit events and one more breakpoint | * Will now get two thread exit events and one more breakpoint | ||||
* event. | * event. | ||||
*/ | */ | ||||
for (j = 0; j < 3; j++) { | for (j = 0; j < 3; j++) { | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, | ||||
sizeof(pl)) != -1); | sizeof(pl)) != -1); | ||||
if (pl.pl_lwpid == lwps[0]) | if (pl.pl_lwpid == lwps[0]) | ||||
i = 0; | i = 0; | ||||
else | else | ||||
i = 1; | i = 1; | ||||
ATF_REQUIRE_MSG(lwps[i] != 0, "event for exited thread"); | ATF_REQUIRE_MSG(lwps[i] != 0, "event for exited thread"); | ||||
if (pl.pl_flags & PL_FLAG_EXITED) { | if (pl.pl_flags & PL_FLAG_EXITED) { | ||||
ATF_REQUIRE_MSG(hit_break[i], | ATF_REQUIRE_MSG(hit_break[i], | ||||
"exited thread did not report breakpoint"); | "exited thread did not report breakpoint"); | ||||
lwps[i] = 0; | lwps[i] = 0; | ||||
} else { | } else { | ||||
ATF_REQUIRE((pl.pl_flags & PL_FLAG_SI) != 0); | ATF_REQUIRE((pl.pl_flags & PL_FLAG_SI) != 0); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGTRAP && | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGTRAP); | ||||
pl.pl_siginfo.si_code == TRAP_BRKPT); | REQUIRE_EQ(pl.pl_siginfo.si_code, TRAP_BRKPT); | ||||
ATF_REQUIRE_MSG(!hit_break[i], | ATF_REQUIRE_MSG(!hit_break[i], | ||||
"double breakpoint event"); | "double breakpoint event"); | ||||
hit_break[i] = true; | hit_break[i] = true; | ||||
ATF_REQUIRE(ptrace(PT_GETREGS, pl.pl_lwpid, (caddr_t)®, | ATF_REQUIRE(ptrace(PT_GETREGS, pl.pl_lwpid, (caddr_t)®, | ||||
0) != -1); | 0) != -1); | ||||
SKIP_BREAK(®); | SKIP_BREAK(®); | ||||
ATF_REQUIRE(ptrace(PT_SETREGS, pl.pl_lwpid, (caddr_t)®, | ATF_REQUIRE(ptrace(PT_SETREGS, pl.pl_lwpid, (caddr_t)®, | ||||
0) != -1); | 0) != -1); | ||||
} | } | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
} | } | ||||
/* Both threads should have exited. */ | /* Both threads should have exited. */ | ||||
ATF_REQUIRE(lwps[0] == 0); | REQUIRE_EQ(lwps[0], 0); | ||||
ATF_REQUIRE(lwps[1] == 0); | REQUIRE_EQ(lwps[1], 0); | ||||
/* The last event should be for the child process's exit. */ | /* The last event should be for the child process's exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
* Verify that PT_LWPINFO doesn't return stale siginfo. | * Verify that PT_LWPINFO doesn't return stale siginfo. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__PT_LWPINFO_stale_siginfo); | ATF_TC_WITHOUT_HEAD(ptrace__PT_LWPINFO_stale_siginfo); | ||||
ATF_TC_BODY(ptrace__PT_LWPINFO_stale_siginfo, tc) | ATF_TC_BODY(ptrace__PT_LWPINFO_stale_siginfo, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
int events, status; | int events, status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
raise(SIGABRT); | raise(SIGABRT); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The next stop should report the SIGABRT in the child body. */ | /* The next stop should report the SIGABRT in the child body. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGABRT); | REQUIRE_EQ(WSTOPSIG(status), SIGABRT); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI); | ||||
ATF_REQUIRE(pl.pl_siginfo.si_signo == SIGABRT); | REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGABRT); | ||||
/* | /* | ||||
* Continue the process ignoring the signal, but enabling | * Continue the process ignoring the signal, but enabling | ||||
* syscall traps. | * syscall traps. | ||||
*/ | */ | ||||
ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0); | ||||
/* | /* | ||||
* The next stop should report a system call entry from | * The next stop should report a system call entry from | ||||
* exit(). PL_FLAGS_SI should not be set. | * exit(). PL_FLAGS_SI should not be set. | ||||
*/ | */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ||||
ATF_REQUIRE((pl.pl_flags & PL_FLAG_SI) == 0); | REQUIRE_EQ((pl.pl_flags & PL_FLAG_SI), 0); | ||||
/* Disable syscall tracing and continue the child to let it exit. */ | /* Disable syscall tracing and continue the child to let it exit. */ | ||||
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events, | ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events, | ||||
sizeof(events)) == 0); | sizeof(events)) == 0); | ||||
events &= ~PTRACE_SYSCALL; | events &= ~PTRACE_SYSCALL; | ||||
ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events, | ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events, | ||||
sizeof(events)) == 0); | sizeof(events)) == 0); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The last event should be for the child process's exit. */ | /* The last event should be for the child process's exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* A simple test of PT_GET_SC_ARGS and PT_GET_SC_RET. | * A simple test of PT_GET_SC_ARGS and PT_GET_SC_RET. | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__syscall_args); | ATF_TC_WITHOUT_HEAD(ptrace__syscall_args); | ||||
ATF_TC_BODY(ptrace__syscall_args, tc) | ATF_TC_BODY(ptrace__syscall_args, tc) | ||||
{ | { | ||||
struct ptrace_lwpinfo pl; | struct ptrace_lwpinfo pl; | ||||
struct ptrace_sc_ret psr; | struct ptrace_sc_ret psr; | ||||
pid_t fpid, wpid; | pid_t fpid, wpid; | ||||
register_t args[2]; | register_t args[2]; | ||||
int events, status; | int events, status; | ||||
ATF_REQUIRE((fpid = fork()) != -1); | ATF_REQUIRE((fpid = fork()) != -1); | ||||
if (fpid == 0) { | if (fpid == 0) { | ||||
trace_me(); | trace_me(); | ||||
kill(getpid(), 0); | kill(getpid(), 0); | ||||
close(3); | close(3); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* The first wait() should report the stop from SIGSTOP. */ | /* The first wait() should report the stop from SIGSTOP. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* | /* | ||||
* Continue the process ignoring the signal, but enabling | * Continue the process ignoring the signal, but enabling | ||||
* syscall traps. | * syscall traps. | ||||
*/ | */ | ||||
ATF_REQUIRE(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0); | ||||
/* | /* | ||||
* The next stop should be the syscall entry from getpid(). | * The next stop should be the syscall entry from getpid(). | ||||
*/ | */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ||||
ATF_REQUIRE(pl.pl_syscall_code == SYS_getpid); | REQUIRE_EQ(pl.pl_syscall_code, SYS_getpid); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* | /* | ||||
* The next stop should be the syscall exit from getpid(). | * The next stop should be the syscall exit from getpid(). | ||||
*/ | */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX); | ||||
ATF_REQUIRE(pl.pl_syscall_code == SYS_getpid); | REQUIRE_EQ(pl.pl_syscall_code, SYS_getpid); | ||||
ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr, | ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr, | ||||
sizeof(psr)) != -1); | sizeof(psr)) != -1); | ||||
ATF_REQUIRE(psr.sr_error == 0); | REQUIRE_EQ(psr.sr_error, 0); | ||||
ATF_REQUIRE(psr.sr_retval[0] == wpid); | REQUIRE_EQ(psr.sr_retval[0], wpid); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* | /* | ||||
* The next stop should be the syscall entry from kill(). | * The next stop should be the syscall entry from kill(). | ||||
*/ | */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ||||
ATF_REQUIRE(pl.pl_syscall_code == SYS_kill); | REQUIRE_EQ(pl.pl_syscall_code, SYS_kill); | ||||
ATF_REQUIRE(pl.pl_syscall_narg == 2); | REQUIRE_EQ(pl.pl_syscall_narg, 2); | ||||
ATF_REQUIRE(ptrace(PT_GET_SC_ARGS, wpid, (caddr_t)args, | ATF_REQUIRE(ptrace(PT_GET_SC_ARGS, wpid, (caddr_t)args, | ||||
sizeof(args)) != -1); | sizeof(args)) != -1); | ||||
ATF_REQUIRE(args[0] == wpid); | REQUIRE_EQ(args[0], wpid); | ||||
ATF_REQUIRE(args[1] == 0); | REQUIRE_EQ(args[1], 0); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* | /* | ||||
* The next stop should be the syscall exit from kill(). | * The next stop should be the syscall exit from kill(). | ||||
*/ | */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX); | ||||
ATF_REQUIRE(pl.pl_syscall_code == SYS_kill); | REQUIRE_EQ(pl.pl_syscall_code, SYS_kill); | ||||
ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr, | ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr, | ||||
sizeof(psr)) != -1); | sizeof(psr)) != -1); | ||||
ATF_REQUIRE(psr.sr_error == 0); | REQUIRE_EQ(psr.sr_error, 0); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* | /* | ||||
* The next stop should be the syscall entry from close(). | * The next stop should be the syscall entry from close(). | ||||
*/ | */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE); | ||||
ATF_REQUIRE(pl.pl_syscall_code == SYS_close); | REQUIRE_EQ(pl.pl_syscall_code, SYS_close); | ||||
ATF_REQUIRE(pl.pl_syscall_narg == 1); | REQUIRE_EQ(pl.pl_syscall_narg, 1); | ||||
ATF_REQUIRE(ptrace(PT_GET_SC_ARGS, wpid, (caddr_t)args, | ATF_REQUIRE(ptrace(PT_GET_SC_ARGS, wpid, (caddr_t)args, | ||||
sizeof(args)) != -1); | sizeof(args)) != -1); | ||||
ATF_REQUIRE(args[0] == 3); | REQUIRE_EQ(args[0], 3); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* | /* | ||||
* The next stop should be the syscall exit from close(). | * The next stop should be the syscall exit from close(). | ||||
*/ | */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(wpid == fpid); | REQUIRE_EQ(wpid, fpid); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); | REQUIRE_EQ(WSTOPSIG(status), SIGTRAP); | ||||
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); | ||||
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX); | ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX); | ||||
ATF_REQUIRE(pl.pl_syscall_code == SYS_close); | REQUIRE_EQ(pl.pl_syscall_code, SYS_close); | ||||
ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr, | ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr, | ||||
sizeof(psr)) != -1); | sizeof(psr)) != -1); | ||||
ATF_REQUIRE(psr.sr_error == EBADF); | REQUIRE_EQ(psr.sr_error, EBADF); | ||||
/* Disable syscall tracing and continue the child to let it exit. */ | /* Disable syscall tracing and continue the child to let it exit. */ | ||||
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events, | ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events, | ||||
sizeof(events)) == 0); | sizeof(events)) == 0); | ||||
events &= ~PTRACE_SYSCALL; | events &= ~PTRACE_SYSCALL; | ||||
ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events, | ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events, | ||||
sizeof(events)) == 0); | sizeof(events)) == 0); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0); | ||||
/* The last event should be for the child process's exit. */ | /* The last event should be for the child process's exit. */ | ||||
wpid = waitpid(fpid, &status, 0); | wpid = waitpid(fpid, &status, 0); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 1); | REQUIRE_EQ(WEXITSTATUS(status), 1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Verify that when the process is traced that it isn't reparent | * Verify that when the process is traced that it isn't reparent | ||||
* to the init process when we close all process descriptors. | * to the init process when we close all process descriptors. | ||||
*/ | */ | ||||
ATF_TC(ptrace__proc_reparent); | ATF_TC(ptrace__proc_reparent); | ||||
ATF_TC_HEAD(ptrace__proc_reparent, tc) | ATF_TC_HEAD(ptrace__proc_reparent, tc) | ||||
Show All 13 Lines | if (traced == 0) { | ||||
exit(0); | exit(0); | ||||
} | } | ||||
ATF_REQUIRE(pd >= 0); | ATF_REQUIRE(pd >= 0); | ||||
debuger = fork(); | debuger = fork(); | ||||
ATF_REQUIRE(debuger >= 0); | ATF_REQUIRE(debuger >= 0); | ||||
if (debuger == 0) { | if (debuger == 0) { | ||||
/* The traced process is reparented to debuger. */ | /* The traced process is reparented to debuger. */ | ||||
ATF_REQUIRE(ptrace(PT_ATTACH, traced, 0, 0) == 0); | REQUIRE_EQ(ptrace(PT_ATTACH, traced, 0, 0), 0); | ||||
wpid = waitpid(traced, &status, 0); | wpid = waitpid(traced, &status, 0); | ||||
ATF_REQUIRE(wpid == traced); | REQUIRE_EQ(wpid, traced); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(close(pd) == 0); | REQUIRE_EQ(close(pd), 0); | ||||
ATF_REQUIRE(ptrace(PT_DETACH, traced, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_DETACH, traced, (caddr_t)1, 0), 0); | ||||
/* We closed pd so we should not have any child. */ | /* We closed pd so we should not have any child. */ | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
exit(0); | exit(0); | ||||
} | } | ||||
ATF_REQUIRE(close(pd) == 0); | REQUIRE_EQ(close(pd), 0); | ||||
wpid = waitpid(debuger, &status, 0); | wpid = waitpid(debuger, &status, 0); | ||||
ATF_REQUIRE(wpid == debuger); | REQUIRE_EQ(wpid, debuger); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 0); | REQUIRE_EQ(WEXITSTATUS(status), 0); | ||||
/* Check if we still have any child. */ | /* Check if we still have any child. */ | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
} | } | ||||
/* | /* | ||||
* Ensure that traced processes created with pdfork(2) are visible to | * Ensure that traced processes created with pdfork(2) are visible to | ||||
* waitid(P_ALL). | * waitid(P_ALL). | ||||
*/ | */ | ||||
ATF_TC_WITHOUT_HEAD(ptrace__procdesc_wait_child); | ATF_TC_WITHOUT_HEAD(ptrace__procdesc_wait_child); | ||||
ATF_TC_BODY(ptrace__procdesc_wait_child, tc) | ATF_TC_BODY(ptrace__procdesc_wait_child, tc) | ||||
{ | { | ||||
pid_t child, wpid; | pid_t child, wpid; | ||||
int pd, status; | int pd, status; | ||||
child = pdfork(&pd, 0); | child = pdfork(&pd, 0); | ||||
ATF_REQUIRE(child >= 0); | ATF_REQUIRE(child >= 0); | ||||
if (child == 0) { | if (child == 0) { | ||||
trace_me(); | trace_me(); | ||||
(void)raise(SIGSTOP); | (void)raise(SIGSTOP); | ||||
exit(0); | exit(0); | ||||
} | } | ||||
wpid = waitpid(child, &status, 0); | wpid = waitpid(child, &status, 0); | ||||
ATF_REQUIRE(wpid == child); | REQUIRE_EQ(wpid, child); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == child); | REQUIRE_EQ(wpid, child); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); | ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); | ||||
/* | /* | ||||
* If process was created by pdfork, the return code have to | * If process was created by pdfork, the return code have to | ||||
* be collected through process descriptor. | * be collected through process descriptor. | ||||
*/ | */ | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
ATF_REQUIRE(close(pd) != -1); | ATF_REQUIRE(close(pd) != -1); | ||||
} | } | ||||
/* | /* | ||||
* Ensure that traced processes created with pdfork(2) are not visible | * Ensure that traced processes created with pdfork(2) are not visible | ||||
* after returning to parent - waitid(P_ALL). | * after returning to parent - waitid(P_ALL). | ||||
*/ | */ | ||||
Show All 13 Lines | if (traced == 0) { | ||||
exit(0); | exit(0); | ||||
} | } | ||||
ATF_REQUIRE(pd >= 0); | ATF_REQUIRE(pd >= 0); | ||||
debuger = fork(); | debuger = fork(); | ||||
ATF_REQUIRE(debuger >= 0); | ATF_REQUIRE(debuger >= 0); | ||||
if (debuger == 0) { | if (debuger == 0) { | ||||
/* The traced process is reparented to debuger. */ | /* The traced process is reparented to debuger. */ | ||||
ATF_REQUIRE(ptrace(PT_ATTACH, traced, 0, 0) == 0); | REQUIRE_EQ(ptrace(PT_ATTACH, traced, 0, 0), 0); | ||||
wpid = waitpid(traced, &status, 0); | wpid = waitpid(traced, &status, 0); | ||||
ATF_REQUIRE(wpid == traced); | REQUIRE_EQ(wpid, traced); | ||||
ATF_REQUIRE(WIFSTOPPED(status)); | ATF_REQUIRE(WIFSTOPPED(status)); | ||||
ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); | REQUIRE_EQ(WSTOPSIG(status), SIGSTOP); | ||||
/* Allow process to die. */ | /* Allow process to die. */ | ||||
ATF_REQUIRE(ptrace(PT_CONTINUE, traced, (caddr_t)1, 0) == 0); | REQUIRE_EQ(ptrace(PT_CONTINUE, traced, (caddr_t)1, 0), 0); | ||||
wpid = waitpid(traced, &status, 0); | wpid = waitpid(traced, &status, 0); | ||||
ATF_REQUIRE(wpid == traced); | REQUIRE_EQ(wpid, traced); | ||||
ATF_REQUIRE(WIFEXITED(status)); | ATF_REQUIRE(WIFEXITED(status)); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 0); | REQUIRE_EQ(WEXITSTATUS(status), 0); | ||||
/* Reparent back to the orginal process. */ | /* Reparent back to the orginal process. */ | ||||
ATF_REQUIRE(close(pd) == 0); | REQUIRE_EQ(close(pd), 0); | ||||
exit(0); | exit(0); | ||||
} | } | ||||
wpid = waitpid(debuger, &status, 0); | wpid = waitpid(debuger, &status, 0); | ||||
ATF_REQUIRE(wpid == debuger); | REQUIRE_EQ(wpid, debuger); | ||||
ATF_REQUIRE(WEXITSTATUS(status) == 0); | REQUIRE_EQ(WEXITSTATUS(status), 0); | ||||
/* | /* | ||||
* We have a child but it has a process descriptori | * We have a child but it has a process descriptori | ||||
* so we should not be able to collect it process. | * so we should not be able to collect it process. | ||||
*/ | */ | ||||
wpid = wait(&status); | wpid = wait(&status); | ||||
ATF_REQUIRE(wpid == -1); | REQUIRE_EQ(wpid, -1); | ||||
ATF_REQUIRE(errno == ECHILD); | REQUIRE_EQ(errno, ECHILD); | ||||
ATF_REQUIRE(close(pd) == 0); | REQUIRE_EQ(close(pd), 0); | ||||
} | } | ||||
ATF_TP_ADD_TCS(tp) | ATF_TP_ADD_TCS(tp) | ||||
{ | { | ||||
ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_trace_me); | ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_trace_me); | ||||
ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_attach); | ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_attach); | ||||
ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_child_debugger); | ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_child_debugger); | ||||
▲ Show 20 Lines • Show All 62 Lines • Show Last 20 Lines |
I would be tempted to drop the _INT suffix since you are using __typeof__, etc. I would otherwise read _INT as meaning the arguments are of type int.