root/tests/sys/kern/ptrace_test.c
/*-
 * Copyright (c) 2015 John Baldwin <jhb@FreeBSD.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#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>

/*
 * Architectures with a user-visible breakpoint().
 */
#if defined(__aarch64__) || defined(__amd64__) || defined(__arm__) ||   \
    defined(__i386__) || defined(__riscv)
#define HAVE_BREAKPOINT
#endif

/*
 * Adjust PC to skip over a breakpoint when stopped for a breakpoint trap.
 */
#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

/*
 * A variant of ATF_REQUIRE that is suitable for use in child
 * processes.  This only works if the parent process is tripped up by
 * the early exit and fails some requirement itself.
 */
#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];

        /* Use write() not fprintf() to avoid possible duplicate output. */
        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)
{

        /* Attach the parent process as a tracer of this process. */
        CHILD_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);

        /* Trigger a stop. */
        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)
{

        /*
         * Wait for a process to exit.  This is kind of gross, but
         * there is not a better way.
         *
         * Prior to r325719, the kern.proc.pid.<pid> sysctl failed
         * with ESRCH.  After that change, a valid struct kinfo_proc
         * is returned for zombies with ki_stat set to SZOMB.
         */
        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);
        }
}

/*
 * Verify that a parent debugger process "sees" the exit of a debugged
 * process exactly once when attached via PT_TRACE_ME.
 */
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) {
                /* Child process. */
                trace_me();

                _exit(1);
        }

        /* Parent process. */

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(child, &status, 0);
        REQUIRE_EQ(wpid, child);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Continue the child ignoring the SIGSTOP. */
        ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);

        /* The second wait() should report the exit status. */
        wpid = waitpid(child, &status, 0);
        REQUIRE_EQ(wpid, child);
        ATF_REQUIRE(WIFEXITED(status));
        REQUIRE_EQ(WEXITSTATUS(status), 1);

        /* The child should no longer exist. */
        wpid = waitpid(child, &status, 0);
        REQUIRE_EQ(wpid, -1);
        REQUIRE_EQ(errno, ECHILD);
}

/*
 * Verify that a parent debugger process "sees" the exit of a debugged
 * process exactly once when attached via PT_ATTACH.
 */
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) {
                /* Child process. */
                close(cpipe[0]);

                /* Wait for the parent to attach. */
                CHILD_REQUIRE_EQ(0, read(cpipe[1], &c, sizeof(c)));

                _exit(1);
        }
        close(cpipe[1]);

        /* Parent process. */

        /* Attach to the child process. */
        attach_child(child);

        /* Continue the child ignoring the SIGSTOP. */
        ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);

        /* Signal the child to exit. */
        close(cpipe[0]);

        /* The second wait() should report the exit status. */
        wpid = waitpid(child, &status, 0);
        REQUIRE_EQ(wpid, child);
        ATF_REQUIRE(WIFEXITED(status));
        REQUIRE_EQ(WEXITSTATUS(status), 1);

        /* The child should no longer exist. */
        wpid = waitpid(child, &status, 0);
        REQUIRE_EQ(wpid, -1);
        REQUIRE_EQ(errno, ECHILD);
}

/*
 * Verify that a parent process "sees" the exit of a debugged process only
 * after the debugger has seen it.
 */
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) {
                /* Child process. */
                close(cpipe[0]);

                /* Wait for parent to be ready. */
                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) {
                /* Debugger process. */
                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);

                /* Signal parent that debugger is attached. */
                CHILD_REQUIRE_EQ(write(dpipe[1], &c, sizeof(c)),
                    (ssize_t)sizeof(c));

                /* Wait for parent's failed wait. */
                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]);

        /* Parent process. */

        /* Wait for the debugger to attach to the child. */
        REQUIRE_EQ(read(dpipe[0], &c, sizeof(c)), (ssize_t)sizeof(c));

        /* Release the child. */
        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);

        /*
         * This wait should return a pid of 0 to indicate no status to
         * report.  The parent should see the child as non-exited
         * until the debugger sees the exit.
         */
        wpid = waitpid(child, &status, WNOHANG);
        REQUIRE_EQ(wpid, 0);

        /* Signal the debugger to wait for the child. */
        close(dpipe[0]);

        /* Wait for the debugger. */
        wpid = waitpid(debugger, &status, 0);
        REQUIRE_EQ(wpid, debugger);
        ATF_REQUIRE(WIFEXITED(status));
        REQUIRE_EQ(WEXITSTATUS(status), 0);

        /* The child process should now be ready. */
        wpid = waitpid(child, &status, WNOHANG);
        REQUIRE_EQ(wpid, child);
        ATF_REQUIRE(WIFEXITED(status));
        REQUIRE_EQ(WEXITSTATUS(status), 1);
}

