#include <sys/types.h>
#include <sys/cpuset.h>
#include <sys/elf.h>
#include <sys/event.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/procctl.h>
#include <sys/procdesc.h>
#include <sys/ptrace.h>
#include <sys/procfs.h>
#include <sys/queue.h>
#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <errno.h>
#include <machine/cpufunc.h>
#include <pthread.h>
#include <sched.h>
#include <semaphore.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <atf-c.h>
#if defined(__aarch64__) || defined(__amd64__) || defined(__arm__) || \
defined(__i386__) || defined(__riscv)
#define HAVE_BREAKPOINT
#endif
#ifdef HAVE_BREAKPOINT
#if defined(__aarch64__)
#define SKIP_BREAK(reg) ((reg)->elr += 4)
#elif defined(__amd64__) || defined(__i386__)
#define SKIP_BREAK(reg)
#elif defined(__arm__)
#define SKIP_BREAK(reg) ((reg)->r_pc += 4)
#elif defined(__riscv)
#define SKIP_BREAK(reg) ((reg)->sepc += 4)
#endif
#endif
#define CHILD_REQUIRE(exp) do { \
if (!(exp)) \
child_fail_require(__FILE__, __LINE__, \
#exp " not met\n"); \
} while (0)
#define CHILD_REQUIRE_EQ(actual, expected) do { \
__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); \
} while (0)
static __dead2 void
child_fail_require(const char *file, int line, const char *fmt, ...)
{
va_list ap;
char buf[1024];
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);
}
#define REQUIRE_EQ(actual, expected) do { \
__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)
static void
trace_me(void)
{
CHILD_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
raise(SIGSTOP);
}
static void
attach_child(pid_t pid)
{
pid_t wpid;
int status;
REQUIRE_EQ(ptrace(PT_ATTACH, pid, NULL, 0), 0);
wpid = waitpid(pid, &status, 0);
REQUIRE_EQ(wpid, pid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
}
static void
wait_for_zombie(pid_t pid)
{
for (;;) {
struct kinfo_proc kp;
size_t len;
int mib[4];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC;
mib[2] = KERN_PROC_PID;
mib[3] = pid;
len = sizeof(kp);
if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) {
REQUIRE_EQ(errno, ESRCH);
break;
}
if (kp.ki_stat == SZOMB)
break;
usleep(5000);
}
}
ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_trace_me);
ATF_TC_BODY(ptrace__parent_wait_after_trace_me, tc)
{
pid_t child, wpid;
int status;
ATF_REQUIRE((child = fork()) != -1);
if (child == 0) {
trace_me();
_exit(1);
}
wpid = waitpid(child, &status, 0);
REQUIRE_EQ(wpid, child);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
wpid = waitpid(child, &status, 0);
REQUIRE_EQ(wpid, child);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = waitpid(child, &status, 0);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_attach);
ATF_TC_BODY(ptrace__parent_wait_after_attach, tc)
{
pid_t child, wpid;
int cpipe[2], status;
char c;
REQUIRE_EQ(pipe(cpipe), 0);
ATF_REQUIRE((child = fork()) != -1);
if (child == 0) {
close(cpipe[0]);
CHILD_REQUIRE_EQ(0, read(cpipe[1], &c, sizeof(c)));
_exit(1);
}
close(cpipe[1]);
attach_child(child);
ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
close(cpipe[0]);
wpid = waitpid(child, &status, 0);
REQUIRE_EQ(wpid, child);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = waitpid(child, &status, 0);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_child_debugger);
ATF_TC_BODY(ptrace__parent_sees_exit_after_child_debugger, tc)
{
pid_t child, debugger, wpid;
int cpipe[2], dpipe[2], status;
char c;
REQUIRE_EQ(pipe(cpipe), 0);
ATF_REQUIRE((child = fork()) != -1);
if (child == 0) {
close(cpipe[0]);
CHILD_REQUIRE_EQ(read(cpipe[1], &c, sizeof(c)),
(ssize_t)sizeof(c));
_exit(1);
}
close(cpipe[1]);
REQUIRE_EQ(pipe(dpipe), 0);
ATF_REQUIRE((debugger = fork()) != -1);
if (debugger == 0) {
close(dpipe[0]);
CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1);
wpid = waitpid(child, &status, 0);
CHILD_REQUIRE_EQ(wpid, child);
CHILD_REQUIRE(WIFSTOPPED(status));
CHILD_REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
CHILD_REQUIRE_EQ(write(dpipe[1], &c, sizeof(c)),
(ssize_t)sizeof(c));
CHILD_REQUIRE_EQ(read(dpipe[1], &c, sizeof(c)), 0);
wpid = waitpid(child, &status, 0);
CHILD_REQUIRE_EQ(wpid, child);
CHILD_REQUIRE(WIFEXITED(status));
CHILD_REQUIRE_EQ(WEXITSTATUS(status), 1);
_exit(0);
}
close(dpipe[1]);
REQUIRE_EQ(read(dpipe[0], &c, sizeof(c)), (ssize_t)sizeof(c));
REQUIRE_EQ(write(cpipe[0], &c, sizeof(c)), (ssize_t)sizeof(c));
REQUIRE_EQ(read(cpipe[0], &c, sizeof(c)), 0);
close(cpipe[0]);
wait_for_zombie(child);
wpid = waitpid(child, &status, WNOHANG);
REQUIRE_EQ(wpid, 0);
close(dpipe[0]);
wpid = waitpid(debugger, &status, 0);
REQUIRE_EQ(wpid, debugger);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
wpid = waitpid(child, &status, WNOHANG);
REQUIRE_EQ(wpid, child);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
}
ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_unrelated_debugger);
ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc)
{
pid_t child, debugger, fpid, wpid;
int cpipe[2], dpipe[2], status;
char c;
REQUIRE_EQ(pipe(cpipe), 0);
ATF_REQUIRE((child = fork()) != -1);
if (child == 0) {
close(cpipe[0]);
CHILD_REQUIRE_EQ(read(cpipe[1], &c, sizeof(c)),
(ssize_t)sizeof(c));
_exit(1);
}
close(cpipe[1]);
REQUIRE_EQ(pipe(dpipe), 0);
ATF_REQUIRE((debugger = fork()) != -1);
if (debugger == 0) {
CHILD_REQUIRE((fpid = fork()) != -1);
if (fpid != 0)
_exit(2);
close(dpipe[0]);
CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1);
wpid = waitpid(child, &status, 0);
CHILD_REQUIRE_EQ(wpid, child);
CHILD_REQUIRE(WIFSTOPPED(status));
CHILD_REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
CHILD_REQUIRE_EQ(write(dpipe[1], &c, sizeof(c)),
(ssize_t)sizeof(c));
CHILD_REQUIRE_EQ(read(dpipe[1], &c, sizeof(c)),
(ssize_t)sizeof(c));
wpid = waitpid(child, &status, 0);
CHILD_REQUIRE_EQ(wpid, child);
CHILD_REQUIRE(WIFEXITED(status));
CHILD_REQUIRE_EQ(WEXITSTATUS(status), 1);
_exit(0);
}
close(dpipe[1]);
wpid = waitpid(debugger, &status, 0);
REQUIRE_EQ(wpid, debugger);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 2);
wpid = waitpid(child, &status, WNOHANG);
REQUIRE_EQ(wpid, 0);
REQUIRE_EQ(read(dpipe[0], &c, sizeof(c)), (ssize_t)sizeof(c));
REQUIRE_EQ(write(cpipe[0], &c, sizeof(c)), (ssize_t)sizeof(c));
REQUIRE_EQ(read(cpipe[0], &c, sizeof(c)), 0);
close(cpipe[0]);
wait_for_zombie(child);
wpid = waitpid(child, &status, WNOHANG);
REQUIRE_EQ(wpid, 0);
REQUIRE_EQ(write(dpipe[0], &c, sizeof(c)), (ssize_t)sizeof(c));
REQUIRE_EQ(read(dpipe[0], &c, sizeof(c)), 0);
close(dpipe[0]);
wpid = waitpid(child, &status, WNOHANG);
REQUIRE_EQ(wpid, child);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
}
ATF_TC_WITHOUT_HEAD(ptrace__parent_exits_before_child);
ATF_TC_BODY(ptrace__parent_exits_before_child, tc)
{
ssize_t n;
int cpipe1[2], cpipe2[2], gcpipe[2], status;
pid_t child, gchild;
REQUIRE_EQ(pipe(cpipe1), 0);
REQUIRE_EQ(pipe(cpipe2), 0);
REQUIRE_EQ(pipe(gcpipe), 0);
REQUIRE_EQ(procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL), 0);
ATF_REQUIRE((child = fork()) != -1);
if (child == 0) {
CHILD_REQUIRE((gchild = fork()) != -1);
if (gchild == 0) {
status = 1;
do {
n = read(gcpipe[0], &status, sizeof(status));
} while (n == -1 && errno == EINTR);
_exit(status);
}
CHILD_REQUIRE_EQ(write(cpipe1[1], &gchild, sizeof(gchild)),
(ssize_t)sizeof(gchild));
CHILD_REQUIRE_EQ(read(cpipe2[0], &status, sizeof(status)),
(ssize_t)sizeof(status));
_exit(status);
}
REQUIRE_EQ(read(cpipe1[0], &gchild, sizeof(gchild)),
(ssize_t)sizeof(gchild));
REQUIRE_EQ(ptrace(PT_ATTACH, gchild, NULL, 0), 0);
status = 0;
REQUIRE_EQ(write(cpipe2[1], &status, sizeof(status)),
(ssize_t)sizeof(status));
REQUIRE_EQ(waitpid(child, &status, 0), child);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
status = 0;
REQUIRE_EQ(write(gcpipe[1], &status, sizeof(status)),
(ssize_t)sizeof(status));
REQUIRE_EQ(waitpid(gchild, &status, 0), gchild);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(ptrace(PT_DETACH, gchild, (caddr_t)1, 0), 0);
REQUIRE_EQ(waitpid(gchild, &status, 0), gchild);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
REQUIRE_EQ(close(cpipe1[0]), 0);
REQUIRE_EQ(close(cpipe1[1]), 0);
REQUIRE_EQ(close(cpipe2[0]), 0);
REQUIRE_EQ(close(cpipe2[1]), 0);
REQUIRE_EQ(close(gcpipe[0]), 0);
REQUIRE_EQ(close(gcpipe[1]), 0);
}
static __dead2 void
follow_fork_parent(bool use_vfork)
{
pid_t fpid, wpid;
int status;
if (use_vfork)
CHILD_REQUIRE((fpid = vfork()) != -1);
else
CHILD_REQUIRE((fpid = fork()) != -1);
if (fpid == 0)
_exit(2);
wpid = waitpid(fpid, &status, 0);
CHILD_REQUIRE_EQ(wpid, fpid);
CHILD_REQUIRE(WIFEXITED(status));
CHILD_REQUIRE_EQ(WEXITSTATUS(status), 2);
_exit(1);
}
static pid_t
handle_fork_events(pid_t parent, struct ptrace_lwpinfo *ppl)
{
struct ptrace_lwpinfo pl;
bool fork_reported[2];
pid_t child, wpid;
int i, status;
fork_reported[0] = false;
fork_reported[1] = false;
child = -1;
for (i = 0; i < 2; i++) {
wpid = wait(&status);
ATF_REQUIRE(wpid > 0);
ATF_REQUIRE(WIFSTOPPED(status));
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
sizeof(pl)) != -1);
ATF_REQUIRE((pl.pl_flags & (PL_FLAG_FORKED | PL_FLAG_CHILD)) !=
0);
ATF_REQUIRE((pl.pl_flags & (PL_FLAG_FORKED | PL_FLAG_CHILD)) !=
(PL_FLAG_FORKED | PL_FLAG_CHILD));
if (pl.pl_flags & PL_FLAG_CHILD) {
ATF_REQUIRE(wpid != parent);
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(!fork_reported[1]);
if (child == -1)
child = wpid;
else
REQUIRE_EQ(child, wpid);
if (ppl != NULL)
ppl[1] = pl;
fork_reported[1] = true;
} else {
REQUIRE_EQ(wpid, parent);
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(!fork_reported[0]);
if (child == -1)
child = pl.pl_child_pid;
else
REQUIRE_EQ(child, pl.pl_child_pid);
if (ppl != NULL)
ppl[0] = pl;
fork_reported[0] = true;
}
}
return (child);
}
ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_both_attached);
ATF_TC_BODY(ptrace__follow_fork_both_attached, tc)
{
pid_t children[2], fpid, wpid;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
follow_fork_parent(false);
}
children[0] = fpid;
wpid = waitpid(children[0], &status, 0);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[1]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 2);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached);
ATF_TC_BODY(ptrace__follow_fork_child_detached, tc)
{
pid_t children[2], fpid, wpid;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
follow_fork_parent(false);
}
children[0] = fpid;
wpid = waitpid(children[0], &status, 0);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
ATF_REQUIRE(ptrace(PT_DETACH, children[1], (caddr_t)1, 0) != -1);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_parent_detached);
ATF_TC_BODY(ptrace__follow_fork_parent_detached, tc)
{
pid_t children[2], fpid, wpid;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
follow_fork_parent(false);
}
children[0] = fpid;
wpid = waitpid(children[0], &status, 0);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[1]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 2);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
static void
attach_fork_parent(int cpipe[2])
{
pid_t fpid;
close(cpipe[0]);
CHILD_REQUIRE((fpid = fork()) != -1);
if (fpid != 0)
_exit(3);
fpid = getpid();
CHILD_REQUIRE_EQ(write(cpipe[1], &fpid, sizeof(fpid)),
(ssize_t)sizeof(fpid));
CHILD_REQUIRE_EQ(read(cpipe[1], &fpid, sizeof(fpid)), 0);
}
ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_both_attached_unrelated_debugger);
ATF_TC_BODY(ptrace__follow_fork_both_attached_unrelated_debugger, tc)
{
pid_t children[2], fpid, wpid;
int cpipe[2], status;
REQUIRE_EQ(pipe(cpipe), 0);
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
attach_fork_parent(cpipe);
follow_fork_parent(false);
}
close(cpipe[1]);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 3);
REQUIRE_EQ(read(cpipe[0], &children[0], sizeof(children[0])),
(ssize_t)sizeof(children[0]));
attach_child(children[0]);
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
close(cpipe[0]);
children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[1]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 2);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached_unrelated_debugger);
ATF_TC_BODY(ptrace__follow_fork_child_detached_unrelated_debugger, tc)
{
pid_t children[2], fpid, wpid;
int cpipe[2], status;
REQUIRE_EQ(pipe(cpipe), 0);
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
attach_fork_parent(cpipe);
follow_fork_parent(false);
}
close(cpipe[1]);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 3);
REQUIRE_EQ(read(cpipe[0], &children[0], sizeof(children[0])),
(ssize_t)sizeof(children[0]));
attach_child(children[0]);
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
close(cpipe[0]);
children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
ATF_REQUIRE(ptrace(PT_DETACH, children[1], (caddr_t)1, 0) != -1);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_parent_detached_unrelated_debugger);
ATF_TC_BODY(ptrace__follow_fork_parent_detached_unrelated_debugger, tc)
{
pid_t children[2], fpid, wpid;
int cpipe[2], status;
REQUIRE_EQ(pipe(cpipe), 0);
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
attach_fork_parent(cpipe);
follow_fork_parent(false);
}
close(cpipe[1]);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 3);
REQUIRE_EQ(read(cpipe[0], &children[0], sizeof(children[0])),
(ssize_t)sizeof(children[0]));
attach_child(children[0]);
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
close(cpipe[0]);
children[1] = handle_fork_events(children[0], NULL);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[1]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 2);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__getppid);
ATF_TC_BODY(ptrace__getppid, tc)
{
pid_t child, debugger, ppid, wpid;
int cpipe[2], dpipe[2], status;
char c;
REQUIRE_EQ(pipe(cpipe), 0);
ATF_REQUIRE((child = fork()) != -1);
if (child == 0) {
close(cpipe[0]);
CHILD_REQUIRE_EQ(read(cpipe[1], &c, sizeof(c)),
(ssize_t)sizeof(c));
ppid = getppid();
CHILD_REQUIRE_EQ(write(cpipe[1], &ppid, sizeof(ppid)),
(ssize_t)sizeof(ppid));
_exit(1);
}
close(cpipe[1]);
REQUIRE_EQ(pipe(dpipe), 0);
ATF_REQUIRE((debugger = fork()) != -1);
if (debugger == 0) {
close(dpipe[0]);
CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1);
wpid = waitpid(child, &status, 0);
CHILD_REQUIRE_EQ(wpid, child);
CHILD_REQUIRE(WIFSTOPPED(status));
CHILD_REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
CHILD_REQUIRE_EQ(write(dpipe[1], &c, sizeof(c)),
(ssize_t)sizeof(c));
wpid = waitpid(child, &status, 0);
CHILD_REQUIRE_EQ(wpid, child);
CHILD_REQUIRE(WIFEXITED(status));
CHILD_REQUIRE_EQ(WEXITSTATUS(status), 1);
_exit(0);
}
close(dpipe[1]);
REQUIRE_EQ(read(dpipe[0], &c, sizeof(c)), (ssize_t)sizeof(c));
REQUIRE_EQ(write(cpipe[0], &c, sizeof(c)), (ssize_t)sizeof(c));
REQUIRE_EQ(read(cpipe[0], &ppid, sizeof(ppid)), (ssize_t)sizeof(ppid));
close(cpipe[0]);
REQUIRE_EQ(ppid, getpid());
wpid = waitpid(debugger, &status, 0);
REQUIRE_EQ(wpid, debugger);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
wpid = waitpid(child, &status, WNOHANG);
REQUIRE_EQ(wpid, child);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
}
ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_fork);
ATF_TC_BODY(ptrace__new_child_pl_syscall_code_fork, tc)
{
struct ptrace_lwpinfo pl[2];
pid_t children[2], fpid, wpid;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
follow_fork_parent(false);
}
children[0] = fpid;
wpid = waitpid(children[0], &status, 0);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
children[1] = handle_fork_events(children[0], pl);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_SCX) != 0);
ATF_REQUIRE((pl[1].pl_flags & PL_FLAG_SCX) != 0);
REQUIRE_EQ(pl[0].pl_syscall_code, (unsigned)SYS_fork);
REQUIRE_EQ(pl[0].pl_syscall_code, pl[1].pl_syscall_code);
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[1], (caddr_t)1, 0) != -1);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[1]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 2);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_vfork);
ATF_TC_BODY(ptrace__new_child_pl_syscall_code_vfork, tc)
{
struct ptrace_lwpinfo pl[2];
pid_t children[2], fpid, wpid;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
follow_fork_parent(true);
}
children[0] = fpid;
wpid = waitpid(children[0], &status, 0);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
children[1] = handle_fork_events(children[0], pl);
ATF_REQUIRE(children[1] > 0);
ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_SCX) != 0);
ATF_REQUIRE((pl[1].pl_flags & PL_FLAG_SCX) != 0);
REQUIRE_EQ(pl[0].pl_syscall_code, (unsigned)SYS_vfork);
REQUIRE_EQ(pl[0].pl_syscall_code, pl[1].pl_syscall_code);
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[1], (caddr_t)1, 0) != -1);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[1]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 2);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
static void *
simple_thread(void *arg __unused)
{
pthread_exit(NULL);
}
static __dead2 void
simple_thread_main(void)
{
pthread_t thread;
CHILD_REQUIRE_EQ(pthread_create(&thread, NULL, simple_thread, NULL), 0);
CHILD_REQUIRE_EQ(pthread_join(thread, NULL), 0);
exit(1);
}
ATF_TC_WITHOUT_HEAD(ptrace__new_child_pl_syscall_code_thread);
ATF_TC_BODY(ptrace__new_child_pl_syscall_code_thread, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
lwpid_t mainlwp;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
simple_thread_main();
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
sizeof(pl)) != -1);
mainlwp = pl.pl_lwpid;
ATF_REQUIRE(ptrace(PT_TO_SCX, fpid, (caddr_t)1, 0) != -1);
for (;;) {
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
sizeof(pl)) != -1);
ATF_REQUIRE((pl.pl_flags & PL_FLAG_SCX) != 0);
ATF_REQUIRE(pl.pl_syscall_code != 0);
if (pl.pl_lwpid != mainlwp)
break;
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
}
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
for (;;) {
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
if (WIFEXITED(status))
break;
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
}
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__lwp_events);
ATF_TC_BODY(ptrace__lwp_events, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
lwpid_t lwps[2];
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
simple_thread_main();
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
sizeof(pl)) != -1);
lwps[0] = pl.pl_lwpid;
REQUIRE_EQ(ptrace(PT_LWP_EVENTS, wpid, NULL, 1), 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)),
(PL_FLAG_BORN | PL_FLAG_SCX));
ATF_REQUIRE(pl.pl_lwpid != lwps[0]);
lwps[1] = pl.pl_lwpid;
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ((pl.pl_flags & (PL_FLAG_EXITED | PL_FLAG_SCE)),
(PL_FLAG_EXITED | PL_FLAG_SCE));
REQUIRE_EQ(pl.pl_lwpid, lwps[1]);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
static void *
exec_thread(void *arg __unused)
{
execl("/usr/bin/true", "true", NULL);
exit(127);
}
static __dead2 void
exec_thread_main(void)
{
pthread_t thread;
CHILD_REQUIRE_EQ(pthread_create(&thread, NULL, exec_thread, NULL), 0);
for (;;)
sleep(60);
exit(1);
}
ATF_TC_WITHOUT_HEAD(ptrace__lwp_events_exec);
ATF_TC_BODY(ptrace__lwp_events_exec, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
lwpid_t lwps[2];
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
exec_thread_main();
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
sizeof(pl)) != -1);
lwps[0] = pl.pl_lwpid;
REQUIRE_EQ(ptrace(PT_LWP_EVENTS, wpid, NULL, 1), 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)),
(PL_FLAG_BORN | PL_FLAG_SCX));
ATF_REQUIRE(pl.pl_lwpid != lwps[0]);
lwps[1] = pl.pl_lwpid;
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ((pl.pl_flags & (PL_FLAG_EXITED | PL_FLAG_SCE)),
(PL_FLAG_EXITED));
REQUIRE_EQ(pl.pl_lwpid, lwps[0]);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ((pl.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)),
(PL_FLAG_EXEC | PL_FLAG_SCX));
REQUIRE_EQ(pl.pl_lwpid, lwps[1]);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
static void
handler(int sig __unused)
{
}
static void
signal_main(void)
{
signal(SIGINFO, handler);
raise(SIGINFO);
exit(0);
}
ATF_TC_WITHOUT_HEAD(ptrace__siginfo);
ATF_TC_BODY(ptrace__siginfo, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
signal_main();
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGINFO);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ(pl.pl_event, PL_EVENT_SIGNAL);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI);
REQUIRE_EQ(pl.pl_siginfo.si_code, SI_LWP);
REQUIRE_EQ(pl.pl_siginfo.si_pid, wpid);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__ptrace_exec_disable);
ATF_TC_BODY(ptrace__ptrace_exec_disable, tc)
{
pid_t fpid, wpid;
int events, status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
exec_thread(NULL);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
events = 0;
ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events,
sizeof(events)) == 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__ptrace_exec_enable);
ATF_TC_BODY(ptrace__ptrace_exec_enable, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int events, status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
exec_thread(NULL);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
events = PTRACE_EXEC;
ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events,
sizeof(events)) == 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ((pl.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)),
(PL_FLAG_EXEC | PL_FLAG_SCX));
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__event_mask);
ATF_TC_BODY(ptrace__event_mask, tc)
{
pid_t fpid, wpid;
int events, status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
exit(0);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, fpid, NULL, 1) != -1);
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
sizeof(events)) == 0);
ATF_REQUIRE(events & PTRACE_FORK);
ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, fpid, NULL, 0) != -1);
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
sizeof(events)) == 0);
ATF_REQUIRE(!(events & PTRACE_FORK));
ATF_REQUIRE(ptrace(PT_LWP_EVENTS, fpid, NULL, 1) != -1);
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
sizeof(events)) == 0);
ATF_REQUIRE(events & PTRACE_LWP);
ATF_REQUIRE(ptrace(PT_LWP_EVENTS, fpid, NULL, 0) != -1);
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
sizeof(events)) == 0);
ATF_REQUIRE(!(events & PTRACE_LWP));
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__ptrace_vfork);
ATF_TC_BODY(ptrace__ptrace_vfork, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int events, status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
follow_fork_parent(true);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
sizeof(events)) == 0);
events |= PTRACE_VFORK;
ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events,
sizeof(events)) == 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) != -1);
wpid = wait(&status);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE((pl.pl_flags & PL_FLAG_VFORK_DONE) != 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) != -1);
wpid = wait(&status);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__ptrace_vfork_follow);
ATF_TC_BODY(ptrace__ptrace_vfork_follow, tc)
{
struct ptrace_lwpinfo pl[2];
pid_t children[2], fpid, wpid;
int events, status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
follow_fork_parent(true);
}
children[0] = fpid;
wpid = waitpid(children[0], &status, 0);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, children[0], (caddr_t)&events,
sizeof(events)) == 0);
events |= PTRACE_FORK | PTRACE_VFORK;
ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, children[0], (caddr_t)&events,
sizeof(events)) == 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
children[1] = handle_fork_events(children[0], pl);
ATF_REQUIRE(children[1] > 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[1], (caddr_t)1, 0) != -1);
wpid = waitpid(children[1], &status, 0);
REQUIRE_EQ(wpid, children[1]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 2);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl[0], sizeof(pl[0])) !=
-1);
ATF_REQUIRE((pl[0].pl_flags & PL_FLAG_VFORK_DONE) != 0);
ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
wpid = wait(&status);
REQUIRE_EQ(wpid, children[0]);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
#ifdef HAVE_BREAKPOINT
ATF_TC_WITHOUT_HEAD(ptrace__PT_KILL_breakpoint);
ATF_TC_BODY(ptrace__PT_KILL_breakpoint, tc)
{
pid_t fpid, wpid;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
breakpoint();
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSIGNALED(status));
REQUIRE_EQ(WTERMSIG(status), SIGKILL);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
#endif
ATF_TC_WITHOUT_HEAD(ptrace__PT_KILL_system_call);
ATF_TC_BODY(ptrace__PT_KILL_system_call, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
getpid();
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE);
REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSIGNALED(status));
REQUIRE_EQ(WTERMSIG(status), SIGKILL);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_KILL_threads);
ATF_TC_BODY(ptrace__PT_KILL_threads, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
lwpid_t main_lwp;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
simple_thread_main();
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
sizeof(pl)) != -1);
main_lwp = pl.pl_lwpid;
REQUIRE_EQ(ptrace(PT_LWP_EVENTS, wpid, NULL, 1), 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)),
(PL_FLAG_BORN | PL_FLAG_SCX));
ATF_REQUIRE(pl.pl_lwpid != main_lwp);
REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSIGNALED(status));
REQUIRE_EQ(WTERMSIG(status), SIGKILL);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
static void *
mask_usr1_thread(void *arg)
{
pthread_barrier_t *pbarrier;
sigset_t sigmask;
pbarrier = (pthread_barrier_t*)arg;
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGUSR1);
CHILD_REQUIRE_EQ(pthread_sigmask(SIG_BLOCK, &sigmask, NULL), 0);
pthread_barrier_wait(pbarrier);
for (;;)
sleep(60);
return (NULL);
}
ATF_TC(ptrace__PT_KILL_competing_signal);
ATF_TC_HEAD(ptrace__PT_KILL_competing_signal, tc)
{
atf_tc_set_md_var(tc, "require.user", "root");
}
ATF_TC_BODY(ptrace__PT_KILL_competing_signal, tc)
{
pid_t fpid, wpid;
int status;
cpuset_t setmask;
pthread_t t;
pthread_barrier_t barrier;
struct sched_param sched_param;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
CPU_ZERO(&setmask);
CPU_SET(0, &setmask);
cpusetid_t setid;
CHILD_REQUIRE_EQ(cpuset(&setid), 0);
CHILD_REQUIRE(cpuset_setaffinity(CPU_LEVEL_CPUSET,
CPU_WHICH_CPUSET, setid, sizeof(setmask), &setmask) == 0);
CHILD_REQUIRE_EQ(pthread_barrier_init(&barrier, NULL, 2), 0);
CHILD_REQUIRE(pthread_create(&t, NULL, mask_usr1_thread,
(void*)&barrier) == 0);
sched_param.sched_priority =
(sched_get_priority_max(SCHED_FIFO) +
sched_get_priority_min(SCHED_FIFO)) / 2;
CHILD_REQUIRE(pthread_setschedparam(pthread_self(),
SCHED_FIFO, &sched_param) == 0);
sched_param.sched_priority -= 1;
CHILD_REQUIRE(pthread_setschedparam(t, SCHED_FIFO,
&sched_param) == 0);
sigset_t sigmask;
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGUSR2);
CHILD_REQUIRE_EQ(pthread_sigmask(SIG_BLOCK, &sigmask, NULL), 0);
pthread_barrier_wait(&barrier);
trace_me();
for (;;)
sleep(60);
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
REQUIRE_EQ(kill(fpid, SIGUSR2), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGUSR2);
REQUIRE_EQ(kill(fpid, SIGUSR1), 0);
REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSIGNALED(status));
REQUIRE_EQ(WTERMSIG(status), SIGKILL);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC(ptrace__PT_KILL_competing_stop);
ATF_TC_HEAD(ptrace__PT_KILL_competing_stop, tc)
{
atf_tc_set_md_var(tc, "require.user", "root");
}
ATF_TC_BODY(ptrace__PT_KILL_competing_stop, tc)
{
pid_t fpid, wpid;
int status;
cpuset_t setmask;
pthread_t t;
pthread_barrier_t barrier;
lwpid_t main_lwp;
struct ptrace_lwpinfo pl;
struct sched_param sched_param;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
CPU_ZERO(&setmask);
CPU_SET(0, &setmask);
cpusetid_t setid;
CHILD_REQUIRE_EQ(cpuset(&setid), 0);
CHILD_REQUIRE(cpuset_setaffinity(CPU_LEVEL_CPUSET,
CPU_WHICH_CPUSET, setid, sizeof(setmask), &setmask) == 0);
CHILD_REQUIRE_EQ(pthread_barrier_init(&barrier, NULL, 2), 0);
CHILD_REQUIRE(pthread_create(&t, NULL, mask_usr1_thread,
(void*)&barrier) == 0);
sched_param.sched_priority =
(sched_get_priority_max(SCHED_FIFO) +
sched_get_priority_min(SCHED_FIFO)) / 2;
CHILD_REQUIRE(pthread_setschedparam(pthread_self(),
SCHED_FIFO, &sched_param) == 0);
sched_param.sched_priority -= 1;
CHILD_REQUIRE(pthread_setschedparam(t, SCHED_FIFO,
&sched_param) == 0);
sigset_t sigmask;
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGUSR2);
CHILD_REQUIRE_EQ(pthread_sigmask(SIG_BLOCK, &sigmask, NULL), 0);
pthread_barrier_wait(&barrier);
raise(SIGSTOP);
getpid();
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
main_lwp = pl.pl_lwpid;
REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);
for (;;) {
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
if (WSTOPSIG(status) == SIGTRAP) {
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX));
} else {
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
break;
}
REQUIRE_EQ(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);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
sizeof(pl)) != -1);
REQUIRE_EQ(pl.pl_lwpid, main_lwp);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE);
REQUIRE_EQ(ptrace(PT_SUSPEND, main_lwp, 0, 0), 0);
REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_lwpid != main_lwp);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX);
REQUIRE_EQ(kill(fpid, SIGUSR2), 0);
REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGUSR2);
REQUIRE_EQ(ptrace(PT_RESUME, main_lwp, 0, 0), 0);
REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSIGNALED(status));
REQUIRE_EQ(WTERMSIG(status), SIGKILL);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
static void
sigusr1_handler(int sig)
{
CHILD_REQUIRE_EQ(sig, SIGUSR1);
_exit(2);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_KILL_with_signal_full_sigqueue);
ATF_TC_BODY(ptrace__PT_KILL_with_signal_full_sigqueue, tc)
{
pid_t fpid, wpid;
int status;
int max_pending_per_proc;
size_t len;
int i;
ATF_REQUIRE(signal(SIGUSR1, sigusr1_handler) != SIG_ERR);
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
len = sizeof(max_pending_per_proc);
ATF_REQUIRE(sysctlbyname("kern.sigqueue.max_pending_per_proc",
&max_pending_per_proc, &len, NULL, 0) == 0);
for (i = 0; i < max_pending_per_proc; ++i)
REQUIRE_EQ(kill(fpid, SIGUSR1), 0);
REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSIGNALED(status));
REQUIRE_EQ(WTERMSIG(status), SIGKILL);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_system_call_entry);
ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_system_call_entry, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int status;
ATF_REQUIRE(signal(SIGUSR1, sigusr1_handler) != SIG_ERR);
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
getpid();
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);
for (;;) {
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX));
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
} else {
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 2);
break;
}
}
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
static void
sigusr1_counting_handler(int sig)
{
static int counter = 0;
CHILD_REQUIRE_EQ(sig, SIGUSR1);
counter++;
if (counter == 2)
_exit(2);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_system_call_entry_and_exit);
ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_system_call_entry_and_exit, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int status;
ATF_REQUIRE(signal(SIGUSR1, sigusr1_counting_handler) != SIG_ERR);
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
getpid();
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);
for (;;) {
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX));
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
} else {
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 2);
break;
}
}
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_full_sigqueue);
ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_full_sigqueue, tc)
{
pid_t fpid, wpid;
int status;
int max_pending_per_proc;
size_t len;
int i;
ATF_REQUIRE(signal(SIGUSR2, handler) != SIG_ERR);
ATF_REQUIRE(signal(SIGUSR1, sigusr1_handler) != SIG_ERR);
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
len = sizeof(max_pending_per_proc);
ATF_REQUIRE(sysctlbyname("kern.sigqueue.max_pending_per_proc",
&max_pending_per_proc, &len, NULL, 0) == 0);
for (i = 0; i < max_pending_per_proc; ++i)
REQUIRE_EQ(kill(fpid, SIGUSR2), 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);
for (;;) {
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
if (WIFSTOPPED(status)) {
REQUIRE_EQ(WSTOPSIG(status), SIGUSR2);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
} else {
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 2);
break;
}
}
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
static sem_t sigusr1_sem;
static int got_usr1;
static void
sigusr1_sempost_handler(int sig __unused)
{
got_usr1++;
CHILD_REQUIRE_EQ(sem_post(&sigusr1_sem), 0);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_masked_full_sigqueue);
ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_masked_full_sigqueue, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int status, err;
int max_pending_per_proc;
size_t len;
int i;
sigset_t sigmask;
ATF_REQUIRE(signal(SIGUSR2, handler) != SIG_ERR);
REQUIRE_EQ(sem_init(&sigusr1_sem, 0, 0), 0);
ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR);
got_usr1 = 0;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
CHILD_REQUIRE_EQ(sigemptyset(&sigmask), 0);
CHILD_REQUIRE_EQ(sigaddset(&sigmask, SIGUSR1), 0);
CHILD_REQUIRE_EQ(sigprocmask(SIG_BLOCK, &sigmask, NULL), 0);
trace_me();
CHILD_REQUIRE_EQ(got_usr1, 0);
CHILD_REQUIRE_EQ(sigprocmask(SIG_UNBLOCK, &sigmask, NULL), 0);
do {
err = sem_wait(&sigusr1_sem);
CHILD_REQUIRE(err == 0 || errno == EINTR);
} while (err != 0 && errno == EINTR);
CHILD_REQUIRE_EQ(got_usr1, 1);
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
len = sizeof(max_pending_per_proc);
ATF_REQUIRE(sysctlbyname("kern.sigqueue.max_pending_per_proc",
&max_pending_per_proc, &len, NULL, 0) == 0);
for (i = 0; i < max_pending_per_proc; ++i)
REQUIRE_EQ(kill(fpid, SIGUSR2), 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);
for (i = 0; i < max_pending_per_proc; ++i) {
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGUSR2);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGUSR1);
ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGUSR1);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_change_sig);
ATF_TC_BODY(ptrace__PT_CONTINUE_change_sig, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
sleep(20);
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
REQUIRE_EQ(kill(fpid, SIGINT), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGINT);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGINT);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGTERM), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSIGNALED(status));
REQUIRE_EQ(WTERMSIG(status), SIGTERM);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_sigtrap_system_call_entry);
ATF_TC_BODY(ptrace__PT_CONTINUE_with_sigtrap_system_call_entry, tc)
{
struct ptrace_lwpinfo pl;
struct rlimit rl;
pid_t fpid, wpid;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
rl.rlim_cur = rl.rlim_max = 0;
REQUIRE_EQ(setrlimit(RLIMIT_CORE, &rl), 0);
getpid();
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGTRAP), 0);
for (;;) {
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX));
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
} else {
ATF_REQUIRE(WIFSIGNALED(status));
REQUIRE_EQ(WTERMSIG(status), SIGTRAP);
break;
}
}
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_mix);
ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_mix, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int status;
ATF_REQUIRE(signal(SIGUSR1, sigusr1_counting_handler) != SIG_ERR);
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
getpid();
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX);
REQUIRE_EQ(kill(fpid, SIGABRT), 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGABRT);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGABRT);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);
for (;;) {
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX));
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
} else {
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 2);
break;
}
}
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_kqueue);
ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_kqueue, tc)
{
pid_t fpid, wpid;
int status, kq, nevents;
struct kevent kev;
ATF_REQUIRE(signal(SIGUSR1, SIG_IGN) != SIG_ERR);
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
CHILD_REQUIRE((kq = kqueue()) > 0);
EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
CHILD_REQUIRE_EQ(kevent(kq, &kev, 1, NULL, 0, NULL), 0);
trace_me();
for (;;) {
nevents = kevent(kq, NULL, 0, &kev, 1, NULL);
if (nevents == -1 && errno == EINTR)
continue;
CHILD_REQUIRE(nevents > 0);
CHILD_REQUIRE_EQ(kev.filter, EVFILT_SIGNAL);
CHILD_REQUIRE_EQ(kev.ident, (uintptr_t)SIGUSR1);
break;
}
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
static void *
signal_thread(void *arg)
{
int err;
sigset_t sigmask;
pthread_barrier_t *pbarrier = (pthread_barrier_t*)arg;
do {
err = sem_wait(&sigusr1_sem);
CHILD_REQUIRE(err == 0 || errno == EINTR);
} while (err != 0 && errno == EINTR);
pthread_barrier_wait(pbarrier);
CHILD_REQUIRE_EQ(sigemptyset(&sigmask), 0);
CHILD_REQUIRE_EQ(sigaddset(&sigmask, SIGUSR1), 0);
CHILD_REQUIRE_EQ(pthread_sigmask(SIG_BLOCK, &sigmask, NULL), 0);
pthread_barrier_wait(pbarrier);
pthread_barrier_wait(pbarrier);
return (NULL);
}
ATF_TC_WITHOUT_HEAD(ptrace__killed_with_sigmask);
ATF_TC_BODY(ptrace__killed_with_sigmask, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int status, err;
sigset_t sigmask;
REQUIRE_EQ(sem_init(&sigusr1_sem, 0, 0), 0);
ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR);
got_usr1 = 0;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
CHILD_REQUIRE_EQ(sigemptyset(&sigmask), 0);
CHILD_REQUIRE_EQ(sigaddset(&sigmask, SIGUSR1), 0);
CHILD_REQUIRE_EQ(sigprocmask(SIG_BLOCK, &sigmask, NULL), 0);
trace_me();
CHILD_REQUIRE_EQ(got_usr1, 0);
CHILD_REQUIRE_EQ(sigprocmask(SIG_UNBLOCK, &sigmask, NULL), 0);
do {
err = sem_wait(&sigusr1_sem);
CHILD_REQUIRE(err == 0 || errno == EINTR);
} while (err != 0 && errno == EINTR);
CHILD_REQUIRE_EQ(got_usr1, 1);
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGSTOP);
REQUIRE_EQ(kill(fpid, SIGUSR1), 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGUSR1);
ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGUSR1);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_sigmask);
ATF_TC_BODY(ptrace__PT_CONTINUE_with_sigmask, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int status, err;
sigset_t sigmask;
REQUIRE_EQ(sem_init(&sigusr1_sem, 0, 0), 0);
ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR);
got_usr1 = 0;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
CHILD_REQUIRE_EQ(sigemptyset(&sigmask), 0);
CHILD_REQUIRE_EQ(sigaddset(&sigmask, SIGUSR1), 0);
CHILD_REQUIRE_EQ(sigprocmask(SIG_BLOCK, &sigmask, NULL), 0);
trace_me();
CHILD_REQUIRE_EQ(got_usr1, 0);
CHILD_REQUIRE_EQ(sigprocmask(SIG_UNBLOCK, &sigmask, NULL), 0);
do {
err = sem_wait(&sigusr1_sem);
CHILD_REQUIRE(err == 0 || errno == EINTR);
} while (err != 0 && errno == EINTR);
CHILD_REQUIRE_EQ(got_usr1, 1);
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGSTOP);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGUSR1);
ATF_REQUIRE(ptrace(PT_LWPINFO, fpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGUSR1);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_with_signal_thread_sigmask);
ATF_TC_BODY(ptrace__PT_CONTINUE_with_signal_thread_sigmask, tc)
{
pid_t fpid, wpid;
int status, err;
pthread_t t;
sigset_t sigmask;
pthread_barrier_t barrier;
REQUIRE_EQ(pthread_barrier_init(&barrier, NULL, 2), 0);
REQUIRE_EQ(sem_init(&sigusr1_sem, 0, 0), 0);
ATF_REQUIRE(signal(SIGUSR1, sigusr1_sempost_handler) != SIG_ERR);
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
CHILD_REQUIRE_EQ(pthread_create(&t, NULL, signal_thread,
(void *)&barrier), 0);
CHILD_REQUIRE_EQ(sigemptyset(&sigmask), 0);
CHILD_REQUIRE_EQ(sigaddset(&sigmask, SIGUSR1), 0);
CHILD_REQUIRE_EQ(pthread_sigmask(SIG_BLOCK, &sigmask, NULL), 0);
trace_me();
pthread_barrier_wait(&barrier);
CHILD_REQUIRE_EQ(pthread_sigmask(SIG_UNBLOCK, &sigmask, NULL),
0);
pthread_barrier_wait(&barrier);
raise(SIGSTOP);
do {
err = sem_wait(&sigusr1_sem);
CHILD_REQUIRE(err == 0 || errno == EINTR);
} while (err != 0 && errno == EINTR);
pthread_barrier_wait(&barrier);
CHILD_REQUIRE_EQ(pthread_join(t, NULL), 0);
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
REQUIRE_EQ(kill(fpid, SIGUSR2), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGUSR2);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
REQUIRE_EQ(kill(fpid, SIGUSR2), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGUSR2);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_REGSET);
ATF_TC_BODY(ptrace__PT_REGSET, tc)
{
#if defined(__aarch64__)
struct arm64_addr_mask addr_mask;
#endif
struct prstatus prstatus;
struct iovec vec;
pid_t child, wpid;
int status;
ATF_REQUIRE((child = fork()) != -1);
if (child == 0) {
trace_me();
exit(1);
}
wpid = waitpid(child, &status, 0);
REQUIRE_EQ(wpid, child);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
vec.iov_base = NULL;
vec.iov_len = 0;
ATF_REQUIRE(ptrace(PT_GETREGSET, wpid, (caddr_t)&vec, NT_PRSTATUS) !=
-1);
ATF_REQUIRE(vec.iov_len == sizeof(prstatus));
ATF_REQUIRE(vec.iov_base == NULL);
memset(&prstatus, 0, sizeof(prstatus));
vec.iov_base = &prstatus;
ATF_REQUIRE(ptrace(PT_GETREGSET, wpid, (caddr_t)&vec, NT_PRSTATUS) !=
-1);
ATF_REQUIRE(vec.iov_len == sizeof(prstatus));
ATF_REQUIRE(vec.iov_base == &prstatus);
ATF_REQUIRE(prstatus.pr_statussz == sizeof(prstatus));
ATF_REQUIRE(ptrace(PT_SETREGSET, wpid, (caddr_t)&vec, NT_PRSTATUS) !=
-1);
#if defined(__aarch64__)
vec.iov_base = &addr_mask;
vec.iov_len = sizeof(addr_mask);
ATF_REQUIRE(ptrace(PT_GETREGSET, wpid, (caddr_t)&vec,
NT_ARM_ADDR_MASK) != -1);
REQUIRE_EQ(addr_mask.code, addr_mask.data);
ATF_REQUIRE(addr_mask.code == 0xff00000000000000ul ||
addr_mask.code == 0xff7f000000000000UL);
#endif
REQUIRE_EQ(ptrace(PT_CONTINUE, child, (caddr_t)1, 0), 0);
wpid = waitpid(child, &status, 0);
REQUIRE_EQ(wpid, child);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = waitpid(child, &status, 0);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
static void *
raise_sigstop_thread(void *arg __unused)
{
raise(SIGSTOP);
return NULL;
}
static void *
sleep_thread(void *arg __unused)
{
sleep(60);
return NULL;
}
static void
terminate_with_pending_sigstop(bool sigstop_from_main_thread)
{
pid_t fpid, wpid;
int status, i;
cpuset_t setmask;
cpusetid_t setid;
pthread_t t;
REQUIRE_EQ(procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL), 0);
fpid = fork();
ATF_REQUIRE(fpid >= 0);
if (fpid == 0) {
fpid = fork();
CHILD_REQUIRE(fpid >= 0);
if (fpid == 0) {
trace_me();
CPU_ZERO(&setmask);
CPU_SET(0, &setmask);
CHILD_REQUIRE_EQ(cpuset(&setid), 0);
CHILD_REQUIRE(cpuset_setaffinity(CPU_LEVEL_CPUSET,
CPU_WHICH_CPUSET, setid,
sizeof(setmask), &setmask) == 0);
if (sigstop_from_main_thread) {
CHILD_REQUIRE(pthread_create(&t, NULL,
sleep_thread, NULL) == 0);
raise(SIGSTOP);
} else {
CHILD_REQUIRE(pthread_create(&t, NULL,
raise_sigstop_thread, NULL) == 0);
sleep(60);
}
exit(0);
}
wpid = waitpid(fpid, &status, 0);
CHILD_REQUIRE_EQ(wpid, fpid);
CHILD_REQUIRE(WIFSTOPPED(status));
CHILD_REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
CHILD_REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
CHILD_REQUIRE_EQ(wpid, fpid);
CHILD_REQUIRE(WIFSTOPPED(status));
CHILD_REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
exit(0);
}
for (i = 0; i < 2; ++i) {
wpid = wait(&status);
if (wpid == fpid) {
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
} else {
ATF_REQUIRE(WIFSIGNALED(status));
REQUIRE_EQ(WTERMSIG(status), SIGKILL);
}
}
}
ATF_TC(ptrace__parent_terminate_with_pending_sigstop1);
ATF_TC_HEAD(ptrace__parent_terminate_with_pending_sigstop1, tc)
{
atf_tc_set_md_var(tc, "require.user", "root");
}
ATF_TC_BODY(ptrace__parent_terminate_with_pending_sigstop1, tc)
{
terminate_with_pending_sigstop(true);
}
ATF_TC(ptrace__parent_terminate_with_pending_sigstop2);
ATF_TC_HEAD(ptrace__parent_terminate_with_pending_sigstop2, tc)
{
atf_tc_set_md_var(tc, "require.user", "root");
}
ATF_TC_BODY(ptrace__parent_terminate_with_pending_sigstop2, tc)
{
terminate_with_pending_sigstop(false);
}
ATF_TC_WITHOUT_HEAD(ptrace__event_mask_sigkill_discard);
ATF_TC_BODY(ptrace__event_mask_sigkill_discard, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int status, event_mask, new_event_mask;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
raise(SIGSTOP);
exit(0);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
event_mask = PTRACE_EXEC | PTRACE_FORK | PTRACE_LWP;
ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, wpid, (caddr_t)&event_mask,
sizeof(event_mask)) == 0);
REQUIRE_EQ(kill(fpid, SIGKILL), 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGKILL);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGKILL);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
new_event_mask = 0;
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, wpid, (caddr_t)&new_event_mask,
sizeof(new_event_mask)) == 0);
REQUIRE_EQ(event_mask, new_event_mask);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
static void *
flock_thread(void *arg)
{
int fd;
fd = *(int *)arg;
(void)flock(fd, LOCK_EX);
(void)flock(fd, LOCK_UN);
return (NULL);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_ATTACH_with_SBDRY_thread);
ATF_TC_BODY(ptrace__PT_ATTACH_with_SBDRY_thread, tc)
{
pthread_barrier_t barrier;
pthread_barrierattr_t battr;
char tmpfile[64];
pid_t child, wpid;
int error, fd, i, status;
REQUIRE_EQ(pthread_barrierattr_init(&battr), 0);
ATF_REQUIRE(pthread_barrierattr_setpshared(&battr,
PTHREAD_PROCESS_SHARED) == 0);
REQUIRE_EQ(pthread_barrier_init(&barrier, &battr, 2), 0);
(void)snprintf(tmpfile, sizeof(tmpfile), "./ptrace.XXXXXX");
fd = mkstemp(tmpfile);
ATF_REQUIRE(fd >= 0);
ATF_REQUIRE((child = fork()) != -1);
if (child == 0) {
pthread_t t[2];
int cfd;
error = pthread_barrier_wait(&barrier);
if (error != 0 && error != PTHREAD_BARRIER_SERIAL_THREAD)
_exit(1);
cfd = open(tmpfile, O_RDONLY);
if (cfd < 0)
_exit(1);
if (pthread_create(&t[0], NULL, flock_thread, &cfd) != 0)
_exit(1);
if (pthread_create(&t[1], NULL, flock_thread, &cfd) != 0)
_exit(1);
if (pthread_join(t[0], NULL) != 0)
_exit(1);
if (pthread_join(t[1], NULL) != 0)
_exit(1);
_exit(0);
}
REQUIRE_EQ(flock(fd, LOCK_EX), 0);
error = pthread_barrier_wait(&barrier);
ATF_REQUIRE(error == 0 || error == PTHREAD_BARRIER_SERIAL_THREAD);
sleep(1);
REQUIRE_EQ(ptrace(PT_ATTACH, child, NULL, 0), 0);
for (i = 0; i < 3; i++) {
wpid = waitpid(child, &status, WNOHANG);
if (wpid == child && WIFSTOPPED(status) &&
WSTOPSIG(status) == SIGSTOP)
break;
sleep(1);
}
ATF_REQUIRE_MSG(i < 3, "failed to stop child process after PT_ATTACH");
REQUIRE_EQ(ptrace(PT_DETACH, child, NULL, 0), 0);
REQUIRE_EQ(flock(fd, LOCK_UN), 0);
REQUIRE_EQ(unlink(tmpfile), 0);
REQUIRE_EQ(close(fd), 0);
}
static void
sigusr1_step_handler(int sig)
{
CHILD_REQUIRE_EQ(sig, SIGUSR1);
raise(SIGABRT);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_STEP_with_signal);
ATF_TC_BODY(ptrace__PT_STEP_with_signal, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
signal(SIGUSR1, sigusr1_step_handler);
raise(SIGABRT);
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGABRT);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGABRT);
REQUIRE_EQ(ptrace(PT_STEP, fpid, (caddr_t)1, SIGUSR1), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGABRT);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGABRT);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGTRAP);
REQUIRE_EQ(pl.pl_siginfo.si_code, TRAP_TRACE);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
#ifdef HAVE_BREAKPOINT
ATF_TC_WITHOUT_HEAD(ptrace__breakpoint_siginfo);
ATF_TC_BODY(ptrace__breakpoint_siginfo, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
breakpoint();
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE((pl.pl_flags & PL_FLAG_SI) != 0);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGTRAP);
REQUIRE_EQ(pl.pl_siginfo.si_code, TRAP_BRKPT);
REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSIGNALED(status));
REQUIRE_EQ(WTERMSIG(status), SIGKILL);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
#endif
ATF_TC_WITHOUT_HEAD(ptrace__step_siginfo);
ATF_TC_BODY(ptrace__step_siginfo, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_STEP, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE((pl.pl_flags & PL_FLAG_SI) != 0);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGTRAP);
REQUIRE_EQ(pl.pl_siginfo.si_code, TRAP_TRACE);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
#if defined(HAVE_BREAKPOINT) && defined(SKIP_BREAK)
static void *
continue_thread(void *arg __unused)
{
breakpoint();
return (NULL);
}
static __dead2 void
continue_thread_main(void)
{
pthread_t threads[2];
CHILD_REQUIRE(pthread_create(&threads[0], NULL, continue_thread,
NULL) == 0);
CHILD_REQUIRE(pthread_create(&threads[1], NULL, continue_thread,
NULL) == 0);
CHILD_REQUIRE_EQ(pthread_join(threads[0], NULL), 0);
CHILD_REQUIRE_EQ(pthread_join(threads[1], NULL), 0);
exit(1);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_CONTINUE_different_thread);
ATF_TC_BODY(ptrace__PT_CONTINUE_different_thread, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
lwpid_t lwps[2];
bool hit_break[2];
struct reg reg;
int i, j, status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
continue_thread_main();
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
sizeof(pl)) != -1);
REQUIRE_EQ(ptrace(PT_LWP_EVENTS, wpid, NULL, 1), 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)),
(PL_FLAG_BORN | PL_FLAG_SCX));
lwps[0] = pl.pl_lwpid;
ATF_REQUIRE(ptrace(PT_SUSPEND, lwps[0], NULL, 0) != -1);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
REQUIRE_EQ((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)),
(PL_FLAG_BORN | PL_FLAG_SCX));
ATF_REQUIRE(pl.pl_lwpid != lwps[0]);
lwps[1] = pl.pl_lwpid;
hit_break[0] = hit_break[1] = false;
ATF_REQUIRE(ptrace(PT_RESUME, lwps[0], NULL, 0) != -1);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE((pl.pl_flags & PL_FLAG_SI) != 0);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGTRAP);
REQUIRE_EQ(pl.pl_siginfo.si_code, TRAP_BRKPT);
if (pl.pl_lwpid == lwps[0])
i = 0;
else
i = 1;
hit_break[i] = true;
ATF_REQUIRE(ptrace(PT_GETREGS, pl.pl_lwpid, (caddr_t)®, 0) != -1);
SKIP_BREAK(®);
ATF_REQUIRE(ptrace(PT_SETREGS, pl.pl_lwpid, (caddr_t)®, 0) != -1);
REQUIRE_EQ(ptrace(PT_CONTINUE, lwps[i ^ 1], (caddr_t)1, 0), 0);
for (j = 0; j < 3; j++) {
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
sizeof(pl)) != -1);
if (pl.pl_lwpid == lwps[0])
i = 0;
else
i = 1;
ATF_REQUIRE_MSG(lwps[i] != 0, "event for exited thread");
if (pl.pl_flags & PL_FLAG_EXITED) {
ATF_REQUIRE_MSG(hit_break[i],
"exited thread did not report breakpoint");
lwps[i] = 0;
} else {
ATF_REQUIRE((pl.pl_flags & PL_FLAG_SI) != 0);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGTRAP);
REQUIRE_EQ(pl.pl_siginfo.si_code, TRAP_BRKPT);
ATF_REQUIRE_MSG(!hit_break[i],
"double breakpoint event");
hit_break[i] = true;
ATF_REQUIRE(ptrace(PT_GETREGS, pl.pl_lwpid, (caddr_t)®,
0) != -1);
SKIP_BREAK(®);
ATF_REQUIRE(ptrace(PT_SETREGS, pl.pl_lwpid, (caddr_t)®,
0) != -1);
}
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
}
REQUIRE_EQ(lwps[0], 0);
REQUIRE_EQ(lwps[1], 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
#endif
ATF_TC_WITHOUT_HEAD(ptrace__PT_LWPINFO_stale_siginfo);
ATF_TC_BODY(ptrace__PT_LWPINFO_stale_siginfo, tc)
{
struct ptrace_lwpinfo pl;
pid_t fpid, wpid;
int events, status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
raise(SIGABRT);
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGABRT);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI);
REQUIRE_EQ(pl.pl_siginfo.si_signo, SIGABRT);
REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE);
REQUIRE_EQ((pl.pl_flags & PL_FLAG_SI), 0);
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
sizeof(events)) == 0);
events &= ~PTRACE_SYSCALL;
ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events,
sizeof(events)) == 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__syscall_args);
ATF_TC_BODY(ptrace__syscall_args, tc)
{
struct ptrace_lwpinfo pl;
struct ptrace_sc_ret psr;
pid_t fpid, wpid;
register_t args[2];
int events, status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
kill(getpid(), 0);
close(12345);
exit(1);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE);
REQUIRE_EQ(pl.pl_syscall_code, (unsigned)SYS_getpid);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX);
REQUIRE_EQ(pl.pl_syscall_code, (unsigned)SYS_getpid);
ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr,
sizeof(psr)) != -1);
REQUIRE_EQ(psr.sr_error, 0);
REQUIRE_EQ(psr.sr_retval[0], wpid);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE);
REQUIRE_EQ(pl.pl_syscall_code, (unsigned)SYS_kill);
REQUIRE_EQ(pl.pl_syscall_narg, 2u);
ATF_REQUIRE(ptrace(PT_GET_SC_ARGS, wpid, (caddr_t)args,
sizeof(args)) != -1);
REQUIRE_EQ(args[0], wpid);
REQUIRE_EQ(args[1], 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX);
REQUIRE_EQ(pl.pl_syscall_code, (unsigned)SYS_kill);
ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr,
sizeof(psr)) != -1);
REQUIRE_EQ(psr.sr_error, 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCE);
REQUIRE_EQ(pl.pl_syscall_code, (unsigned)SYS_close);
REQUIRE_EQ(pl.pl_syscall_narg, 1u);
ATF_REQUIRE(ptrace(PT_GET_SC_ARGS, wpid, (caddr_t)args,
sizeof(args)) != -1);
REQUIRE_EQ(args[0], 12345);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);
ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
ATF_REQUIRE(pl.pl_flags & PL_FLAG_SCX);
REQUIRE_EQ(pl.pl_syscall_code, (unsigned)SYS_close);
ATF_REQUIRE(ptrace(PT_GET_SC_RET, wpid, (caddr_t)&psr,
sizeof(psr)) != -1);
REQUIRE_EQ(psr.sr_error, EBADF);
ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
sizeof(events)) == 0);
events &= ~PTRACE_SYSCALL;
ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events,
sizeof(events)) == 0);
REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
wpid = waitpid(fpid, &status, 0);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__syscall_args_anywhere);
ATF_TC_BODY(ptrace__syscall_args_anywhere, tc)
{
struct timespec rqt;
struct ptrace_lwpinfo lwpi;
register_t args[8];
pid_t debuggee, wpid;
int error, status;
debuggee = fork();
ATF_REQUIRE(debuggee >= 0);
if (debuggee == 0) {
rqt.tv_sec = 100000;
rqt.tv_nsec = 0;
for (;;)
nanosleep(&rqt, NULL);
_exit(0);
}
sleep(2);
error = ptrace(PT_ATTACH, debuggee, 0, 0);
ATF_REQUIRE(error == 0);
wpid = waitpid(debuggee, &status, 0);
REQUIRE_EQ(wpid, debuggee);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
error = ptrace(PT_LWPINFO, debuggee, (caddr_t)&lwpi, sizeof(lwpi));
ATF_REQUIRE(error == 0);
ATF_REQUIRE(lwpi.pl_syscall_code == SYS_nanosleep);
ATF_REQUIRE(lwpi.pl_syscall_narg == 2);
error = ptrace(PT_GET_SC_ARGS, debuggee, (caddr_t)&args[0],
lwpi.pl_syscall_narg * sizeof(register_t));
ATF_REQUIRE(error == 0);
ATF_REQUIRE(args[0] == (register_t)&rqt);
ATF_REQUIRE(args[1] == 0);
error = ptrace(PT_DETACH, debuggee, 0, 0);
ATF_REQUIRE(error == 0);
kill(SIGKILL, debuggee);
}
ATF_TC(ptrace__proc_reparent);
ATF_TC_HEAD(ptrace__proc_reparent, tc)
{
atf_tc_set_md_var(tc, "timeout", "2");
}
ATF_TC_BODY(ptrace__proc_reparent, tc)
{
pid_t traced, debuger, wpid;
int pd, status;
traced = pdfork(&pd, 0);
ATF_REQUIRE(traced >= 0);
if (traced == 0) {
raise(SIGSTOP);
exit(0);
}
ATF_REQUIRE(pd >= 0);
debuger = fork();
ATF_REQUIRE(debuger >= 0);
if (debuger == 0) {
REQUIRE_EQ(ptrace(PT_ATTACH, traced, 0, 0), 0);
wpid = waitpid(traced, &status, 0);
REQUIRE_EQ(wpid, traced);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(close(pd), 0);
REQUIRE_EQ(ptrace(PT_DETACH, traced, (caddr_t)1, 0), 0);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
exit(0);
}
REQUIRE_EQ(close(pd), 0);
wpid = waitpid(debuger, &status, 0);
REQUIRE_EQ(wpid, debuger);
REQUIRE_EQ(WEXITSTATUS(status), 0);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
}
ATF_TC_WITHOUT_HEAD(ptrace__procdesc_wait_child);
ATF_TC_BODY(ptrace__procdesc_wait_child, tc)
{
pid_t child, wpid;
int pd, status;
child = pdfork(&pd, 0);
ATF_REQUIRE(child >= 0);
if (child == 0) {
trace_me();
(void)raise(SIGSTOP);
exit(0);
}
wpid = waitpid(child, &status, 0);
REQUIRE_EQ(wpid, child);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
wpid = wait(&status);
REQUIRE_EQ(wpid, child);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
ATF_REQUIRE(close(pd) != -1);
}
ATF_TC_WITHOUT_HEAD(ptrace__procdesc_reparent_wait_child);
ATF_TC_BODY(ptrace__procdesc_reparent_wait_child, tc)
{
pid_t traced, debuger, wpid;
int pd, status;
traced = pdfork(&pd, 0);
ATF_REQUIRE(traced >= 0);
if (traced == 0) {
raise(SIGSTOP);
exit(0);
}
ATF_REQUIRE(pd >= 0);
REQUIRE_EQ(traced, waitpid(traced, &status, WSTOPPED));
debuger = fork();
ATF_REQUIRE(debuger >= 0);
if (debuger == 0) {
REQUIRE_EQ(ptrace(PT_ATTACH, traced, 0, 0), 0);
wpid = waitpid(traced, &status, 0);
REQUIRE_EQ(wpid, traced);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_CONTINUE, traced, (caddr_t)1, 0), 0);
wpid = waitpid(traced, &status, 0);
REQUIRE_EQ(wpid, traced);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
REQUIRE_EQ(close(pd), 0);
exit(0);
}
wpid = waitpid(debuger, &status, 0);
REQUIRE_EQ(wpid, debuger);
REQUIRE_EQ(WEXITSTATUS(status), 0);
wpid = wait(&status);
REQUIRE_EQ(wpid, -1);
REQUIRE_EQ(errno, ECHILD);
REQUIRE_EQ(close(pd), 0);
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_SC_REMOTE_getpid);
ATF_TC_BODY(ptrace__PT_SC_REMOTE_getpid, tc)
{
struct ptrace_sc_remote pscr;
pid_t fpid, wpid;
int status;
ATF_REQUIRE((fpid = fork()) != -1);
if (fpid == 0) {
trace_me();
exit(0);
}
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
pscr.pscr_syscall = SYS_getpid;
pscr.pscr_nargs = 0;
pscr.pscr_args = NULL;
ATF_REQUIRE(ptrace(PT_SC_REMOTE, fpid, (caddr_t)&pscr, sizeof(pscr)) !=
-1);
ATF_REQUIRE_MSG(pscr.pscr_ret.sr_error == 0,
"remote getpid failed with error %d", pscr.pscr_ret.sr_error);
ATF_REQUIRE_MSG(pscr.pscr_ret.sr_retval[0] == fpid,
"unexpected return value %jd instead of %d",
(intmax_t)pscr.pscr_ret.sr_retval[0], fpid);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
pscr.pscr_syscall = SYS_getppid;
pscr.pscr_nargs = 0;
pscr.pscr_args = NULL;
ATF_REQUIRE(ptrace(PT_SC_REMOTE, fpid, (caddr_t)&pscr, sizeof(pscr)) !=
-1);
ATF_REQUIRE_MSG(pscr.pscr_ret.sr_error == 0,
"remote getppid failed with error %d", pscr.pscr_ret.sr_error);
ATF_REQUIRE_MSG(pscr.pscr_ret.sr_retval[0] == getpid(),
"unexpected return value %jd instead of %d",
(intmax_t)pscr.pscr_ret.sr_retval[0], fpid);
wpid = waitpid(fpid, &status, 0);
REQUIRE_EQ(wpid, fpid);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_DETACH, fpid, (caddr_t)1, 0) != -1);
}
ATF_TC_WITHOUT_HEAD(ptrace__reap_kill_stopped);
ATF_TC_BODY(ptrace__reap_kill_stopped, tc)
{
struct procctl_reaper_kill prk;
pid_t debuggee, wpid;
int error, status;
REQUIRE_EQ(procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL), 0);
debuggee = fork();
ATF_REQUIRE(debuggee >= 0);
if (debuggee == 0) {
trace_me();
for (;;)
sleep(10);
_exit(0);
}
wpid = waitpid(debuggee, &status, 0);
REQUIRE_EQ(wpid, debuggee);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
ATF_REQUIRE(ptrace(PT_TO_SCX, debuggee, (caddr_t)1, 0) != -1);
usleep(100000);
memset(&prk, 0, sizeof(prk));
prk.rk_sig = SIGTERM;
error = procctl(P_PID, getpid(), PROC_REAP_KILL, &prk);
REQUIRE_EQ(error, 0);
REQUIRE_EQ(1u, prk.rk_killed);
REQUIRE_EQ(-1, prk.rk_fpid);
}
struct child_res {
struct timespec sleep_time;
int nanosleep_res;
int nanosleep_errno;
};
static const long nsec = 1000000000L;
static const struct timespec ten_sec = {
.tv_sec = 10,
.tv_nsec = 0,
};
static const struct timespec twelve_sec = {
.tv_sec = 12,
.tv_nsec = 0,
};
ATF_TC_WITHOUT_HEAD(ptrace__PT_ATTACH_no_EINTR);
ATF_TC_BODY(ptrace__PT_ATTACH_no_EINTR, tc)
{
struct child_res *shm;
struct timespec rqt, now, wake;
pid_t debuggee;
int status;
shm = mmap(NULL, sizeof(*shm), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANON, -1, 0);
ATF_REQUIRE(shm != MAP_FAILED);
ATF_REQUIRE((debuggee = fork()) != -1);
if (debuggee == 0) {
rqt.tv_sec = 10;
rqt.tv_nsec = 0;
clock_gettime(CLOCK_MONOTONIC_PRECISE, &now);
errno = 0;
shm->nanosleep_res = nanosleep(&rqt, NULL);
shm->nanosleep_errno = errno;
clock_gettime(CLOCK_MONOTONIC_PRECISE, &wake);
timespecsub(&wake, &now, &shm->sleep_time);
_exit(0);
}
sleep(2);
REQUIRE_EQ(ptrace(PT_ATTACH, debuggee, 0, 0), 0);
REQUIRE_EQ(waitpid(debuggee, &status, 0), debuggee);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_DETACH, debuggee, 0, 0), 0);
REQUIRE_EQ(waitpid(debuggee, &status, 0), debuggee);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
ATF_REQUIRE(shm->nanosleep_res == 0);
ATF_REQUIRE(shm->nanosleep_errno == 0);
ATF_REQUIRE(timespeccmp(&shm->sleep_time, &ten_sec, >=));
ATF_REQUIRE(timespeccmp(&shm->sleep_time, &twelve_sec, <=));
}
ATF_TC_WITHOUT_HEAD(ptrace__PT_DETACH_continued);
ATF_TC_BODY(ptrace__PT_DETACH_continued, tc)
{
char buf[256];
pid_t debuggee, debugger;
int dpipe[2] = {-1, -1}, status;
ATF_REQUIRE(pipe(dpipe) == 0);
ATF_REQUIRE((debuggee = fork()) != -1);
if (debuggee == 0) {
ssize_t readsz;
close(dpipe[1]);
while ((readsz = read(dpipe[0], buf, sizeof(buf))) != 0) {
if (readsz > 0 || errno == EINTR)
continue;
_exit(1);
}
_exit(0);
}
close(dpipe[0]);
ATF_REQUIRE(kill(debuggee, SIGSTOP) == 0);
REQUIRE_EQ(waitpid(debuggee, &status, WUNTRACED), debuggee);
ATF_REQUIRE(WIFSTOPPED(status));
ATF_REQUIRE((debugger = fork()) != -1);
if (debugger == 0) {
REQUIRE_EQ(ptrace(PT_ATTACH, debuggee, 0, 0), 0);
REQUIRE_EQ(waitpid(debuggee, &status, 0), debuggee);
ATF_REQUIRE(WIFSTOPPED(status));
REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);
REQUIRE_EQ(ptrace(PT_DETACH, debuggee, 0, 0), 0);
_exit(0);
}
REQUIRE_EQ(waitpid(debugger, &status, 0), debugger);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
REQUIRE_EQ(waitpid(debuggee, &status, WCONTINUED), debuggee);
ATF_REQUIRE(WIFCONTINUED(status));
close(dpipe[1]);
REQUIRE_EQ(waitpid(debuggee, &status, 0), debuggee);
ATF_REQUIRE(WIFEXITED(status));
REQUIRE_EQ(WEXITSTATUS(status), 0);
}
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_attach);
ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_child_debugger);
ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_unrelated_debugger);
ATF_TP_ADD_TC(tp, ptrace__parent_exits_before_child);
ATF_TP_ADD_TC(tp, ptrace__follow_fork_both_attached);
ATF_TP_ADD_TC(tp, ptrace__follow_fork_child_detached);
ATF_TP_ADD_TC(tp, ptrace__follow_fork_parent_detached);
ATF_TP_ADD_TC(tp, ptrace__follow_fork_both_attached_unrelated_debugger);
ATF_TP_ADD_TC(tp,
ptrace__follow_fork_child_detached_unrelated_debugger);
ATF_TP_ADD_TC(tp,
ptrace__follow_fork_parent_detached_unrelated_debugger);
ATF_TP_ADD_TC(tp, ptrace__getppid);
ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_fork);
ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_vfork);
ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_thread);
ATF_TP_ADD_TC(tp, ptrace__lwp_events);
ATF_TP_ADD_TC(tp, ptrace__lwp_events_exec);
ATF_TP_ADD_TC(tp, ptrace__siginfo);
ATF_TP_ADD_TC(tp, ptrace__ptrace_exec_disable);
ATF_TP_ADD_TC(tp, ptrace__ptrace_exec_enable);
ATF_TP_ADD_TC(tp, ptrace__event_mask);
ATF_TP_ADD_TC(tp, ptrace__ptrace_vfork);
ATF_TP_ADD_TC(tp, ptrace__ptrace_vfork_follow);
#ifdef HAVE_BREAKPOINT
ATF_TP_ADD_TC(tp, ptrace__PT_KILL_breakpoint);
#endif
ATF_TP_ADD_TC(tp, ptrace__PT_KILL_system_call);
ATF_TP_ADD_TC(tp, ptrace__PT_KILL_threads);
ATF_TP_ADD_TC(tp, ptrace__PT_KILL_competing_signal);
ATF_TP_ADD_TC(tp, ptrace__PT_KILL_competing_stop);
ATF_TP_ADD_TC(tp, ptrace__PT_KILL_with_signal_full_sigqueue);
ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_signal_system_call_entry);
ATF_TP_ADD_TC(tp,
ptrace__PT_CONTINUE_with_signal_system_call_entry_and_exit);
ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_signal_full_sigqueue);
ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_signal_masked_full_sigqueue);
ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_change_sig);
ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_sigtrap_system_call_entry);
ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_signal_mix);
ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_signal_kqueue);
ATF_TP_ADD_TC(tp, ptrace__killed_with_sigmask);
ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_sigmask);
ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_with_signal_thread_sigmask);
ATF_TP_ADD_TC(tp, ptrace__PT_REGSET);
ATF_TP_ADD_TC(tp, ptrace__parent_terminate_with_pending_sigstop1);
ATF_TP_ADD_TC(tp, ptrace__parent_terminate_with_pending_sigstop2);
ATF_TP_ADD_TC(tp, ptrace__event_mask_sigkill_discard);
ATF_TP_ADD_TC(tp, ptrace__PT_ATTACH_with_SBDRY_thread);
ATF_TP_ADD_TC(tp, ptrace__PT_STEP_with_signal);
#ifdef HAVE_BREAKPOINT
ATF_TP_ADD_TC(tp, ptrace__breakpoint_siginfo);
#endif
ATF_TP_ADD_TC(tp, ptrace__step_siginfo);
#if defined(HAVE_BREAKPOINT) && defined(SKIP_BREAK)
ATF_TP_ADD_TC(tp, ptrace__PT_CONTINUE_different_thread);
#endif
ATF_TP_ADD_TC(tp, ptrace__PT_LWPINFO_stale_siginfo);
ATF_TP_ADD_TC(tp, ptrace__syscall_args);
ATF_TP_ADD_TC(tp, ptrace__syscall_args_anywhere);
ATF_TP_ADD_TC(tp, ptrace__proc_reparent);
ATF_TP_ADD_TC(tp, ptrace__procdesc_wait_child);
ATF_TP_ADD_TC(tp, ptrace__procdesc_reparent_wait_child);
ATF_TP_ADD_TC(tp, ptrace__PT_SC_REMOTE_getpid);
ATF_TP_ADD_TC(tp, ptrace__reap_kill_stopped);
ATF_TP_ADD_TC(tp, ptrace__PT_ATTACH_no_EINTR);
ATF_TP_ADD_TC(tp, ptrace__PT_DETACH_continued);
return (atf_no_error());
}