/*
 * Verify that a parent process "sees" the exit of a debugged process
 * only after a non-direct-child debugger has seen it.  In particular,
 * various wait() calls in the parent must avoid failing with ESRCH by
 * checking the parent's orphan list for the debugee.
 */
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) {
                /* Child process. */
                close(cpipe[0]);

                /* Wait for parent to be ready. */
                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) {
                /* Debugger parent. */

                /*
                 * Fork again and drop the debugger parent so that the
                 * debugger is not a child of the main parent.
                 */
                CHILD_REQUIRE((fpid = fork()) != -1);
                if (fpid != 0)
                        _exit(2);

                /* Debugger process. */
                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);

                /* Signal parent that debugger is attached. */
                CHILD_REQUIRE_EQ(write(dpipe[1], &c, sizeof(c)),
                    (ssize_t)sizeof(c));

                /* Wait for parent's failed wait. */
                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]);

        /* Parent process. */

        /* Wait for the debugger parent process to exit. */
        wpid = waitpid(debugger, &status, 0);
        REQUIRE_EQ(wpid, debugger);
        ATF_REQUIRE(WIFEXITED(status));
        REQUIRE_EQ(WEXITSTATUS(status), 2);

        /* A WNOHANG wait here should see the non-exited child. */
        wpid = waitpid(child, &status, WNOHANG);
        REQUIRE_EQ(wpid, 0);

        /* Wait for the debugger to attach to the child. */
        REQUIRE_EQ(read(dpipe[0], &c, sizeof(c)), (ssize_t)sizeof(c));

        /* Release the child. */
        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);

        /*
         * This wait should return a pid of 0 to indicate no status to
         * report.  The parent should see the child as non-exited
         * until the debugger sees the exit.
         */
        wpid = waitpid(child, &status, WNOHANG);
        REQUIRE_EQ(wpid, 0);

        /* Signal the debugger to wait for the child. */
        REQUIRE_EQ(write(dpipe[0], &c, sizeof(c)), (ssize_t)sizeof(c));

        /* Wait for the debugger. */
        REQUIRE_EQ(read(dpipe[0], &c, sizeof(c)), 0);
        close(dpipe[0]);

        /* The child process should now be ready. */
        wpid = waitpid(child, &status, WNOHANG);
        REQUIRE_EQ(wpid, child);
        ATF_REQUIRE(WIFEXITED(status));
        REQUIRE_EQ(WEXITSTATUS(status), 1);
}

/*
 * Make sure that we can collect the exit status of an orphaned process.
 */
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);
}

/*
 * The parent process should always act the same regardless of how the
 * debugger is attached to it.
 */
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)
                /* Child */
                _exit(2);

        wpid = waitpid(fpid, &status, 0);
        CHILD_REQUIRE_EQ(wpid, fpid);
        CHILD_REQUIRE(WIFEXITED(status));
        CHILD_REQUIRE_EQ(WEXITSTATUS(status), 2);

        _exit(1);
}

/*
 * Helper routine for follow fork tests.  This waits for two stops
 * that report both "sides" of a fork.  It returns the pid of the new
 * child process.
 */
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;
        
        /*
         * Each process should report a fork event.  The parent should
         * report a PL_FLAG_FORKED event, and the child should report
         * a PL_FLAG_CHILD event.
         */
        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);
}

/*
 * Verify that a new child process is stopped after a followed fork and
 * that the traced parent sees the exit of the child after the debugger
 * when both processes remain attached to the debugger.
 */
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);
        }

        /* Parent process. */
        children[0] = fpid;

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Continue the child ignoring the SIGSTOP. */
        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);

        /*
         * The child can't exit until the grandchild reports status, so the
         * grandchild should report its exit first to the debugger.
         */
        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);
}

/*
 * Verify that a new child process is stopped after a followed fork
 * and that the traced parent sees the exit of the child when the new
 * child process is detached after it reports its fork.
 */
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);
        }

        /* Parent process. */
        children[0] = fpid;

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Continue the child ignoring the SIGSTOP. */
        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);

        /*
         * Should not see any status from the grandchild now, only the
         * child.
         */
        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);
}

/*
 * Verify that a new child process is stopped after a followed fork
 * and that the traced parent sees the exit of the child when the
 * traced parent is detached after the fork.
 */
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);
        }

        /* Parent process. */
        children[0] = fpid;

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Continue the child ignoring the SIGSTOP. */
        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);

        /*
         * The child can't exit until the grandchild reports status, so the
         * grandchild should report its exit first to the debugger.
         *
         * Even though the child process is detached, it is still a
         * child of the debugger, so it will still report it's exit
         * after the grandchild.
         */
        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]);

        /* Double-fork to disassociate from the debugger. */
        CHILD_REQUIRE((fpid = fork()) != -1);
        if (fpid != 0)
                _exit(3);
        
        /* Send the pid of the disassociated child to the debugger. */
        fpid = getpid();
        CHILD_REQUIRE_EQ(write(cpipe[1], &fpid, sizeof(fpid)),
            (ssize_t)sizeof(fpid));

        /* Wait for the debugger to attach. */
        CHILD_REQUIRE_EQ(read(cpipe[1], &fpid, sizeof(fpid)), 0);
}

/*
 * Verify that a new child process is stopped after a followed fork and
 * that the traced parent sees the exit of the child after the debugger
 * when both processes remain attached to the debugger.  In this test
 * the parent that forks is not a direct child of the debugger.
 */
ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_both_attached_unrelated_debugger);
ATF_TC_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);
        }

        /* Parent process. */
        close(cpipe[1]);

        /* Wait for the direct child to exit. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFEXITED(status));
        REQUIRE_EQ(WEXITSTATUS(status), 3);

        /* Read the pid of the fork parent. */
        REQUIRE_EQ(read(cpipe[0], &children[0], sizeof(children[0])),
            (ssize_t)sizeof(children[0]));

        /* Attach to the fork parent. */
        attach_child(children[0]);

        ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);

        /* Continue the fork parent ignoring the SIGSTOP. */
        ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);

        /* Signal the fork parent to continue. */
        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);

        /*
         * The fork parent can't exit until the child reports status,
         * so the child should report its exit first to the debugger.
         */
        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);
}

/*
 * Verify that a new child process is stopped after a followed fork
 * and that the traced parent sees the exit of the child when the new
 * child process is detached after it reports its fork.  In this test
 * the parent that forks is not a direct child of the debugger.
 */
ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached_unrelated_debugger);
ATF_TC_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);
        }

        /* Parent process. */
        close(cpipe[1]);

        /* Wait for the direct child to exit. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFEXITED(status));
        REQUIRE_EQ(WEXITSTATUS(status), 3);

        /* Read the pid of the fork parent. */
        REQUIRE_EQ(read(cpipe[0], &children[0], sizeof(children[0])),
            (ssize_t)sizeof(children[0]));

        /* Attach to the fork parent. */
        attach_child(children[0]);

        ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);

        /* Continue the fork parent ignoring the SIGSTOP. */
        ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);

        /* Signal the fork parent to continue. */
        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);

        /*
         * Should not see any status from the child now, only the fork
         * parent.
         */
        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);
}

/*
 * Verify that a new child process is stopped after a followed fork
 * and that the traced parent sees the exit of the child when the
 * traced parent is detached after the fork.  In this test the parent
 * that forks is not a direct child of the debugger.
 */
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);
        }

        /* Parent process. */
        close(cpipe[1]);

        /* Wait for the direct child to exit. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFEXITED(status));
        REQUIRE_EQ(WEXITSTATUS(status), 3);

        /* Read the pid of the fork parent. */
        REQUIRE_EQ(read(cpipe[0], &children[0], sizeof(children[0])),
            (ssize_t)sizeof(children[0]));

        /* Attach to the fork parent. */
        attach_child(children[0]);

        ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);

        /* Continue the fork parent ignoring the SIGSTOP. */
        ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);

        /* Signal the fork parent to continue. */
        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);

        /*
         * Should not see any status from the fork parent now, only
         * the child.
         */
        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);
}

/*
 * Verify that a child process does not see an unrelated debugger as its
 * parent but sees its original parent process.
 */
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) {
                /* Child process. */
                close(cpipe[0]);

                /* Wait for parent to be ready. */
                CHILD_REQUIRE_EQ(read(cpipe[1], &c, sizeof(c)),
                    (ssize_t)sizeof(c));

                /* Report the parent PID to the parent. */
                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) {
                /* Debugger process. */
                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);

                /* Signal parent that debugger is attached. */
                CHILD_REQUIRE_EQ(write(dpipe[1], &c, sizeof(c)),
                    (ssize_t)sizeof(c));

                /* Wait for traced child to exit. */
                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]);

        /* Parent process. */

        /* Wait for the debugger to attach to the child. */
        REQUIRE_EQ(read(dpipe[0], &c, sizeof(c)), (ssize_t)sizeof(c));

        /* Release the child. */
        REQUIRE_EQ(write(cpipe[0], &c, sizeof(c)), (ssize_t)sizeof(c));

        /* Read the parent PID from the child. */
        REQUIRE_EQ(read(cpipe[0], &ppid, sizeof(ppid)), (ssize_t)sizeof(ppid));
        close(cpipe[0]);

        REQUIRE_EQ(ppid, getpid());

        /* Wait for the debugger. */
        wpid = waitpid(debugger, &status, 0);
        REQUIRE_EQ(wpid, debugger);
        ATF_REQUIRE(WIFEXITED(status));
        REQUIRE_EQ(WEXITSTATUS(status), 0);

        /* The child process should now be ready. */
        wpid = waitpid(child, &status, WNOHANG);
        REQUIRE_EQ(wpid, child);
        ATF_REQUIRE(WIFEXITED(status));
        REQUIRE_EQ(WEXITSTATUS(status), 1);
}

/*
 * Verify that pl_syscall_code in struct ptrace_lwpinfo for a new
 * child process created via fork() reports the correct value.
 */
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);
        }

        /* Parent process. */
        children[0] = fpid;

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Continue the child ignoring the SIGSTOP. */
        ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);

        /* Wait for both halves of the fork event to get reported. */
        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);

        /*
         * The child can't exit until the grandchild reports status, so the
         * grandchild should report its exit first to the debugger.
         */
        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);
}

/*
 * Verify that pl_syscall_code in struct ptrace_lwpinfo for a new
 * child process created via vfork() reports the correct value.
 */
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);
        }

        /* Parent process. */
        children[0] = fpid;

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Continue the child ignoring the SIGSTOP. */
        ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);

        /* Wait for both halves of the fork event to get reported. */
        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);

        /*
         * The child can't exit until the grandchild reports status, so the
         * grandchild should report its exit first to the debugger.
         */
        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);
}

/*
 * Verify that pl_syscall_code in struct ptrace_lwpinfo for a new
 * thread reports the correct value.
 */
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();
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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;

        /*
         * Continue the child ignoring the SIGSTOP and tracing all
         * system call exits.
         */
        ATF_REQUIRE(ptrace(PT_TO_SCX, fpid, (caddr_t)1, 0) != -1);

        /*
         * Wait for the new thread to arrive.  pthread_create() might
         * invoke any number of system calls.  For now we just wait
         * for the new thread to arrive and make sure it reports a
         * valid system call code.  If ptrace grows thread event
         * reporting then this test can be made more precise.
         */
        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)
                        /* New thread seen. */
                        break;

                REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
        }

        /* Wait for the child to exit. */
        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);
}

/*
 * Verify that the expected LWP events are reported for a child thread.
 */
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();
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Continue the child ignoring the SIGSTOP. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The first event should be for the child thread's birth. */
        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);

        /* The next event should be for the child thread's death. */
        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);

        /* The last event should be for the child process's exit. */
        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);
}

/*
 * Verify that the expected LWP events are reported for a multithreaded
 * process that calls execve(2).
 */
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();
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Continue the child ignoring the SIGSTOP. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The first event should be for the child thread's birth. */
        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);

        /*
         * The next event should be for the main thread's death due to
         * single threading from execve().
         */
        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);

        /* The next event should be for the child process's exec. */
        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);

        /* The last event should be for the child process's exit. */
        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);
}

/*
 * Verify that the expected ptrace event is reported for a signal.
 */
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();
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* The next event should be for the SIGINFO. */
        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);

        /* The last event should be for the child process's exit. */
        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);
}

/*
 * Verify that the expected ptrace events are reported for PTRACE_EXEC.
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Should get one event at exit. */
        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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* The next event should be for the child process's exec. */
        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);

        /* The last event should be for the child process's exit. */
        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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* PT_FOLLOW_FORK should toggle the state of PTRACE_FORK. */
        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));

        /* PT_LWP_EVENTS should toggle the state of PTRACE_LWP. */
        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);

        /* Should get one event at exit. */
        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);
}

/*
 * Verify that the expected ptrace events are reported for PTRACE_VFORK.
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);
        
        /* Continue the child ignoring the SIGSTOP. */
        ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) != -1);

        /* The next event should report the end of the vfork. */
        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);
        }

        /* Parent process. */
        children[0] = fpid;

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Continue the child ignoring the SIGSTOP. */
        ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);

        /* Wait for both halves of the fork event to get reported. */
        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);

        /*
         * The child can't exit until the grandchild reports status, so the
         * grandchild should report its exit first to the debugger.
         */
        wpid = waitpid(children[1], &status, 0);
        REQUIRE_EQ(wpid, children[1]);
        ATF_REQUIRE(WIFEXITED(status));
        REQUIRE_EQ(WEXITSTATUS(status), 2);

        /*
         * The child should report it's vfork() completion before it
         * exits.
         */
        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
/*
 * Verify that no more events are reported after PT_KILL except for the
 * process exit when stopped due to a breakpoint trap.
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Continue the child ignoring the SIGSTOP. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The second wait() should report hitting the breakpoint. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGTRAP);

        /* Kill the child process. */
        REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0);

        /* The last wait() should report the SIGKILL. */
        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 /* HAVE_BREAKPOINT */

/*
 * Verify that no more events are reported after PT_KILL except for the
 * process exit when stopped inside of a system call.
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Continue the child ignoring the SIGSTOP and tracing system calls. */
        REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);

        /* The second wait() should report a system call entry for getpid(). */
        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);

        /* Kill the child process. */
        REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0);

        /* The last wait() should report the SIGKILL. */
        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);
}

/*
 * Verify that no more events are reported after PT_KILL except for the
 * process exit when killing a multithreaded process.
 */
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();
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Continue the child ignoring the SIGSTOP. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The first event should be for the child thread's birth. */
        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);

        /* Kill the child process. */
        REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0);

        /* The last wait() should report the SIGKILL. */
        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);

        /* Sync up with other thread after sigmask updated. */
        pthread_barrier_wait(pbarrier);

        for (;;)
                sleep(60);

        return (NULL);
}

/*
 * Verify that the SIGKILL from PT_KILL takes priority over other signals
 * and prevents spurious stops due to those other signals.
 */
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) {
                /* Bind to one CPU so only one thread at a time will run. */
                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);

                /*
                 * Give the main thread higher priority. The test always
                 * assumes that, if both threads are able to run, the main
                 * thread runs first.
                 */
                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);

                /* Sync up with other thread after sigmask updated. */
                pthread_barrier_wait(&barrier);

                trace_me();

                for (;;)
                        sleep(60);

                exit(1);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Continue the child ignoring the SIGSTOP. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* Send a signal that only the second thread can handle. */
        REQUIRE_EQ(kill(fpid, SIGUSR2), 0);

        /* The second wait() should report the SIGUSR2. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGUSR2);

        /* Send a signal that only the first thread can handle. */
        REQUIRE_EQ(kill(fpid, SIGUSR1), 0);

        /* Replace the SIGUSR2 with a kill. */
        REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0);

        /* The last wait() should report the SIGKILL (not the SIGUSR signal). */
        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);
}

/*
 * Verify that the SIGKILL from PT_KILL takes priority over other stop events
 * and prevents spurious stops caused by those events.
 */
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();

                /* Bind to one CPU so only one thread at a time will run. */
                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);

                /*
                 * Give the main thread higher priority. The test always
                 * assumes that, if both threads are able to run, the main
                 * thread runs first.
                 */
                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);

                /* Sync up with other thread after sigmask updated. */
                pthread_barrier_wait(&barrier);

                /* Sync up with the test before doing the getpid(). */
                raise(SIGSTOP);

                getpid();
                exit(1);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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;

        /* Continue the child ignoring the SIGSTOP and tracing system calls. */
        REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);

        /*
         * Continue until child is done with setup, which is indicated with
         * SIGSTOP. Ignore system calls in the meantime.
         */
        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);
        }

        /* Proceed, allowing main thread to hit syscall entry for getpid(). */
        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);
        /* Prevent the main thread from hitting its syscall exit for now. */
        REQUIRE_EQ(ptrace(PT_SUSPEND, main_lwp, 0, 0), 0);

        /*
         * Proceed, allowing second thread to hit syscall exit for
         * pthread_barrier_wait().
         */
        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);

        /* Send a signal that only the second thread can handle. */
        REQUIRE_EQ(kill(fpid, SIGUSR2), 0);

        REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);

        /* The next wait() should report the SIGUSR2. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGUSR2);

        /* Allow the main thread to try to finish its system call. */
        REQUIRE_EQ(ptrace(PT_RESUME, main_lwp, 0, 0), 0);

        /*
         * At this point, the main thread is in the middle of a system call and
         * has been resumed. The second thread has taken a SIGUSR2 which will
         * be replaced with a SIGKILL below. The main thread will get to run
         * first. It should notice the kill request (even though the signal
         * replacement occurred in the other thread) and exit accordingly.  It
         * should not stop for the system call exit event.
         */

        /* Replace the SIGUSR2 with a kill. */
        REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0);

        /* The last wait() should report the SIGKILL (not a syscall exit). */
        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);
}

/*
 * Verify that even if the signal queue is full for a child process,
 * a PT_KILL will kill the process.
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Fill the signal queue. */
        for (i = 0; i < max_pending_per_proc; ++i)
                REQUIRE_EQ(kill(fpid, SIGUSR1), 0);

        /* Kill the child process. */
        REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0);

        /* The last wait() should report the SIGKILL. */
        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);
}

/*
 * Verify that when stopped at a system call entry, a signal can be
 * requested with PT_CONTINUE which will be delivered once the system
 * call is complete.
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Continue the child ignoring the SIGSTOP and tracing system calls. */
        REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);

        /* The second wait() should report a system call entry for getpid(). */
        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);

        /* Continue the child process with a signal. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);

        for (;;) {
                /*
                 * The last wait() should report exit 2, i.e., a normal _exit
                 * from the signal handler. In the meantime, catch and proceed
                 * past any syscall stops.
                 */
                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);
}

/*
 * Verify that, when continuing from a stop at system call entry and exit,
 * a signal can be requested from both stops, and both will be delivered when
 * the system call is complete.
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Continue the child ignoring the SIGSTOP and tracing system calls. */
        REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);

        /* The second wait() should report a system call entry for getpid(). */
        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);

        /* Continue the child process with a signal. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);

        /* The third wait() should report a system call exit for getpid(). */
        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);

        /* Continue the child process with a signal. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);

        for (;;) {
                /*
                 * The last wait() should report exit 2, i.e., a normal _exit
                 * from the signal handler. In the meantime, catch and proceed
                 * past any syscall stops.
                 */
                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);
}

/*
 * Verify that even if the signal queue is full for a child process,
 * a PT_CONTINUE with a signal will not result in loss of that signal.
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Fill the signal queue. */
        for (i = 0; i < max_pending_per_proc; ++i)
                REQUIRE_EQ(kill(fpid, SIGUSR2), 0);

        /* Continue with signal. */
        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 {
                        /*
                         * The last wait() should report normal _exit from the
                         * SIGUSR1 handler.
                         */
                        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);
}

/*
 * Verify that even if the signal queue is full for a child process,
 * and the signal is masked, a PT_CONTINUE with a signal will not
 * result in loss of that signal.
 */
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);

                /* Allow the pending SIGUSR1 in now. */
                CHILD_REQUIRE_EQ(sigprocmask(SIG_UNBLOCK, &sigmask, NULL), 0);
                /* Wait to receive the SIGUSR1. */
                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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Fill the signal queue. */
        for (i = 0; i < max_pending_per_proc; ++i)
                REQUIRE_EQ(kill(fpid, SIGUSR2), 0);

        /* Continue with signal. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);

        /* Collect and ignore all of the SIGUSR2. */
        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);
        }

        /* Now our PT_CONTINUE'd SIGUSR1 should cause a stop after unmask. */
        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);

        /* Continue the child, ignoring the SIGUSR1. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The last wait() should report exit after receiving SIGUSR1. */
        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);
}

/*
 * Verify that, after stopping due to a signal, that signal can be
 * replaced with another signal.
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Send a signal without ptrace. */
        REQUIRE_EQ(kill(fpid, SIGINT), 0);

        /* The second wait() should report a SIGINT was received. */
        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);

        /* Continue the child process with a different signal. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGTERM), 0);

        /*
         * The last wait() should report having died due to the new
         * signal, SIGTERM.
         */
        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);
}

/*
 * Verify that a signal can be passed through to the child even when there
 * was no true signal originally. Such cases arise when a SIGTRAP is
 * invented for e.g, system call stops.
 */
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();
                /* SIGTRAP expected to cause exit on syscall entry. */
                rl.rlim_cur = rl.rlim_max = 0;
                REQUIRE_EQ(setrlimit(RLIMIT_CORE, &rl), 0);
                getpid();
                exit(1);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Continue the child ignoring the SIGSTOP and tracing system calls. */
        REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);

        /* The second wait() should report a system call entry for getpid(). */
        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);

        /* Continue the child process with a SIGTRAP. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGTRAP), 0);

        for (;;) {
                /*
                 * The last wait() should report exit due to SIGTRAP.  In the
                 * meantime, catch and proceed past any syscall stops.
                 */
                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);
}

/*
 * A mixed bag PT_CONTINUE with signal test.
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Continue the child ignoring the SIGSTOP and tracing system calls. */
        REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);

        /* The second wait() should report a system call entry for getpid(). */
        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);

        /* Continue with the first SIGUSR1. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);

        /* The next wait() should report a system call exit for getpid(). */
        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);

        /* Send an ABRT without ptrace. */
        REQUIRE_EQ(kill(fpid, SIGABRT), 0);

        /* Continue normally. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The next wait() should report the SIGABRT. */
        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);

        /* Continue, replacing the SIGABRT with another SIGUSR1. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);

        for (;;) {
                /*
                 * The last wait() should report exit 2, i.e., a normal _exit
                 * from the signal handler. In the meantime, catch and proceed
                 * past any syscall stops.
                 */
                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);
}

/*
 * Verify a signal delivered by ptrace is noticed by kevent(2).
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Continue with the SIGUSR1. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);

        /*
         * The last wait() should report normal exit with code 1.
         */
        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;

        /* Wait for this thread to receive a SIGUSR1. */
        do {
                err = sem_wait(&sigusr1_sem);
                CHILD_REQUIRE(err == 0 || errno == EINTR);
        } while (err != 0 && errno == EINTR);

        /* Free our companion thread from the barrier. */
        pthread_barrier_wait(pbarrier);

        /*
         * Swap ignore duties; the next SIGUSR1 should go to the
         * other thread.
         */
        CHILD_REQUIRE_EQ(sigemptyset(&sigmask), 0);
        CHILD_REQUIRE_EQ(sigaddset(&sigmask, SIGUSR1), 0);
        CHILD_REQUIRE_EQ(pthread_sigmask(SIG_BLOCK, &sigmask, NULL), 0);

        /* Sync up threads after swapping signal masks. */
        pthread_barrier_wait(pbarrier);

        /* Wait until our companion has received its SIGUSR1. */
        pthread_barrier_wait(pbarrier);

        return (NULL);
}

/*
 * Verify that a traced process with blocked signal received the
 * signal from kill() once unmasked.
 */
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);

                /* Allow the pending SIGUSR1 in now. */
                CHILD_REQUIRE_EQ(sigprocmask(SIG_UNBLOCK, &sigmask, NULL), 0);
                /* Wait to receive a SIGUSR1. */
                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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Send blocked SIGUSR1 which should cause a stop. */
        REQUIRE_EQ(kill(fpid, SIGUSR1), 0);

        /* Continue the child ignoring the SIGSTOP. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The next wait() should report the kill(SIGUSR1) was received. */
        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);

        /* Continue the child, allowing in the SIGUSR1. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);

        /* The last wait() should report normal exit with code 1. */
        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);
}

/*
 * Verify that a traced process with blocked signal received the
 * signal from PT_CONTINUE once unmasked.
 */
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);

                /* Allow the pending SIGUSR1 in now. */
                CHILD_REQUIRE_EQ(sigprocmask(SIG_UNBLOCK, &sigmask, NULL), 0);
                /* Wait to receive a SIGUSR1. */
                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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Continue the child replacing SIGSTOP with SIGUSR1. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);

        /* The next wait() should report the SIGUSR1 was received. */
        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);

        /* Continue the child, ignoring the SIGUSR1. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The last wait() should report normal exit with code 1. */
        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);
}

/*
 * Verify that if ptrace stops due to a signal but continues with
 * a different signal that the new signal is routed to a thread
 * that can accept it, and that the thread is awakened by the signal
 * in a timely manner.
 */
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);

                /* The other thread should receive the first SIGUSR1. */
                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();

                /* Wait until other thread has received its SIGUSR1. */
                pthread_barrier_wait(&barrier);

                /*
                 * Swap ignore duties; the next SIGUSR1 should go to this
                 * thread.
                 */
                CHILD_REQUIRE_EQ(pthread_sigmask(SIG_UNBLOCK, &sigmask, NULL),
                    0);

                /* Sync up threads after swapping signal masks. */
                pthread_barrier_wait(&barrier);

                /*
                 * Sync up with test code; we're ready for the next SIGUSR1
                 * now.
                 */
                raise(SIGSTOP);

                /* Wait for this thread to receive a SIGUSR1. */
                do {
                        err = sem_wait(&sigusr1_sem);
                        CHILD_REQUIRE(err == 0 || errno == EINTR);
                } while (err != 0 && errno == EINTR);

                /* Free the other thread from the barrier. */
                pthread_barrier_wait(&barrier);

                CHILD_REQUIRE_EQ(pthread_join(t, NULL), 0);

                exit(1);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Continue the child ignoring the SIGSTOP. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /*
         * Send a signal without ptrace that either thread will accept (USR2,
         * in this case).
         */
        REQUIRE_EQ(kill(fpid, SIGUSR2), 0);

        /* The second wait() should report a SIGUSR2 was received. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGUSR2);

        /* Continue the child, changing the signal to USR1. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);

        /* The next wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Continue the child ignoring the SIGSTOP. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        REQUIRE_EQ(kill(fpid, SIGUSR2), 0);

        /* The next wait() should report a SIGUSR2 was received. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGUSR2);

        /* Continue the child, changing the signal to USR1. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, SIGUSR1), 0);

        /* The last wait() should report normal exit with code 1. */
        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);
}

/*
 * Verify that PT_GETREGSET returns registers and PT_SETREGSET updates them.
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(child, &status, 0);
        REQUIRE_EQ(wpid, child);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Check the size is returned when vec.iov_base is NULL */
        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);

        /* Read the registers. */
        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));

        /* Write the registers back. */
        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);

        /* The second wait() should report the exit status. */
        wpid = waitpid(child, &status, 0);
        REQUIRE_EQ(wpid, child);
        ATF_REQUIRE(WIFEXITED(status));
        REQUIRE_EQ(WEXITSTATUS(status), 1);

        /* The child should no longer exist. */
        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;

        /*
         * Become the reaper for this process tree. We need to be able to check
         * that both child and grandchild have died.
         */
        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();

                        /* Pin to CPU 0 to serialize thread execution. */
                        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) {
                                /*
                                 * We expect the SIGKILL sent when our parent
                                 * dies to be delivered to the new thread.
                                 * Raise the SIGSTOP in this thread so the
                                 * threads compete.
                                 */
                                CHILD_REQUIRE(pthread_create(&t, NULL,
                                    sleep_thread, NULL) == 0);
                                raise(SIGSTOP);
                        } else {
                                /*
                                 * We expect the SIGKILL to be delivered to
                                 * this thread. After creating the new thread,
                                 * just get off the CPU so the other thread can
                                 * raise the SIGSTOP.
                                 */
                                CHILD_REQUIRE(pthread_create(&t, NULL,
                                    raise_sigstop_thread, NULL) == 0);
                                sleep(60);
                        }

                        exit(0);
                }
                /* First stop is trace_me() immediately after fork. */
                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);

                /* Second stop is from the raise(SIGSTOP). */
                wpid = waitpid(fpid, &status, 0);
                CHILD_REQUIRE_EQ(wpid, fpid);
                CHILD_REQUIRE(WIFSTOPPED(status));
                CHILD_REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

                /*
                 * Terminate tracing process without detaching. Our child
                 * should be killed.
                 */
                exit(0);
        }

        /*
         * We should get a normal exit from our immediate child and a SIGKILL
         * exit from our grandchild. The latter case is the interesting one.
         * Our grandchild should not have stopped due to the SIGSTOP that was
         * left dangling when its parent died.
         */
        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);
                }
        }
}

/*
 * These two tests ensure that if the tracing process exits without detaching
 * just after the child received a SIGSTOP, the child is cleanly killed and
 * doesn't go to sleep due to the SIGSTOP. The parent's death will send a
 * SIGKILL to the child. If the SIGKILL and the SIGSTOP are handled by
 * different threads, the SIGKILL must win.  There are two variants of this
 * test, designed to catch the case where the SIGKILL is delivered to the
 * younger thread (the first test) and the case where the SIGKILL is delivered
 * to the older thread (the second test). This behavior has changed in the
 * past, so make no assumption.
 */
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);
}

/*
 * Verify that after ptrace() discards a SIGKILL signal, the event mask
 * is not modified.
 */
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);
        }

        /* The first wait() should report the stop from trace_me(). */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Set several unobtrusive event bits. */
        event_mask = PTRACE_EXEC | PTRACE_FORK | PTRACE_LWP;
        ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, wpid, (caddr_t)&event_mask,
            sizeof(event_mask)) == 0);

        /* Send a SIGKILL without using ptrace. */
        REQUIRE_EQ(kill(fpid, SIGKILL), 0);

        /* Continue the child ignoring the SIGSTOP. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The next stop should be due to the SIGKILL. */
        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);

        /* Continue the child ignoring the SIGKILL. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The next wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Check the current event mask. It should not have changed. */
        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);

        /* Continue the child to let it exit. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The last event should be for the child process's exit. */
        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);
}

/*
 * Verify that PT_ATTACH will suspend threads sleeping in an SBDRY section.
 * We rely on the fact that the lockf implementation sets SBDRY before blocking
 * on a lock. This is a regression test for r318191.
 */
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);

                /*
                 * We want at least two threads blocked on the file lock since
                 * the SIGSTOP from PT_ATTACH may kick one of them out of
                 * sleep.
                 */
                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);

        /*
         * Give the child some time to block. Is there a better way to do this?
         */
        sleep(1);

        /*
         * Attach and give the child 3 seconds to stop.
         */
        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);
}

/*
 * Verify that PT_STEP with a signal invokes the signal before
 * stepping the next instruction (and that the next instruction is
 * stepped correctly).
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* The next stop should report the SIGABRT in the child body. */
        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);

        /* Step the child process inserting SIGUSR1. */
        REQUIRE_EQ(ptrace(PT_STEP, fpid, (caddr_t)1, SIGUSR1), 0);

        /* The next stop should report the SIGABRT in the signal handler. */
        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);

        /* Continue the child process discarding the signal. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The next stop should report a trace trap from PT_STEP. */
        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);

        /* Continue the child to let it exit. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The last event should be for the child process's exit. */
        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
/*
 * Verify that a SIGTRAP event with the TRAP_BRKPT code is reported
 * for a breakpoint trap.
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Continue the child ignoring the SIGSTOP. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The second wait() should report hitting the breakpoint. */
        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);

        /* Kill the child process. */
        REQUIRE_EQ(ptrace(PT_KILL, fpid, 0, 0), 0);

        /* The last wait() should report the SIGKILL. */
        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 /* HAVE_BREAKPOINT */

/*
 * Verify that a SIGTRAP event with the TRAP_TRACE code is reported
 * for a single-step trap from PT_STEP.
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /* Step the child ignoring the SIGSTOP. */
        REQUIRE_EQ(ptrace(PT_STEP, fpid, (caddr_t)1, 0), 0);

        /* The second wait() should report a single-step trap. */
        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);

        /* Continue the child process. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* The last event should be for the child process's exit. */
        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);
}

/*
 * Ensure that PT_CONTINUE clears the status of the thread that
 * triggered the stop even if a different thread's LWP was passed to
 * PT_CONTINUE.
 */
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();
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* Continue the child ignoring the SIGSTOP. */
        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* One of the new threads should report it's birth. */
        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;

        /*
         * Suspend this thread to ensure both threads are alive before
         * hitting the breakpoint.
         */
        ATF_REQUIRE(ptrace(PT_SUSPEND, lwps[0], NULL, 0) != -1);

        REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);

        /* Second thread should report it's birth. */
        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;

        /* Resume both threads waiting for breakpoint events. */
        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);

        /* One thread should report a breakpoint. */
        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)&reg, 0) != -1);
        SKIP_BREAK(&reg);
        ATF_REQUIRE(ptrace(PT_SETREGS, pl.pl_lwpid, (caddr_t)&reg, 0) != -1);

        /*
         * Resume both threads but pass the other thread's LWPID to
         * PT_CONTINUE.
         */
        REQUIRE_EQ(ptrace(PT_CONTINUE, lwps[i ^ 1], (caddr_t)1, 0), 0);

        /*
         * Will now get two thread exit events and one more breakpoint
         * event.
         */
        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)&reg,
                            0) != -1);
                        SKIP_BREAK(&reg);
                        ATF_REQUIRE(ptrace(PT_SETREGS, pl.pl_lwpid, (caddr_t)&reg,
                            0) != -1);
                }

                REQUIRE_EQ(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0), 0);
        }

        /* Both threads should have exited. */
        REQUIRE_EQ(lwps[0], 0);
        REQUIRE_EQ(lwps[1], 0);

        /* The last event should be for the child process's exit. */
        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

/*
 * Verify that PT_LWPINFO doesn't return stale siginfo.
 */
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);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        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);

        /* The next stop should report the SIGABRT in the child body. */
        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);

        /*
         * Continue the process ignoring the signal, but enabling
         * syscall traps.
         */
        REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);

        /*
         * The next stop should report a system call entry from
         * exit().  PL_FLAGS_SI should not be set.
         */
        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);

        /* Disable syscall tracing and continue the child to let it exit. */
        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);

        /* The last event should be for the child process's exit. */
        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);
}

/*
 * A simple test of PT_GET_SC_ARGS and PT_GET_SC_RET.
 */
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 a fd that should not exist. */
                close(12345);
                exit(1);
        }

        /* The first wait() should report the stop from SIGSTOP. */
        wpid = waitpid(fpid, &status, 0);
        REQUIRE_EQ(wpid, fpid);
        ATF_REQUIRE(WIFSTOPPED(status));
        REQUIRE_EQ(WSTOPSIG(status), SIGSTOP);

        /*
         * Continue the process ignoring the signal, but enabling
         * syscall traps.
         */
        REQUIRE_EQ(ptrace(PT_SYSCALL, fpid, (caddr_t)1, 0), 0);

        /*
         * The next stop should be the syscall entry from getpid().
         */
        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);

        /*
         * The next stop should be the syscall exit from getpid().
         */
        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);

        /*
         * The next stop should be the syscall entry from kill().
         */
        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);

        /*
         * The next stop should be the syscall exit from kill().
         */
        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);

        /*
         * The next stop should be the syscall entry from close().
         */
        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);

        /*
         * The next stop should be the syscall exit from close().
         */
        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);

        /* Disable syscall tracing and continue the child to let it exit. */
        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);

        /* The last event should be for the child process's exit. */
        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);
}

/*
 * Check that syscall info is available whenever kernel has valid td_sa.
 * Assumes that libc nanosleep(2) is the plain syscall wrapper.
 */
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);
        }

        /* Give the debuggee some time to go to sleep. */
        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);
}

/*
 * Verify that when the process is traced that it isn't reparent
 * to the init process when we close all process descriptors.
 */
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) {
                /* The traced process is reparented to debuger. */
                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);

                /* We closed pd so we should not have any child. */
                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);

        /* Check if we still have any child. */
        wpid = wait(&status);
        REQUIRE_EQ(wpid, -1);
        REQUIRE_EQ(errno, ECHILD);
}

/*
 * Ensure that traced processes created with pdfork(2) are visible to
 * waitid(P_ALL).
 */
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);

        /*
         * If process was created by pdfork, the return code have to
         * be collected through process descriptor.
         */
        wpid = wait(&status);
        REQUIRE_EQ(wpid, -1);
        REQUIRE_EQ(errno, ECHILD);

        ATF_REQUIRE(close(pd) != -1);
}

/*
 * Ensure that traced processes created with pdfork(2) are not visible
 * after returning to parent - waitid(P_ALL).
 */
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);

        /* Wait until the child process has stopped before fork()ing again. */
        REQUIRE_EQ(traced, waitpid(traced, &status, WSTOPPED));
        debuger = fork();
        ATF_REQUIRE(debuger >= 0);
        if (debuger == 0) {
                /* The traced process is reparented to debuger. */
                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);

                /* Allow process to die. */
                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);

                /* Reparent back to the orginal process. */
                REQUIRE_EQ(close(pd), 0);
                exit(0);
        }

        wpid = waitpid(debuger, &status, 0);
        REQUIRE_EQ(wpid, debuger);
        REQUIRE_EQ(WEXITSTATUS(status), 0);

        /*
         * We have a child but it has a process descriptori
         * so we should not be able to collect it process.
         */
        wpid = wait(&status);
        REQUIRE_EQ(wpid, -1);
        REQUIRE_EQ(errno, ECHILD);

        REQUIRE_EQ(close(pd), 0);
}

/*
 * Try using PT_SC_REMOTE to get the PID of a traced child process.
 */
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);
}

/*
 * Ensure that procctl(PROC_REAP_KILL) won't block forever waiting for a target
 * process that stopped to report its status to a debugger.
 */
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);

        /* Resume the child and ask it to stop during syscall exits. */
        ATF_REQUIRE(ptrace(PT_TO_SCX, debuggee, (caddr_t)1, 0) != -1);

        /* Give the debuggee some time to go to sleep. */
        usleep(100000);

        /*
         * Kill the child process.  procctl() may attempt to stop the target
         * process to prevent it from adding new children to the reaper subtree,
         * and this should not conflict with the child stopping itself for the
         * debugger.
         */
        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);
        }

        /* Give the debuggee some time to go to sleep. */
        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;

        /* Setup the debuggee's pipe, which we'll use to let it terminate. */
        ATF_REQUIRE(pipe(dpipe) == 0);
        ATF_REQUIRE((debuggee = fork()) != -1);

        if (debuggee == 0) {
                ssize_t readsz;

                /*
                 * The debuggee will just absorb everything until the parent
                 * closes it.  In the process, we expect it to get SIGSTOP'd,
                 * then ptrace(2)d and finally, it should resume after we detach
                 * and the parent will be notified.
                 */
                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));

        /* Child is stopped, enter the debugger to attach/detach. */
        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));

        /*
         * Closing the pipe will trigger the debuggee to exit now that the
         * child has resumed following detach.
         */
        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());
}