summaryrefslogtreecommitdiffstats
path: root/contrib/netbsd-tests/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/netbsd-tests/kernel')
-rw-r--r--contrib/netbsd-tests/kernel/kqueue/read/t_fifo.c4
-rw-r--r--contrib/netbsd-tests/kernel/kqueue/read/t_file.c4
-rw-r--r--contrib/netbsd-tests/kernel/kqueue/read/t_pipe.c4
-rw-r--r--contrib/netbsd-tests/kernel/kqueue/read/t_ttypty.c4
-rw-r--r--contrib/netbsd-tests/kernel/kqueue/t_ioctl.c7
-rw-r--r--contrib/netbsd-tests/kernel/kqueue/t_proc1.c13
-rw-r--r--contrib/netbsd-tests/kernel/kqueue/t_proc2.c10
-rw-r--r--contrib/netbsd-tests/kernel/kqueue/t_proc3.c9
-rw-r--r--contrib/netbsd-tests/kernel/kqueue/t_sig.c17
-rw-r--r--contrib/netbsd-tests/kernel/kqueue/t_vnode.c536
-rw-r--r--contrib/netbsd-tests/kernel/msg.h136
-rw-r--r--contrib/netbsd-tests/kernel/t_mqueue.c3
-rw-r--r--contrib/netbsd-tests/kernel/t_ptrace.c208
-rw-r--r--contrib/netbsd-tests/kernel/t_ptrace_wait.c5082
-rw-r--r--contrib/netbsd-tests/kernel/t_ptrace_wait.h431
-rw-r--r--contrib/netbsd-tests/kernel/t_ptrace_wait3.c30
-rw-r--r--contrib/netbsd-tests/kernel/t_ptrace_wait4.c30
-rw-r--r--contrib/netbsd-tests/kernel/t_ptrace_wait6.c30
-rw-r--r--contrib/netbsd-tests/kernel/t_ptrace_waitid.c30
-rw-r--r--contrib/netbsd-tests/kernel/t_ptrace_waitpid.c30
-rw-r--r--contrib/netbsd-tests/kernel/t_rnd.c25
21 files changed, 6626 insertions, 17 deletions
diff --git a/contrib/netbsd-tests/kernel/kqueue/read/t_fifo.c b/contrib/netbsd-tests/kernel/kqueue/read/t_fifo.c
index 5908547..19c7b02 100644
--- a/contrib/netbsd-tests/kernel/kqueue/read/t_fifo.c
+++ b/contrib/netbsd-tests/kernel/kqueue/read/t_fifo.c
@@ -78,7 +78,11 @@ ATF_TC_BODY(fifo, tc)
RL(n = kevent(kq, NULL, 0, event, 1, NULL));
(void)printf("kevent num %d filt %d flags: %#x, fflags: %#x, "
+#ifdef __FreeBSD__
+ "data: %" PRIdPTR "\n", n, event[0].filter, event[0].flags,
+#else
"data: %" PRId64 "\n", n, event[0].filter, event[0].flags,
+#endif
event[0].fflags, event[0].data);
ATF_REQUIRE_EQ(event[0].filter, EVFILT_READ);
diff --git a/contrib/netbsd-tests/kernel/kqueue/read/t_file.c b/contrib/netbsd-tests/kernel/kqueue/read/t_file.c
index 2335172..80479af 100644
--- a/contrib/netbsd-tests/kernel/kqueue/read/t_file.c
+++ b/contrib/netbsd-tests/kernel/kqueue/read/t_file.c
@@ -111,7 +111,11 @@ ATF_TC_BODY(file, tc)
num += n;
(void)printf("kevent num %d flags: %#x, fflags: %#x, data: "
+#ifdef __FreeBSD__
+ "%" PRIdPTR "\n", n, event[0].flags, event[0].fflags,
+#else
"%" PRId64 "\n", n, event[0].flags, event[0].fflags,
+#endif
event[0].data);
if (event[0].data < 0)
diff --git a/contrib/netbsd-tests/kernel/kqueue/read/t_pipe.c b/contrib/netbsd-tests/kernel/kqueue/read/t_pipe.c
index d8e05f2..2cdd015 100644
--- a/contrib/netbsd-tests/kernel/kqueue/read/t_pipe.c
+++ b/contrib/netbsd-tests/kernel/kqueue/read/t_pipe.c
@@ -67,7 +67,11 @@ ATF_TC_BODY(pipe, tc)
RL(n = kevent(kq, NULL, 0, event, 1, NULL));
(void)printf("kevent num %d flags: %#x, fflags: %#x, data: "
+#ifdef __FreeBSD__
+ "%" PRIdPTR "\n", n, event[0].flags, event[0].fflags, event[0].data);
+#else
"%" PRId64 "\n", n, event[0].flags, event[0].fflags, event[0].data);
+#endif
RL(n = read(fds[0], buffer, event[0].data));
buffer[n] = '\0';
diff --git a/contrib/netbsd-tests/kernel/kqueue/read/t_ttypty.c b/contrib/netbsd-tests/kernel/kqueue/read/t_ttypty.c
index 3a42fd3..57ccf92 100644
--- a/contrib/netbsd-tests/kernel/kqueue/read/t_ttypty.c
+++ b/contrib/netbsd-tests/kernel/kqueue/read/t_ttypty.c
@@ -103,7 +103,11 @@ h_check(bool check_master)
RL(n = kevent(kq, NULL, 0, event, 1, NULL));
(void)printf("kevent num %d filt %d flags: %#x, fflags: %#x, "
+#ifdef __FreeBSD__
+ "data: %" PRIdPTR "\n", n, event[0].filter, event[0].flags,
+#else
"data: %" PRId64 "\n", n, event[0].filter, event[0].flags,
+#endif
event[0].fflags, event[0].data);
ATF_REQUIRE_EQ(event[0].filter, EVFILT_READ);
diff --git a/contrib/netbsd-tests/kernel/kqueue/t_ioctl.c b/contrib/netbsd-tests/kernel/kqueue/t_ioctl.c
index 8ed5a79..d996fdf 100644
--- a/contrib/netbsd-tests/kernel/kqueue/t_ioctl.c
+++ b/contrib/netbsd-tests/kernel/kqueue/t_ioctl.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ioctl.c,v 1.1 2009/02/20 21:39:57 jmmv Exp $ */
+/* $NetBSD: t_ioctl.c,v 1.2 2015/01/14 22:22:32 christos Exp $ */
/*-
* Copyright (c) 2002, 2008 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
#include <sys/cdefs.h>
__COPYRIGHT("@(#) Copyright (c) 2008\
The NetBSD Foundation, inc. All rights reserved.");
-__RCSID("$NetBSD: t_ioctl.c,v 1.1 2009/02/20 21:39:57 jmmv Exp $");
+__RCSID("$NetBSD: t_ioctl.c,v 1.2 2015/01/14 22:22:32 christos Exp $");
#include <sys/event.h>
#include <sys/ioctl.h>
@@ -53,7 +53,8 @@ ATF_TC_BODY(kfilter_byfilter, tc)
{
char buf[32];
struct kfilter_mapping km;
- int i, kq;
+ int kq;
+ uint32_t i;
RL(kq = kqueue());
diff --git a/contrib/netbsd-tests/kernel/kqueue/t_proc1.c b/contrib/netbsd-tests/kernel/kqueue/t_proc1.c
index e755309..aa806ba 100644
--- a/contrib/netbsd-tests/kernel/kqueue/t_proc1.c
+++ b/contrib/netbsd-tests/kernel/kqueue/t_proc1.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_proc1.c,v 1.1 2009/02/20 21:39:57 jmmv Exp $ */
+/* $NetBSD: t_proc1.c,v 1.2 2015/01/14 22:22:32 christos Exp $ */
/*-
* Copyright (c) 2002, 2008 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
#include <sys/cdefs.h>
__COPYRIGHT("@(#) Copyright (c) 2008\
The NetBSD Foundation, inc. All rights reserved.");
-__RCSID("$NetBSD: t_proc1.c,v 1.1 2009/02/20 21:39:57 jmmv Exp $");
+__RCSID("$NetBSD: t_proc1.c,v 1.2 2015/01/14 22:22:32 christos Exp $");
/*
* this also used to trigger problem fixed in
@@ -99,7 +99,8 @@ ATF_TC_BODY(proc1, tc)
{
struct kevent event[1];
pid_t pid;
- int kq, want, status;
+ int kq, status;
+ u_int want;
RL(kq = kqueue());
@@ -112,7 +113,7 @@ ATF_TC_BODY(proc1, tc)
(void)sleep(1); /* give child some time to come up */
- event[0].ident = pid;
+ event[0].ident = (uintptr_t)pid;
event[0].filter = EVFILT_PROC;
event[0].flags = EV_ADD | EV_ENABLE;
event[0].fflags = NOTE_EXIT | NOTE_FORK | NOTE_EXEC; /* | NOTE_TRACK;*/
@@ -138,7 +139,11 @@ ATF_TC_BODY(proc1, tc)
printf(" NOTE_FORK");
}
if (event[0].fflags & NOTE_CHILD)
+#ifdef __FreeBSD__
+ printf(" NOTE_CHILD, parent = %" PRIdPTR, event[0].data);
+#else
printf(" NOTE_CHILD, parent = %" PRId64, event[0].data);
+#endif
printf("\n");
}
diff --git a/contrib/netbsd-tests/kernel/kqueue/t_proc2.c b/contrib/netbsd-tests/kernel/kqueue/t_proc2.c
index 54769d6..2d8d7f7 100644
--- a/contrib/netbsd-tests/kernel/kqueue/t_proc2.c
+++ b/contrib/netbsd-tests/kernel/kqueue/t_proc2.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_proc2.c,v 1.1 2009/02/20 21:39:57 jmmv Exp $ */
+/* $NetBSD: t_proc2.c,v 1.2 2015/01/14 22:22:32 christos Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -32,8 +32,11 @@
#include <sys/cdefs.h>
__COPYRIGHT("@(#) Copyright (c) 2008\
The NetBSD Foundation, inc. All rights reserved.");
-__RCSID("$NetBSD: t_proc2.c,v 1.1 2009/02/20 21:39:57 jmmv Exp $");
+__RCSID("$NetBSD: t_proc2.c,v 1.2 2015/01/14 22:22:32 christos Exp $");
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#endif
#include <sys/event.h>
#include <sys/time.h>
#include <sys/types.h>
@@ -106,7 +109,8 @@ ATF_TC_BODY(proc2, tc)
/* NOTREACHED */
}
- EV_SET(&ke, pid, EVFILT_PROC, EV_ADD, NOTE_FORK|NOTE_TRACK, 0, 0);
+ EV_SET(&ke, (uintptr_t)pid, EVFILT_PROC, EV_ADD, NOTE_FORK|NOTE_TRACK,
+ 0, 0);
RL(kevent(kq, &ke, 1, NULL, 0, &timeout));
diff --git a/contrib/netbsd-tests/kernel/kqueue/t_proc3.c b/contrib/netbsd-tests/kernel/kqueue/t_proc3.c
index 3cb9ae5..eac2f9c 100644
--- a/contrib/netbsd-tests/kernel/kqueue/t_proc3.c
+++ b/contrib/netbsd-tests/kernel/kqueue/t_proc3.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_proc3.c,v 1.1 2012/11/17 21:55:24 joerg Exp $ */
+/* $NetBSD: t_proc3.c,v 1.2 2015/01/14 22:22:32 christos Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
@@ -30,8 +30,11 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_proc3.c,v 1.1 2012/11/17 21:55:24 joerg Exp $");
+__RCSID("$NetBSD: t_proc3.c,v 1.2 2015/01/14 22:22:32 christos Exp $");
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#endif
#include <sys/event.h>
#include <sys/time.h>
#include <sys/types.h>
@@ -63,7 +66,7 @@ ATF_TC_BODY(proc3, tc)
RL(kq = kqueue());
- EV_SET(&ke, getpid(), EVFILT_PROC, EV_ADD, NOTE_TRACK, 0, 0);
+ EV_SET(&ke, (uintptr_t)getpid(), EVFILT_PROC, EV_ADD, NOTE_TRACK, 0, 0);
RL(kevent(kq, &ke, 1, NULL, 0, NULL));
diff --git a/contrib/netbsd-tests/kernel/kqueue/t_sig.c b/contrib/netbsd-tests/kernel/kqueue/t_sig.c
index 4fc0758..ebbd76e 100644
--- a/contrib/netbsd-tests/kernel/kqueue/t_sig.c
+++ b/contrib/netbsd-tests/kernel/kqueue/t_sig.c
@@ -34,6 +34,9 @@ __COPYRIGHT("@(#) Copyright (c) 2008\
The NetBSD Foundation, inc. All rights reserved.");
__RCSID("$NetBSD: t_sig.c,v 1.2 2010/11/03 16:10:20 christos Exp $");
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#endif
#include <sys/event.h>
#include <sys/ioctl.h>
#include <sys/param.h>
@@ -60,9 +63,13 @@ ATF_TC_HEAD(sig, tc)
ATF_TC_BODY(sig, tc)
{
struct timespec timeout;
+#ifdef __NetBSD__
struct kfilter_mapping km;
+#endif
struct kevent event[1];
+#ifdef __NetBSD__
char namebuf[32];
+#endif
pid_t pid, child;
int kq, n, num, status;
@@ -84,16 +91,22 @@ ATF_TC_BODY(sig, tc)
RL(kq = kqueue());
+#ifdef __NetBSD__
(void)strlcpy(namebuf, "EVFILT_SIGNAL", sizeof(namebuf));
km.name = namebuf;
RL(ioctl(kq, KFILTER_BYNAME, &km));
(void)printf("got %d as filter number for `%s'.\n", km.filter, km.name);
+#endif
/* ignore the signal to avoid taking it for real */
REQUIRE_LIBC(signal(SIGUSR1, SIG_IGN), SIG_ERR);
event[0].ident = SIGUSR1;
+#ifdef __NetBSD__
event[0].filter = km.filter;
+#else
+ event[0].filter = EVFILT_SIGNAL;
+#endif
event[0].flags = EV_ADD | EV_ENABLE;
RL(kevent(kq, event, 1, NULL, 0, NULL));
@@ -117,7 +130,11 @@ ATF_TC_BODY(sig, tc)
if (n == 0)
continue;
+#ifdef __FreeBSD__
+ (void)printf("sig: kevent flags: 0x%x, data: %" PRIdPTR " (# "
+#else
(void)printf("sig: kevent flags: 0x%x, data: %" PRId64 " (# "
+#endif
"times signal posted)\n", event[0].flags, event[0].data);
}
diff --git a/contrib/netbsd-tests/kernel/kqueue/t_vnode.c b/contrib/netbsd-tests/kernel/kqueue/t_vnode.c
new file mode 100644
index 0000000..06ef683
--- /dev/null
+++ b/contrib/netbsd-tests/kernel/kqueue/t_vnode.c
@@ -0,0 +1,536 @@
+#ifdef __FreeBSD__
+#include <sys/types.h>
+#endif
+#include <sys/event.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+/*
+ * Test cases for events triggered by manipulating a target directory
+ * content. Using EVFILT_VNODE filter on the target directory descriptor.
+ *
+ */
+
+static const char *dir_target = "foo";
+static const char *dir_inside1 = "foo/bar1";
+static const char *dir_inside2 = "foo/bar2";
+static const char *dir_outside = "bar";
+static const char *file_inside1 = "foo/baz1";
+static const char *file_inside2 = "foo/baz2";
+static const char *file_outside = "qux";
+static const struct timespec ts = {0, 0};
+static int kq = -1;
+static int target = -1;
+
+int init_target(void);
+int init_kqueue(void);
+int create_file(const char *);
+void cleanup(void);
+
+int
+init_target(void)
+{
+ if (mkdir(dir_target, S_IRWXU) < 0) {
+ return -1;
+ }
+ target = open(dir_target, O_RDONLY, 0);
+ return target;
+}
+
+int
+init_kqueue(void)
+{
+ struct kevent eventlist[1];
+
+ kq = kqueue();
+ if (kq < 0) {
+ return -1;
+ }
+ EV_SET(&eventlist[0], (uintptr_t)target, EVFILT_VNODE,
+ EV_ADD | EV_ONESHOT, NOTE_DELETE |
+ NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB |
+ NOTE_LINK | NOTE_RENAME | NOTE_REVOKE, 0, 0);
+ return kevent(kq, eventlist, 1, NULL, 0, NULL);
+}
+
+int
+create_file(const char *file)
+{
+ int fd;
+
+ fd = open(file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+ if (fd < 0) {
+ return -1;
+ }
+ return close(fd);
+}
+
+void
+cleanup(void)
+{
+ (void)unlink(file_inside1);
+ (void)unlink(file_inside2);
+ (void)unlink(file_outside);
+ (void)rmdir(dir_inside1);
+ (void)rmdir(dir_inside2);
+ (void)rmdir(dir_outside);
+ (void)rmdir(dir_target);
+ (void)close(kq);
+ (void)close(target);
+}
+
+ATF_TC_WITH_CLEANUP(dir_no_note_link_create_file_in);
+ATF_TC_HEAD(dir_no_note_link_create_file_in, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) does not return NOTE_LINK for the directory "
+ "'foo' if a file 'foo/baz' is created.");
+}
+ATF_TC_BODY(dir_no_note_link_create_file_in, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(create_file(file_inside1) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, 0);
+}
+ATF_TC_CLEANUP(dir_no_note_link_create_file_in, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_no_note_link_delete_file_in);
+ATF_TC_HEAD(dir_no_note_link_delete_file_in, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) does not return NOTE_LINK for the directory "
+ "'foo' if a file 'foo/baz' is deleted.");
+}
+ATF_TC_BODY(dir_no_note_link_delete_file_in, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(create_file(file_inside1) != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(unlink(file_inside1) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, 0);
+}
+ATF_TC_CLEANUP(dir_no_note_link_delete_file_in, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_no_note_link_mv_dir_within);
+ATF_TC_HEAD(dir_no_note_link_mv_dir_within, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) does not return NOTE_LINK for the directory "
+ "'foo' if a directory 'foo/bar' is renamed to 'foo/baz'.");
+}
+ATF_TC_BODY(dir_no_note_link_mv_dir_within, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(rename(dir_inside1, dir_inside2) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, 0);
+}
+ATF_TC_CLEANUP(dir_no_note_link_mv_dir_within, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_no_note_link_mv_file_within);
+ATF_TC_HEAD(dir_no_note_link_mv_file_within, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) does not return NOTE_LINK for the directory "
+ "'foo' if a file 'foo/baz' is renamed to 'foo/qux'.");
+}
+ATF_TC_BODY(dir_no_note_link_mv_file_within, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(create_file(file_inside1) != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(rename(file_inside1, file_inside2) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, 0);
+}
+ATF_TC_CLEANUP(dir_no_note_link_mv_file_within, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_note_link_create_dir_in);
+ATF_TC_HEAD(dir_note_link_create_dir_in, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) returns NOTE_LINK for the directory "
+ "'foo' if a directory 'foo/bar' is created.");
+}
+ATF_TC_BODY(dir_note_link_create_dir_in, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, NOTE_LINK);
+}
+ATF_TC_CLEANUP(dir_note_link_create_dir_in, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_note_link_delete_dir_in);
+ATF_TC_HEAD(dir_note_link_delete_dir_in, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) returns NOTE_LINK for the directory "
+ "'foo' if a directory 'foo/bar' is deleted.");
+}
+ATF_TC_BODY(dir_note_link_delete_dir_in, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(rmdir(dir_inside1) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, NOTE_LINK);
+}
+ATF_TC_CLEANUP(dir_note_link_delete_dir_in, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_note_link_mv_dir_in);
+ATF_TC_HEAD(dir_note_link_mv_dir_in, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) returns NOTE_LINK for the directory "
+ "'foo' if a directory 'bar' is renamed to 'foo/bar'.");
+}
+ATF_TC_BODY(dir_note_link_mv_dir_in, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(mkdir(dir_outside, S_IRWXU) != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(rename(dir_outside, dir_inside1) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, NOTE_LINK);
+}
+ATF_TC_CLEANUP(dir_note_link_mv_dir_in, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_note_link_mv_dir_out);
+ATF_TC_HEAD(dir_note_link_mv_dir_out, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) returns NOTE_LINK for the directory "
+ "'foo' if a directory 'foo/bar' is renamed to 'bar'.");
+}
+ATF_TC_BODY(dir_note_link_mv_dir_out, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(rename(dir_inside1, dir_outside) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_LINK, NOTE_LINK);
+}
+ATF_TC_CLEANUP(dir_note_link_mv_dir_out, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_note_write_create_dir_in);
+ATF_TC_HEAD(dir_note_write_create_dir_in, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) returns NOTE_WRITE for the directory "
+ "'foo' if a directory 'foo/bar' is created.");
+}
+ATF_TC_BODY(dir_note_write_create_dir_in, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
+}
+ATF_TC_CLEANUP(dir_note_write_create_dir_in, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_note_write_create_file_in);
+ATF_TC_HEAD(dir_note_write_create_file_in, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) returns NOTE_WRITE for the directory "
+ "'foo' if a file 'foo/baz' is created.");
+}
+ATF_TC_BODY(dir_note_write_create_file_in, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(create_file(file_inside1) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
+}
+ATF_TC_CLEANUP(dir_note_write_create_file_in, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_note_write_delete_dir_in);
+ATF_TC_HEAD(dir_note_write_delete_dir_in, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) returns NOTE_WRITE for the directory "
+ "'foo' if a directory 'foo/bar' is deleted.");
+}
+ATF_TC_BODY(dir_note_write_delete_dir_in, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(rmdir(dir_inside1) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
+}
+ATF_TC_CLEANUP(dir_note_write_delete_dir_in, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_note_write_delete_file_in);
+ATF_TC_HEAD(dir_note_write_delete_file_in, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) returns NOTE_WRITE for the directory "
+ "'foo' if a file 'foo/baz' is deleted.");
+}
+ATF_TC_BODY(dir_note_write_delete_file_in, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(create_file(file_inside1) != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(unlink(file_inside1) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
+}
+ATF_TC_CLEANUP(dir_note_write_delete_file_in, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_note_write_mv_dir_in);
+ATF_TC_HEAD(dir_note_write_mv_dir_in, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) returns NOTE_WRITE for the directory "
+ "'foo' if a directory 'bar' is renamed to 'foo/bar'.");
+}
+ATF_TC_BODY(dir_note_write_mv_dir_in, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(mkdir(dir_outside, S_IRWXU) != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(rename(dir_outside, dir_inside1) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
+}
+ATF_TC_CLEANUP(dir_note_write_mv_dir_in, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_note_write_mv_dir_out);
+ATF_TC_HEAD(dir_note_write_mv_dir_out, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) returns NOTE_WRITE for the directory "
+ "'foo' if a directory 'foo/bar' is renamed to 'bar'.");
+}
+ATF_TC_BODY(dir_note_write_mv_dir_out, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(rename(dir_inside1, dir_outside) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
+}
+ATF_TC_CLEANUP(dir_note_write_mv_dir_out, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_note_write_mv_dir_within);
+ATF_TC_HEAD(dir_note_write_mv_dir_within, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) returns NOTE_WRITE for the directory "
+ "'foo' if a directory 'foo/bar' is renamed to 'foo/baz'.");
+}
+ATF_TC_BODY(dir_note_write_mv_dir_within, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(mkdir(dir_inside1, S_IRWXU) != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(rename(dir_inside1, dir_inside2) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
+}
+ATF_TC_CLEANUP(dir_note_write_mv_dir_within, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_note_write_mv_file_in);
+ATF_TC_HEAD(dir_note_write_mv_file_in, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) returns NOTE_WRITE for the directory "
+ "'foo' if a file 'qux' is renamed to 'foo/baz'.");
+}
+ATF_TC_BODY(dir_note_write_mv_file_in, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(create_file(file_outside) != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(rename(file_outside, file_inside1) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
+}
+ATF_TC_CLEANUP(dir_note_write_mv_file_in, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_note_write_mv_file_out);
+ATF_TC_HEAD(dir_note_write_mv_file_out, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) returns NOTE_WRITE for the directory "
+ "'foo' if a file 'foo/baz' is renamed to 'qux'.");
+}
+ATF_TC_BODY(dir_note_write_mv_file_out, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(create_file(file_inside1) != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(rename(file_inside1, file_outside) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
+}
+ATF_TC_CLEANUP(dir_note_write_mv_file_out, tc)
+{
+ cleanup();
+}
+
+ATF_TC_WITH_CLEANUP(dir_note_write_mv_file_within);
+ATF_TC_HEAD(dir_note_write_mv_file_within, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "This test case ensures "
+ "that kevent(2) returns NOTE_WRITE for the directory "
+ "'foo' if a file 'foo/baz' is renamed to 'foo/qux'.");
+}
+ATF_TC_BODY(dir_note_write_mv_file_within, tc)
+{
+ struct kevent changelist[1];
+
+ ATF_REQUIRE(init_target() != -1);
+ ATF_REQUIRE(create_file(file_inside1) != -1);
+ ATF_REQUIRE(init_kqueue() != -1);
+
+ ATF_REQUIRE(rename(file_inside1, file_inside2) != -1);
+ ATF_REQUIRE(kevent(kq, NULL, 0, changelist, 1, &ts) != -1);
+ ATF_CHECK_EQ(changelist[0].fflags & NOTE_WRITE, NOTE_WRITE);
+}
+ATF_TC_CLEANUP(dir_note_write_mv_file_within, tc)
+{
+ cleanup();
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, dir_no_note_link_create_file_in);
+ ATF_TP_ADD_TC(tp, dir_no_note_link_delete_file_in);
+ ATF_TP_ADD_TC(tp, dir_no_note_link_mv_dir_within);
+ ATF_TP_ADD_TC(tp, dir_no_note_link_mv_file_within);
+ ATF_TP_ADD_TC(tp, dir_note_link_create_dir_in);
+ ATF_TP_ADD_TC(tp, dir_note_link_delete_dir_in);
+ ATF_TP_ADD_TC(tp, dir_note_link_mv_dir_in);
+ ATF_TP_ADD_TC(tp, dir_note_link_mv_dir_out);
+ ATF_TP_ADD_TC(tp, dir_note_write_create_dir_in);
+ ATF_TP_ADD_TC(tp, dir_note_write_create_file_in);
+ ATF_TP_ADD_TC(tp, dir_note_write_delete_dir_in);
+ ATF_TP_ADD_TC(tp, dir_note_write_delete_file_in);
+ ATF_TP_ADD_TC(tp, dir_note_write_mv_dir_in);
+ ATF_TP_ADD_TC(tp, dir_note_write_mv_dir_out);
+ ATF_TP_ADD_TC(tp, dir_note_write_mv_dir_within);
+ ATF_TP_ADD_TC(tp, dir_note_write_mv_file_in);
+ ATF_TP_ADD_TC(tp, dir_note_write_mv_file_out);
+ ATF_TP_ADD_TC(tp, dir_note_write_mv_file_within);
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/kernel/msg.h b/contrib/netbsd-tests/kernel/msg.h
new file mode 100644
index 0000000..547400e
--- /dev/null
+++ b/contrib/netbsd-tests/kernel/msg.h
@@ -0,0 +1,136 @@
+/* $NetBSD: msg.h,v 1.1 2016/12/05 20:10:10 christos Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+struct msg_fds {
+ int pfd[2];
+ int cfd[2];
+};
+
+#define CLOSEFD(fd) do { \
+ if (fd != -1) { \
+ close(fd); \
+ fd = -1; \
+ } \
+} while (/*CONSTCOND*/ 0)
+
+static int
+msg_open(struct msg_fds *fds)
+{
+ if (pipe(fds->pfd) == -1)
+ return -1;
+ if (pipe(fds->cfd) == -1) {
+ close(fds->pfd[0]);
+ close(fds->pfd[1]);
+ return -1;
+ }
+ return 0;
+}
+
+static void
+msg_close(struct msg_fds *fds)
+{
+ CLOSEFD(fds->pfd[0]);
+ CLOSEFD(fds->pfd[1]);
+ CLOSEFD(fds->cfd[0]);
+ CLOSEFD(fds->cfd[1]);
+}
+
+static int
+msg_write_child(const char *info, struct msg_fds *fds, void *msg, size_t len)
+{
+ ssize_t rv;
+ CLOSEFD(fds->cfd[1]);
+ CLOSEFD(fds->pfd[0]);
+
+ printf("Send %s\n", info);
+ rv = write(fds->pfd[1], msg, len);
+ if (rv != (ssize_t)len)
+ return 1;
+// printf("Wait %s\n", info);
+ rv = read(fds->cfd[0], msg, len);
+ if (rv != (ssize_t)len)
+ return 1;
+ return 0;
+}
+
+static int
+msg_write_parent(const char *info, struct msg_fds *fds, void *msg, size_t len)
+{
+ ssize_t rv;
+ CLOSEFD(fds->pfd[1]);
+ CLOSEFD(fds->cfd[0]);
+
+ printf("Send %s\n", info);
+ rv = write(fds->cfd[1], msg, len);
+ if (rv != (ssize_t)len)
+ return 1;
+// printf("Wait %s\n", info);
+ rv = read(fds->pfd[0], msg, len);
+ if (rv != (ssize_t)len)
+ return 1;
+ return 0;
+}
+
+static int
+msg_read_parent(const char *info, struct msg_fds *fds, void *msg, size_t len)
+{
+ ssize_t rv;
+ CLOSEFD(fds->pfd[1]);
+ CLOSEFD(fds->cfd[0]);
+
+ printf("Wait %s\n", info);
+ rv = read(fds->pfd[0], msg, len);
+ if (rv != (ssize_t)len)
+ return 1;
+// printf("Send %s\n", info);
+ rv = write(fds->cfd[1], msg, len);
+ if (rv != (ssize_t)len)
+ return 1;
+ return 0;
+}
+
+static int
+msg_read_child(const char *info, struct msg_fds *fds, void *msg, size_t len)
+{
+ ssize_t rv;
+ CLOSEFD(fds->cfd[1]);
+ CLOSEFD(fds->pfd[0]);
+
+ printf("Wait %s\n", info);
+ rv = read(fds->cfd[0], msg, len);
+ if (rv != (ssize_t)len)
+ return 1;
+// printf("Send %s\n", info);
+ rv = write(fds->pfd[1], msg, len);
+ if (rv != (ssize_t)len)
+ return 1;
+ return 0;
+}
diff --git a/contrib/netbsd-tests/kernel/t_mqueue.c b/contrib/netbsd-tests/kernel/t_mqueue.c
index aa98d91..485269f 100644
--- a/contrib/netbsd-tests/kernel/t_mqueue.c
+++ b/contrib/netbsd-tests/kernel/t_mqueue.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_mqueue.c,v 1.4 2014/03/02 19:56:48 jmmv Exp $ */
+/* $NetBSD: t_mqueue.c,v 1.5 2017/01/10 22:10:22 christos Exp $ */
/*
* Test for POSIX message queue priority handling.
@@ -14,6 +14,7 @@
#endif
#include <atf-c.h>
+#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/contrib/netbsd-tests/kernel/t_ptrace.c b/contrib/netbsd-tests/kernel/t_ptrace.c
new file mode 100644
index 0000000..074a953
--- /dev/null
+++ b/contrib/netbsd-tests/kernel/t_ptrace.c
@@ -0,0 +1,208 @@
+/* $NetBSD: t_ptrace.c,v 1.17 2016/11/13 22:59:31 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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/cdefs.h>
+__RCSID("$NetBSD: t_ptrace.c,v 1.17 2016/11/13 22:59:31 kamil Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "../h_macros.h"
+
+/*
+ * A child process cannot call atf functions and expect them to magically
+ * work like in the parent.
+ * The printf(3) messaging from a child will not work out of the box as well
+ * without estabilishing a communication protocol with its parent. To not
+ * overcomplicate the tests - do not log from a child and use err(3)/errx(3)
+ * wrapped with FORKEE_ASSERT()/FORKEE_ASSERTX() as that is guaranteed to work.
+ */
+#define FORKEE_ASSERTX(x) \
+do { \
+ int ret = (x); \
+ if (!ret) \
+ errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \
+ __FILE__, __LINE__, __func__, #x); \
+} while (0)
+
+#define FORKEE_ASSERT(x) \
+do { \
+ int ret = (x); \
+ if (!ret) \
+ err(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \
+ __FILE__, __LINE__, __func__, #x); \
+} while (0)
+
+ATF_TC(attach_pid0);
+ATF_TC_HEAD(attach_pid0, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Assert that a debugger cannot attach to PID 0");
+}
+
+ATF_TC_BODY(attach_pid0, tc)
+{
+ errno = 0;
+ ATF_REQUIRE_ERRNO(EPERM, ptrace(PT_ATTACH, 0, NULL, 0) == -1);
+}
+
+ATF_TC(attach_pid1);
+ATF_TC_HEAD(attach_pid1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Assert that a debugger cannot attach to PID 1 (as non-root)");
+
+ atf_tc_set_md_var(tc, "require.user", "unprivileged");
+}
+
+ATF_TC_BODY(attach_pid1, tc)
+{
+ ATF_REQUIRE_ERRNO(EPERM, ptrace(PT_ATTACH, 1, NULL, 0) == -1);
+}
+
+ATF_TC(attach_pid1_securelevel);
+ATF_TC_HEAD(attach_pid1_securelevel, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Assert that a debugger cannot attach to PID 1 with "
+ "securelevel >= 1 (as root)");
+
+ atf_tc_set_md_var(tc, "require.user", "root");
+}
+
+ATF_TC_BODY(attach_pid1_securelevel, tc)
+{
+ int level;
+ size_t len = sizeof(level);
+
+ ATF_REQUIRE(sysctlbyname("kern.securelevel", &level, &len, NULL, 0)
+ != -1);
+
+ if (level < 1) {
+ atf_tc_skip("Test must be run with securelevel >= 1");
+ }
+
+ ATF_REQUIRE_ERRNO(EPERM, ptrace(PT_ATTACH, 1, NULL, 0) == -1);
+}
+
+ATF_TC(attach_self);
+ATF_TC_HEAD(attach_self, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Assert that a debugger cannot attach to self (as it's nonsense)");
+}
+
+ATF_TC_BODY(attach_self, tc)
+{
+ ATF_REQUIRE_ERRNO(EINVAL, ptrace(PT_ATTACH, getpid(), NULL, 0) == -1);
+}
+
+ATF_TC(attach_chroot);
+ATF_TC_HEAD(attach_chroot, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Assert that a debugger cannot trace another process unless the "
+ "process's root directory is at or below the tracing process's "
+ "root");
+
+ atf_tc_set_md_var(tc, "require.user", "root");
+}
+
+ATF_TC_BODY(attach_chroot, tc)
+{
+ char buf[PATH_MAX];
+ pid_t child;
+ int fds_toparent[2], fds_fromparent[2];
+ int rv;
+ uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
+
+ (void)memset(buf, '\0', sizeof(buf));
+ ATF_REQUIRE(getcwd(buf, sizeof(buf)) != NULL);
+ (void)strlcat(buf, "/dir", sizeof(buf));
+
+ ATF_REQUIRE(mkdir(buf, 0500) == 0);
+ ATF_REQUIRE(chdir(buf) == 0);
+
+ ATF_REQUIRE(pipe(fds_toparent) == 0);
+ ATF_REQUIRE(pipe(fds_fromparent) == 0);
+ child = atf_utils_fork();
+ if (child == 0) {
+ FORKEE_ASSERT(close(fds_toparent[0]) == 0);
+ FORKEE_ASSERT(close(fds_fromparent[1]) == 0);
+
+ FORKEE_ASSERT(chroot(buf) == 0);
+
+ rv = write(fds_toparent[1], &msg, sizeof(msg));
+ FORKEE_ASSERTX(rv == sizeof(msg));
+
+ ATF_REQUIRE_ERRNO(EPERM,
+ ptrace(PT_ATTACH, getppid(), NULL, 0) == -1);
+
+ rv = read(fds_fromparent[0], &msg, sizeof(msg));
+ FORKEE_ASSERTX(rv == sizeof(msg));
+
+ _exit(0);
+ }
+ ATF_REQUIRE(close(fds_toparent[1]) == 0);
+ ATF_REQUIRE(close(fds_fromparent[0]) == 0);
+
+ printf("Waiting for chrooting of the child PID %d", child);
+ rv = read(fds_toparent[0], &msg, sizeof(msg));
+ ATF_REQUIRE(rv == sizeof(msg));
+
+ printf("Child is ready, it will try to PT_ATTACH to parent\n");
+ rv = write(fds_fromparent[1], &msg, sizeof(msg));
+ ATF_REQUIRE(rv == sizeof(msg));
+
+ printf("fds_fromparent is no longer needed - close it\n");
+ ATF_REQUIRE(close(fds_fromparent[1]) == 0);
+
+ printf("fds_toparent is no longer needed - close it\n");
+ ATF_REQUIRE(close(fds_toparent[0]) == 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+ ATF_TP_ADD_TC(tp, attach_pid0);
+ ATF_TP_ADD_TC(tp, attach_pid1);
+ ATF_TP_ADD_TC(tp, attach_pid1_securelevel);
+ ATF_TP_ADD_TC(tp, attach_self);
+ ATF_TP_ADD_TC(tp, attach_chroot);
+
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/kernel/t_ptrace_wait.c b/contrib/netbsd-tests/kernel/t_ptrace_wait.c
new file mode 100644
index 0000000..e502a03
--- /dev/null
+++ b/contrib/netbsd-tests/kernel/t_ptrace_wait.c
@@ -0,0 +1,5082 @@
+/* $NetBSD: t_ptrace_wait.c,v 1.53 2017/01/10 05:08:24 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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/cdefs.h>
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.53 2017/01/10 05:08:24 kamil Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <machine/reg.h>
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "../h_macros.h"
+
+#include "t_ptrace_wait.h"
+#include "msg.h"
+
+#define PARENT_TO_CHILD(info, fds, msg) \
+ ATF_REQUIRE(msg_write_child(info " to child " # fds, &fds, &msg, sizeof(msg)) == 0)
+
+#define CHILD_FROM_PARENT(info, fds, msg) \
+ FORKEE_ASSERT(msg_read_parent(info " from parent " # fds, &fds, &msg, sizeof(msg)) == 0)
+
+#define CHILD_TO_PARENT(info, fds, msg) \
+ FORKEE_ASSERT(msg_write_parent(info " to parent " # fds, &fds, &msg, sizeof(msg)) == 0)
+
+#define PARENT_FROM_CHILD(info, fds, msg) \
+ ATF_REQUIRE(msg_read_child(info " from parent " # fds, &fds, &msg, sizeof(msg)) == 0)
+
+ATF_TC(traceme1);
+ATF_TC_HEAD(traceme1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify SIGSTOP followed by _exit(2) in a child");
+}
+
+ATF_TC_BODY(traceme1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(traceme2);
+ATF_TC_HEAD(traceme2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify SIGSTOP followed by _exit(2) in a child");
+}
+
+static int traceme2_caught = 0;
+
+static void
+traceme2_sighandler(int sig)
+{
+ FORKEE_ASSERT_EQ(sig, SIGINT);
+
+ ++traceme2_caught;
+}
+
+ATF_TC_BODY(traceme2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP, sigsent = SIGINT;
+ pid_t child, wpid;
+ struct sigaction sa;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ sa.sa_handler = traceme2_sighandler;
+ sa.sa_flags = SA_SIGINFO;
+ sigemptyset(&sa.sa_mask);
+
+ FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(traceme2_caught, 1);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Before resuming the child process where it left off and with "
+ "signal %s to be sent\n", strsignal(sigsent));
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the exited child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(traceme3);
+ATF_TC_HEAD(traceme3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify SIGSTOP followed by termination by a signal in a child");
+}
+
+ATF_TC_BODY(traceme3, tc)
+{
+ const int sigval = SIGSTOP, sigsent = SIGINT /* Without core-dump */;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ /* NOTREACHED */
+ FORKEE_ASSERTX(0 &&
+ "Child should be terminated by a signal from its parent");
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Before resuming the child process where it left off and with "
+ "signal %s to be sent\n", strsignal(sigsent));
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_signaled(status, sigsent, 0);
+
+ printf("Before calling %s() for the exited child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(traceme4);
+ATF_TC_HEAD(traceme4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify SIGSTOP followed by SIGCONT and _exit(2) in a child");
+}
+
+ATF_TC_BODY(traceme4, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP, sigsent = SIGCONT;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before raising %s from child\n", strsignal(sigsent));
+ FORKEE_ASSERT(raise(sigsent) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(),child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigsent);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the exited child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+#if defined(TWAIT_HAVE_PID)
+ATF_TC(attach1);
+ATF_TC_HEAD(attach1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Assert that tracer sees process termination before the parent");
+}
+
+ATF_TC_BODY(attach1, tc)
+{
+ struct msg_fds parent_tracee, parent_tracer;
+ const int exitval_tracee = 5;
+ const int exitval_tracer = 10;
+ pid_t tracee, tracer, wpid;
+ uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Spawn tracee\n");
+ ATF_REQUIRE(msg_open(&parent_tracee) == 0);
+ tracee = atf_utils_fork();
+ if (tracee == 0) {
+ // Wait for parent to let us exit
+ CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
+ _exit(exitval_tracee);
+ }
+
+ printf("Spawn debugger\n");
+ ATF_REQUIRE(msg_open(&parent_tracer) == 0);
+ tracer = atf_utils_fork();
+ if (tracer == 0) {
+ printf("Before calling PT_ATTACH from tracee %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
+
+ /* Wait for tracee and assert that it was stopped w/ SIGSTOP */
+ FORKEE_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
+
+ forkee_status_stopped(status, SIGSTOP);
+
+ /* Resume tracee with PT_CONTINUE */
+ FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
+
+ /* Inform parent that tracer has attached to tracee */
+ CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
+
+ /* Wait for parent to tell use that tracee should have exited */
+ CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
+
+ /* Wait for tracee and assert that it exited */
+ FORKEE_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
+
+ forkee_status_exited(status, exitval_tracee);
+ printf("Tracee %d exited with %d\n", tracee, exitval_tracee);
+
+ printf("Before exiting of the tracer process\n");
+ _exit(exitval_tracer);
+ }
+
+ printf("Wait for the tracer to attach to the tracee\n");
+ PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
+
+ printf("Resume the tracee and let it exit\n");
+ PARENT_TO_CHILD("exit tracee", parent_tracee, msg);
+
+ printf("Detect that tracee is zombie\n");
+ await_zombie(tracee);
+
+
+ printf("Assert that there is no status about tracee %d - "
+ "Tracer must detect zombie first - calling %s()\n", tracee,
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
+
+ printf("Tell the tracer child should have exited\n");
+ PARENT_TO_CHILD("wait for tracee exit", parent_tracer, msg);
+ printf("Wait for tracer to finish its job and exit - calling %s()\n",
+ TWAIT_FNAME);
+
+ printf("Wait from tracer child to complete waiting for tracee\n");
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
+ tracer);
+
+ validate_status_exited(status, exitval_tracer);
+
+ printf("Wait for tracee to finish its job and exit - calling %s()\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
+ tracee);
+
+ validate_status_exited(status, exitval_tracee);
+
+ msg_close(&parent_tracer);
+ msg_close(&parent_tracee);
+}
+#endif
+
+#if defined(TWAIT_HAVE_PID)
+ATF_TC(attach2);
+ATF_TC_HEAD(attach2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Assert that any tracer sees process termination before its "
+ "parent");
+}
+
+ATF_TC_BODY(attach2, tc)
+{
+ struct msg_fds parent_tracer, parent_tracee;
+ const int exitval_tracee = 5;
+ const int exitval_tracer1 = 10, exitval_tracer2 = 20;
+ pid_t tracee, tracer, wpid;
+ uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Spawn tracee\n");
+ ATF_REQUIRE(msg_open(&parent_tracee) == 0);
+ tracee = atf_utils_fork();
+ if (tracee == 0) {
+ /* Wait for message from the parent */
+ CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
+ _exit(exitval_tracee);
+ }
+
+ printf("Spawn debugger\n");
+ ATF_REQUIRE(msg_open(&parent_tracer) == 0);
+ tracer = atf_utils_fork();
+ if (tracer == 0) {
+ /* Fork again and drop parent to reattach to PID 1 */
+ tracer = atf_utils_fork();
+ if (tracer != 0)
+ _exit(exitval_tracer1);
+
+ printf("Before calling PT_ATTACH from tracee %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
+
+ /* Wait for tracee and assert that it was stopped w/ SIGSTOP */
+ FORKEE_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
+
+ forkee_status_stopped(status, SIGSTOP);
+
+ /* Resume tracee with PT_CONTINUE */
+ FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
+
+ /* Inform parent that tracer has attached to tracee */
+ CHILD_TO_PARENT("Message 1", parent_tracer, msg);
+ CHILD_FROM_PARENT("Message 2", parent_tracer, msg);
+
+ /* Wait for tracee and assert that it exited */
+ FORKEE_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
+
+ forkee_status_exited(status, exitval_tracee);
+
+ printf("Before exiting of the tracer process\n");
+ _exit(exitval_tracer2);
+ }
+ printf("Wait for the tracer process (direct child) to exit calling "
+ "%s()\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
+
+ validate_status_exited(status, exitval_tracer1);
+
+ printf("Wait for the non-exited tracee process with %s()\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
+
+ printf("Wait for the tracer to attach to the tracee\n");
+ PARENT_FROM_CHILD("Message 1", parent_tracer, msg);
+ printf("Resume the tracee and let it exit\n");
+ PARENT_TO_CHILD("Message 1", parent_tracee, msg);
+
+ printf("Detect that tracee is zombie\n");
+ await_zombie(tracee);
+
+ printf("Assert that there is no status about tracee - "
+ "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
+
+ printf("Resume the tracer and let it detect exited tracee\n");
+ PARENT_TO_CHILD("Message 2", parent_tracer, msg);
+
+ printf("Wait for tracee to finish its job and exit - calling %s()\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
+ tracee);
+
+ validate_status_exited(status, exitval_tracee);
+
+ msg_close(&parent_tracer);
+ msg_close(&parent_tracee);
+
+}
+#endif
+
+ATF_TC(attach3);
+ATF_TC_HEAD(attach3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Assert that tracer parent can PT_ATTACH to its child");
+}
+
+ATF_TC_BODY(attach3, tc)
+{
+ struct msg_fds parent_tracee;
+ const int exitval_tracee = 5;
+ pid_t tracee, wpid;
+ uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Spawn tracee\n");
+ ATF_REQUIRE(msg_open(&parent_tracee) == 0);
+ tracee = atf_utils_fork();
+ if (tracee == 0) {
+ CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
+ printf("Parent should now attach to tracee\n");
+
+ CHILD_FROM_PARENT("Message 2", parent_tracee, msg);
+ /* Wait for message from the parent */
+ _exit(exitval_tracee);
+ }
+ PARENT_TO_CHILD("Message 1", parent_tracee, msg);
+
+ printf("Before calling PT_ATTACH for tracee %d\n", tracee);
+ ATF_REQUIRE(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
+
+ printf("Wait for the stopped tracee process with %s()\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
+
+ validate_status_stopped(status, SIGSTOP);
+
+ printf("Resume tracee with PT_CONTINUE\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
+
+ printf("Let the tracee exit now\n");
+ PARENT_TO_CHILD("Message 2", parent_tracee, msg);
+
+ printf("Wait for tracee to exit with %s()\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
+
+ validate_status_exited(status, exitval_tracee);
+
+ printf("Before calling %s() for tracee\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD,
+ wpid = TWAIT_GENERIC(tracee, &status, 0));
+
+ msg_close(&parent_tracee);
+}
+
+ATF_TC(attach4);
+ATF_TC_HEAD(attach4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Assert that tracer child can PT_ATTACH to its parent");
+}
+
+ATF_TC_BODY(attach4, tc)
+{
+ struct msg_fds parent_tracee;
+ const int exitval_tracer = 5;
+ pid_t tracer, wpid;
+ uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Spawn tracer\n");
+ ATF_REQUIRE(msg_open(&parent_tracee) == 0);
+ tracer = atf_utils_fork();
+ if (tracer == 0) {
+
+ /* Wait for message from the parent */
+ CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
+
+ printf("Attach to parent PID %d with PT_ATTACH from child\n",
+ getppid());
+ FORKEE_ASSERT(ptrace(PT_ATTACH, getppid(), NULL, 0) != -1);
+
+ printf("Wait for the stopped parent process with %s()\n",
+ TWAIT_FNAME);
+ FORKEE_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(getppid(), &status, 0), getppid());
+
+ forkee_status_stopped(status, SIGSTOP);
+
+ printf("Resume parent with PT_DETACH\n");
+ FORKEE_ASSERT(ptrace(PT_DETACH, getppid(), (void *)1, 0)
+ != -1);
+
+ /* Tell parent we are ready */
+ CHILD_TO_PARENT("Message 1", parent_tracee, msg);
+
+ _exit(exitval_tracer);
+ }
+
+ printf("Wait for the tracer to become ready\n");
+ PARENT_TO_CHILD("Message 1", parent_tracee, msg);
+ printf("Allow the tracer to exit now\n");
+ PARENT_FROM_CHILD("Message 1", parent_tracee, msg);
+
+ printf("Wait for tracer to exit with %s()\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
+
+ validate_status_exited(status, exitval_tracer);
+
+ printf("Before calling %s() for tracer\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD,
+ wpid = TWAIT_GENERIC(tracer, &status, 0));
+
+ msg_close(&parent_tracee);
+}
+
+#if defined(TWAIT_HAVE_PID)
+ATF_TC(attach5);
+ATF_TC_HEAD(attach5, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Assert that tracer sees its parent when attached to tracer "
+ "(check getppid(2))");
+}
+
+ATF_TC_BODY(attach5, tc)
+{
+ struct msg_fds parent_tracer, parent_tracee;
+ const int exitval_tracee = 5;
+ const int exitval_tracer = 10;
+ pid_t parent, tracee, tracer, wpid;
+ uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Spawn tracee\n");
+ ATF_REQUIRE(msg_open(&parent_tracer) == 0);
+ ATF_REQUIRE(msg_open(&parent_tracee) == 0);
+ tracee = atf_utils_fork();
+ if (tracee == 0) {
+ parent = getppid();
+
+ /* Emit message to the parent */
+ CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
+ CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
+
+ FORKEE_ASSERT_EQ(parent, getppid());
+
+ _exit(exitval_tracee);
+ }
+ printf("Wait for child to record its parent identifier (pid)\n");
+ PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
+
+ printf("Spawn debugger\n");
+ tracer = atf_utils_fork();
+ if (tracer == 0) {
+ /* No IPC to communicate with the child */
+ printf("Before calling PT_ATTACH from tracee %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
+
+ /* Wait for tracee and assert that it was stopped w/ SIGSTOP */
+ FORKEE_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
+
+ forkee_status_stopped(status, SIGSTOP);
+
+ /* Resume tracee with PT_CONTINUE */
+ FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
+
+ /* Inform parent that tracer has attached to tracee */
+ CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
+
+ /* Wait for parent to tell use that tracee should have exited */
+ CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
+
+ /* Wait for tracee and assert that it exited */
+ FORKEE_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
+
+ forkee_status_exited(status, exitval_tracee);
+
+ printf("Before exiting of the tracer process\n");
+ _exit(exitval_tracer);
+ }
+
+ printf("Wait for the tracer to attach to the tracee\n");
+ PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
+
+ printf("Resume the tracee and let it exit\n");
+ PARENT_TO_CHILD("exit tracee", parent_tracee, msg);
+
+ printf("Detect that tracee is zombie\n");
+ await_zombie(tracee);
+
+ printf("Assert that there is no status about tracee - "
+ "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
+
+ printf("Tell the tracer child should have exited\n");
+ PARENT_TO_CHILD("wait for tracee exit", parent_tracer, msg);
+
+ printf("Wait from tracer child to complete waiting for tracee\n");
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
+ tracer);
+
+ validate_status_exited(status, exitval_tracer);
+
+ printf("Wait for tracee to finish its job and exit - calling %s()\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
+ tracee);
+
+ validate_status_exited(status, exitval_tracee);
+
+ msg_close(&parent_tracer);
+ msg_close(&parent_tracee);
+}
+#endif
+
+#if defined(TWAIT_HAVE_PID)
+ATF_TC(attach6);
+ATF_TC_HEAD(attach6, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Assert that tracer sees its parent when attached to tracer "
+ "(check sysctl(7) and struct kinfo_proc2)");
+}
+
+ATF_TC_BODY(attach6, tc)
+{
+ struct msg_fds parent_tracee, parent_tracer;
+ const int exitval_tracee = 5;
+ const int exitval_tracer = 10;
+ pid_t parent, tracee, tracer, wpid;
+ uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ int name[CTL_MAXNAME];
+ struct kinfo_proc2 kp;
+ size_t len = sizeof(kp);
+ unsigned int namelen;
+
+ printf("Spawn tracee\n");
+ ATF_REQUIRE(msg_open(&parent_tracee) == 0);
+ ATF_REQUIRE(msg_open(&parent_tracer) == 0);
+ tracee = atf_utils_fork();
+ if (tracee == 0) {
+ parent = getppid();
+
+ /* Emit message to the parent */
+ CHILD_TO_PARENT("Message 1", parent_tracee, msg);
+ CHILD_FROM_PARENT("Message 2", parent_tracee, msg);
+
+ namelen = 0;
+ name[namelen++] = CTL_KERN;
+ name[namelen++] = KERN_PROC2;
+ name[namelen++] = KERN_PROC_PID;
+ name[namelen++] = getpid();
+ name[namelen++] = len;
+ name[namelen++] = 1;
+
+ FORKEE_ASSERT(sysctl(name, namelen, &kp, &len, NULL, 0) == 0);
+ FORKEE_ASSERT_EQ(parent, kp.p_ppid);
+
+ _exit(exitval_tracee);
+ }
+
+ printf("Wait for child to record its parent identifier (pid)\n");
+ PARENT_FROM_CHILD("Message 1", parent_tracee, msg);
+
+ printf("Spawn debugger\n");
+ tracer = atf_utils_fork();
+ if (tracer == 0) {
+ /* No IPC to communicate with the child */
+ printf("Before calling PT_ATTACH from tracee %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
+
+ /* Wait for tracee and assert that it was stopped w/ SIGSTOP */
+ FORKEE_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
+
+ forkee_status_stopped(status, SIGSTOP);
+
+ /* Resume tracee with PT_CONTINUE */
+ FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
+
+ /* Inform parent that tracer has attached to tracee */
+ CHILD_TO_PARENT("Message 1", parent_tracer, msg);
+
+ CHILD_FROM_PARENT("Message 2", parent_tracer, msg);
+
+ /* Wait for tracee and assert that it exited */
+ FORKEE_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
+
+ forkee_status_exited(status, exitval_tracee);
+
+ printf("Before exiting of the tracer process\n");
+ _exit(exitval_tracer);
+ }
+
+ printf("Wait for the tracer to attach to the tracee\n");
+ PARENT_FROM_CHILD("Message 1", parent_tracer, msg);
+
+ printf("Resume the tracee and let it exit\n");
+ PARENT_TO_CHILD("Message 1", parent_tracee, msg);
+
+ printf("Detect that tracee is zombie\n");
+ await_zombie(tracee);
+
+ printf("Assert that there is no status about tracee - "
+ "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
+
+ printf("Resume the tracer and let it detect exited tracee\n");
+ PARENT_TO_CHILD("Message 2", parent_tracer, msg);
+
+ printf("Wait for tracer to finish its job and exit - calling %s()\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
+ tracer);
+
+ validate_status_exited(status, exitval_tracer);
+
+ printf("Wait for tracee to finish its job and exit - calling %s()\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
+ tracee);
+
+ validate_status_exited(status, exitval_tracee);
+
+ msg_close(&parent_tracee);
+ msg_close(&parent_tracer);
+}
+#endif
+
+#if defined(TWAIT_HAVE_PID)
+ATF_TC(attach7);
+ATF_TC_HEAD(attach7, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Assert that tracer sees its parent when attached to tracer "
+ "(check /proc/curproc/status 3rd column)");
+}
+
+ATF_TC_BODY(attach7, tc)
+{
+ struct msg_fds parent_tracee, parent_tracer;
+ int rv;
+ const int exitval_tracee = 5;
+ const int exitval_tracer = 10;
+ pid_t parent, tracee, tracer, wpid;
+ uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ FILE *fp;
+ struct stat st;
+ const char *fname = "/proc/curproc/status";
+ char s_executable[MAXPATHLEN];
+ int s_pid, s_ppid;
+ /*
+ * Format:
+ * EXECUTABLE PID PPID ...
+ */
+
+ ATF_REQUIRE((rv = stat(fname, &st)) == 0 || (errno == ENOENT));
+ if (rv != 0) {
+ atf_tc_skip("/proc/curproc/status not found");
+ }
+
+ printf("Spawn tracee\n");
+ ATF_REQUIRE(msg_open(&parent_tracee) == 0);
+ ATF_REQUIRE(msg_open(&parent_tracer) == 0);
+ tracee = atf_utils_fork();
+ if (tracee == 0) {
+ parent = getppid();
+
+ // Wait for parent to let us exit
+ CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
+ CHILD_FROM_PARENT("tracee exit", parent_tracee, msg);
+
+ FORKEE_ASSERT((fp = fopen(fname, "r")) != NULL);
+ fscanf(fp, "%s %d %d", s_executable, &s_pid, &s_ppid);
+ FORKEE_ASSERT(fclose(fp) == 0);
+ FORKEE_ASSERT_EQ(parent, s_ppid);
+
+ _exit(exitval_tracee);
+ }
+
+ printf("Wait for child to record its parent identifier (pid)\n");
+ PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
+
+ printf("Spawn debugger\n");
+ tracer = atf_utils_fork();
+ if (tracer == 0) {
+ printf("Before calling PT_ATTACH from tracee %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
+
+ /* Wait for tracee and assert that it was stopped w/ SIGSTOP */
+ FORKEE_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
+
+ forkee_status_stopped(status, SIGSTOP);
+
+ /* Resume tracee with PT_CONTINUE */
+ FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
+
+ /* Inform parent that tracer has attached to tracee */
+ CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
+
+ /* Wait for parent to tell use that tracee should have exited */
+ CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
+
+ /* Wait for tracee and assert that it exited */
+ FORKEE_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
+
+ forkee_status_exited(status, exitval_tracee);
+
+ printf("Before exiting of the tracer process\n");
+ _exit(exitval_tracer);
+ }
+ printf("Wait for the tracer to attach to the tracee\n");
+ PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
+ printf("Resume the tracee and let it exit\n");
+ PARENT_TO_CHILD("tracee exit", parent_tracee, msg);
+
+ printf("Detect that tracee is zombie\n");
+ await_zombie(tracee);
+
+ printf("Assert that there is no status about tracee - "
+ "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
+
+ printf("Resume the tracer and let it detect exited tracee\n");
+ PARENT_TO_CHILD("Message 2", parent_tracer, msg);
+
+ printf("Wait for tracer to finish its job and exit - calling %s()\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
+ tracer);
+
+ validate_status_exited(status, exitval_tracer);
+
+ printf("Wait for tracee to finish its job and exit - calling %s()\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
+ tracee);
+
+ validate_status_exited(status, exitval_tracee);
+
+ msg_close(&parent_tracee);
+ msg_close(&parent_tracer);
+}
+#endif
+
+ATF_TC(eventmask1);
+ATF_TC_HEAD(eventmask1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that empty EVENT_MASK is preserved");
+}
+
+ATF_TC_BODY(eventmask1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ ptrace_event_t set_event, get_event;
+ const int len = sizeof(ptrace_event_t);
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ set_event.pe_set_event = 0;
+ ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &set_event, len) != -1);
+ ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, child, &get_event, len) != -1);
+ ATF_REQUIRE(memcmp(&set_event, &get_event, len) == 0);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(eventmask2);
+ATF_TC_HEAD(eventmask2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that PTRACE_FORK in EVENT_MASK is preserved");
+}
+
+ATF_TC_BODY(eventmask2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ ptrace_event_t set_event, get_event;
+ const int len = sizeof(ptrace_event_t);
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ set_event.pe_set_event = PTRACE_FORK;
+ ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &set_event, len) != -1);
+ ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, child, &get_event, len) != -1);
+ ATF_REQUIRE(memcmp(&set_event, &get_event, len) == 0);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+#if defined(TWAIT_HAVE_PID)
+ATF_TC(fork1);
+ATF_TC_HEAD(fork1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that fork(2) is intercepted by ptrace(2) with EVENT_MASK "
+ "set to PTRACE_FORK");
+}
+
+ATF_TC_BODY(fork1, tc)
+{
+ const int exitval = 5;
+ const int exitval2 = 15;
+ const int sigval = SIGSTOP;
+ pid_t child, child2, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ ptrace_state_t state;
+ const int slen = sizeof(state);
+ ptrace_event_t event;
+ const int elen = sizeof(event);
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT((child2 = fork()) != 1);
+
+ if (child2 == 0)
+ _exit(exitval2);
+
+ FORKEE_REQUIRE_SUCCESS
+ (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
+
+ forkee_status_exited(status, exitval2);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Enable PTRACE_FORK in EVENT_MASK for the child %d\n", child);
+ event.pe_set_event = PTRACE_FORK;
+ ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child %d\n", TWAIT_FNAME, child);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
+ ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_FORK);
+
+ child2 = state.pe_other_pid;
+ printf("Reported PTRACE_FORK event with forkee %d\n", child2);
+
+ printf("Before calling %s() for the forkee %d of the child %d\n",
+ TWAIT_FNAME, child2, child);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
+ child2);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
+ ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_FORK);
+ ATF_REQUIRE_EQ(state.pe_other_pid, child);
+
+ printf("Before resuming the forkee process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the forkee - expected exited\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
+ child2);
+
+ validate_status_exited(status, exitval2);
+
+ printf("Before calling %s() for the forkee - expected no process\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD,
+ wpid = TWAIT_GENERIC(child2, &status, 0));
+
+ printf("Before calling %s() for the child - expected stopped "
+ "SIGCHLD\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGCHLD);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child - expected exited\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child - expected no process\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+ATF_TC(fork2);
+ATF_TC_HEAD(fork2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that fork(2) is not intercepted by ptrace(2) with empty "
+ "EVENT_MASK");
+}
+
+ATF_TC_BODY(fork2, tc)
+{
+ const int exitval = 5;
+ const int exitval2 = 15;
+ const int sigval = SIGSTOP;
+ pid_t child, child2, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ ptrace_event_t event;
+ const int elen = sizeof(event);
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT((child2 = fork()) != 1);
+
+ if (child2 == 0)
+ _exit(exitval2);
+
+ FORKEE_REQUIRE_SUCCESS
+ (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
+
+ forkee_status_exited(status, exitval2);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Set empty EVENT_MASK for the child %d\n", child);
+ event.pe_set_event = 0;
+ ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child - expected stopped "
+ "SIGCHLD\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGCHLD);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child - expected exited\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child - expected no process\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+#if defined(TWAIT_HAVE_PID)
+ATF_TC(vfork1);
+ATF_TC_HEAD(vfork1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that vfork(2) is intercepted by ptrace(2) with EVENT_MASK "
+ "set to PTRACE_VFORK");
+}
+
+ATF_TC_BODY(vfork1, tc)
+{
+ const int exitval = 5;
+ const int exitval2 = 15;
+ const int sigval = SIGSTOP;
+ pid_t child, child2, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ ptrace_state_t state;
+ const int slen = sizeof(state);
+ ptrace_event_t event;
+ const int elen = sizeof(event);
+
+ /*
+ * ptrace(2) command PT_SET_EVENT_MASK: option PTRACE_VFORK unsupported
+ */
+#ifndef PTRACE_VFORK
+#define PTRACE_VFORK 0
+#endif
+ atf_tc_expect_fail("PR kern/51630");
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT((child2 = vfork()) != 1);
+
+ if (child2 == 0)
+ _exit(exitval2);
+
+ FORKEE_REQUIRE_SUCCESS
+ (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
+
+ forkee_status_exited(status, exitval2);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Enable PTRACE_VFORK in EVENT_MASK for the child %d\n", child);
+ event.pe_set_event = PTRACE_VFORK;
+ ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child %d\n", TWAIT_FNAME, child);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
+ ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK);
+
+ child2 = state.pe_other_pid;
+ printf("Reported PTRACE_VFORK event with forkee %d\n", child2);
+
+ printf("Before calling %s() for the forkee %d of the child %d\n",
+ TWAIT_FNAME, child2, child);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
+ child2);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ ATF_REQUIRE(ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
+ ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK);
+ ATF_REQUIRE_EQ(state.pe_other_pid, child);
+
+ printf("Before resuming the forkee process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the forkee - expected exited\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
+ child2);
+
+ validate_status_exited(status, exitval2);
+
+ printf("Before calling %s() for the forkee - expected no process\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD,
+ wpid = TWAIT_GENERIC(child2, &status, 0));
+
+ printf("Before calling %s() for the child - expected stopped "
+ "SIGCHLD\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGCHLD);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child - expected exited\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child - expected no process\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+ATF_TC(vfork2);
+ATF_TC_HEAD(vfork2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that vfork(2) is not intercepted by ptrace(2) with empty "
+ "EVENT_MASK");
+}
+
+ATF_TC_BODY(vfork2, tc)
+{
+ const int exitval = 5;
+ const int exitval2 = 15;
+ const int sigval = SIGSTOP;
+ pid_t child, child2, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ ptrace_event_t event;
+ const int elen = sizeof(event);
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT((child2 = vfork()) != 1);
+
+ if (child2 == 0)
+ _exit(exitval2);
+
+ FORKEE_REQUIRE_SUCCESS
+ (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
+
+ forkee_status_exited(status, exitval2);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Set empty EVENT_MASK for the child %d\n", child);
+ event.pe_set_event = 0;
+ ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child - expected stopped "
+ "SIGCHLD\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGCHLD);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child - expected exited\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child - expected no process\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(io_read_d1);
+ATF_TC_HEAD(io_read_d1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_IO with PIOD_READ_D and len = sizeof(uint8_t)");
+}
+
+ATF_TC_BODY(io_read_d1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ uint8_t lookup_me = 0;
+ const uint8_t magic = 0xab;
+ struct ptrace_io_desc io = {
+ .piod_op = PIOD_READ_D,
+ .piod_offs = &lookup_me,
+ .piod_addr = &lookup_me,
+ .piod_len = sizeof(lookup_me)
+ };
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ lookup_me = magic;
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read lookup_me from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me, magic,
+ "got value %" PRIx8 " != expected %" PRIx8, lookup_me, magic);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(io_read_d2);
+ATF_TC_HEAD(io_read_d2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_IO with PIOD_READ_D and len = sizeof(uint16_t)");
+}
+
+ATF_TC_BODY(io_read_d2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ uint16_t lookup_me = 0;
+ const uint16_t magic = 0x1234;
+ struct ptrace_io_desc io = {
+ .piod_op = PIOD_READ_D,
+ .piod_offs = &lookup_me,
+ .piod_addr = &lookup_me,
+ .piod_len = sizeof(lookup_me)
+ };
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ lookup_me = magic;
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read lookup_me from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me, magic,
+ "got value %" PRIx16 " != expected %" PRIx16, lookup_me, magic);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(io_read_d3);
+ATF_TC_HEAD(io_read_d3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_IO with PIOD_READ_D and len = sizeof(uint32_t)");
+}
+
+ATF_TC_BODY(io_read_d3, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ uint32_t lookup_me = 0;
+ const uint32_t magic = 0x1234abcd;
+ struct ptrace_io_desc io = {
+ .piod_op = PIOD_READ_D,
+ .piod_offs = &lookup_me,
+ .piod_addr = &lookup_me,
+ .piod_len = sizeof(lookup_me)
+ };
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ lookup_me = magic;
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read lookup_me from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me, magic,
+ "got value %" PRIx32 " != expected %" PRIx32, lookup_me, magic);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(io_read_d4);
+ATF_TC_HEAD(io_read_d4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_IO with PIOD_READ_D and len = sizeof(uint64_t)");
+}
+
+ATF_TC_BODY(io_read_d4, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ uint64_t lookup_me = 0;
+ const uint64_t magic = 0x1234abcd9876dcfa;
+ struct ptrace_io_desc io = {
+ .piod_op = PIOD_READ_D,
+ .piod_offs = &lookup_me,
+ .piod_addr = &lookup_me,
+ .piod_len = sizeof(lookup_me)
+ };
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ lookup_me = magic;
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read lookup_me from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me, magic,
+ "got value %" PRIx64 " != expected %" PRIx64, lookup_me, magic);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(io_write_d1);
+ATF_TC_HEAD(io_write_d1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_IO with PIOD_WRITE_D and len = sizeof(uint8_t)");
+}
+
+ATF_TC_BODY(io_write_d1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ uint8_t lookup_me = 0;
+ const uint8_t magic = 0xab;
+ struct ptrace_io_desc io = {
+ .piod_op = PIOD_WRITE_D,
+ .piod_offs = &lookup_me,
+ .piod_addr = &lookup_me,
+ .piod_len = sizeof(lookup_me)
+ };
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(lookup_me, magic);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ lookup_me = magic;
+
+ printf("Write new lookup_me to tracee (PID=%d) from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(io_write_d2);
+ATF_TC_HEAD(io_write_d2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_IO with PIOD_WRITE_D and len = sizeof(uint16_t)");
+}
+
+ATF_TC_BODY(io_write_d2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ uint16_t lookup_me = 0;
+ const uint16_t magic = 0xab12;
+ struct ptrace_io_desc io = {
+ .piod_op = PIOD_WRITE_D,
+ .piod_offs = &lookup_me,
+ .piod_addr = &lookup_me,
+ .piod_len = sizeof(lookup_me)
+ };
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(lookup_me, magic);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ lookup_me = magic;
+
+ printf("Write new lookup_me to tracee (PID=%d) from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(io_write_d3);
+ATF_TC_HEAD(io_write_d3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_IO with PIOD_WRITE_D and len = sizeof(uint32_t)");
+}
+
+ATF_TC_BODY(io_write_d3, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ uint32_t lookup_me = 0;
+ const uint32_t magic = 0xab127643;
+ struct ptrace_io_desc io = {
+ .piod_op = PIOD_WRITE_D,
+ .piod_offs = &lookup_me,
+ .piod_addr = &lookup_me,
+ .piod_len = sizeof(lookup_me)
+ };
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(lookup_me, magic);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ lookup_me = magic;
+
+ printf("Write new lookup_me to tracee (PID=%d) from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(io_write_d4);
+ATF_TC_HEAD(io_write_d4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_IO with PIOD_WRITE_D and len = sizeof(uint64_t)");
+}
+
+ATF_TC_BODY(io_write_d4, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ uint64_t lookup_me = 0;
+ const uint64_t magic = 0xab12764376490123;
+ struct ptrace_io_desc io = {
+ .piod_op = PIOD_WRITE_D,
+ .piod_offs = &lookup_me,
+ .piod_addr = &lookup_me,
+ .piod_len = sizeof(lookup_me)
+ };
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(lookup_me, magic);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ lookup_me = magic;
+
+ printf("Write new lookup_me to tracee (PID=%d) from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(read_d1);
+ATF_TC_HEAD(read_d1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_READ_D called once");
+}
+
+ATF_TC_BODY(read_d1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int lookup_me = 0;
+ const int magic = (int)random();
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ lookup_me = magic;
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read new lookup_me from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me = ptrace(PT_READ_D, child, &lookup_me, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me, magic,
+ "got value %#x != expected %#x", lookup_me, magic);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(read_d2);
+ATF_TC_HEAD(read_d2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_READ_D called twice");
+}
+
+ATF_TC_BODY(read_d2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int lookup_me1 = 0;
+ int lookup_me2 = 0;
+ const int magic1 = (int)random();
+ const int magic2 = (int)random();
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ lookup_me1 = magic1;
+ lookup_me2 = magic2;
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read new lookup_me1 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me1 = ptrace(PT_READ_D, child, &lookup_me1, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me1, magic1,
+ "got value %#x != expected %#x", lookup_me1, magic1);
+
+ printf("Read new lookup_me2 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me2 = ptrace(PT_READ_D, child, &lookup_me2, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me2, magic2,
+ "got value %#x != expected %#x", lookup_me2, magic2);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(read_d3);
+ATF_TC_HEAD(read_d3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_READ_D called three times");
+}
+
+ATF_TC_BODY(read_d3, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int lookup_me1 = 0;
+ int lookup_me2 = 0;
+ int lookup_me3 = 0;
+ const int magic1 = (int)random();
+ const int magic2 = (int)random();
+ const int magic3 = (int)random();
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ lookup_me1 = magic1;
+ lookup_me2 = magic2;
+ lookup_me3 = magic3;
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read new lookup_me1 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me1 = ptrace(PT_READ_D, child, &lookup_me1, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me1, magic1,
+ "got value %#x != expected %#x", lookup_me1, magic1);
+
+ printf("Read new lookup_me2 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me2 = ptrace(PT_READ_D, child, &lookup_me2, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me2, magic2,
+ "got value %#x != expected %#x", lookup_me2, magic2);
+
+ printf("Read new lookup_me3 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me3 = ptrace(PT_READ_D, child, &lookup_me3, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me3, magic3,
+ "got value %#x != expected %#x", lookup_me3, magic3);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(read_d4);
+ATF_TC_HEAD(read_d4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_READ_D called four times");
+}
+
+ATF_TC_BODY(read_d4, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int lookup_me1 = 0;
+ int lookup_me2 = 0;
+ int lookup_me3 = 0;
+ int lookup_me4 = 0;
+ const int magic1 = (int)random();
+ const int magic2 = (int)random();
+ const int magic3 = (int)random();
+ const int magic4 = (int)random();
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ lookup_me1 = magic1;
+ lookup_me2 = magic2;
+ lookup_me3 = magic3;
+ lookup_me4 = magic4;
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read new lookup_me1 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me1 = ptrace(PT_READ_D, child, &lookup_me1, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me1, magic1,
+ "got value %#x != expected %#x", lookup_me1, magic1);
+
+ printf("Read new lookup_me2 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me2 = ptrace(PT_READ_D, child, &lookup_me2, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me2, magic2,
+ "got value %#x != expected %#x", lookup_me2, magic2);
+
+ printf("Read new lookup_me3 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me3 = ptrace(PT_READ_D, child, &lookup_me3, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me3, magic3,
+ "got value %#x != expected %#x", lookup_me3, magic3);
+
+ printf("Read new lookup_me4 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me4 = ptrace(PT_READ_D, child, &lookup_me4, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me4, magic4,
+ "got value %#x != expected %#x", lookup_me4, magic4);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(write_d1);
+ATF_TC_HEAD(write_d1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_WRITE_D called once");
+}
+
+ATF_TC_BODY(write_d1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int lookup_me = 0;
+ const int magic = (int)random();
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(lookup_me, magic);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Write new lookup_me to tracee (PID=%d) from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_WRITE_D, child, &lookup_me, magic) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(write_d2);
+ATF_TC_HEAD(write_d2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_WRITE_D called twice");
+}
+
+ATF_TC_BODY(write_d2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int lookup_me1 = 0;
+ int lookup_me2 = 0;
+ const int magic1 = (int)random();
+ const int magic2 = (int)random();
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(lookup_me1, magic1);
+ FORKEE_ASSERT_EQ(lookup_me2, magic2);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Write new lookup_me1 to tracee (PID=%d) from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_WRITE_D, child, &lookup_me1, magic1) != -1);
+
+ printf("Write new lookup_me2 to tracee (PID=%d) from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_WRITE_D, child, &lookup_me2, magic2) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(write_d3);
+ATF_TC_HEAD(write_d3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_WRITE_D called three times");
+}
+
+ATF_TC_BODY(write_d3, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int lookup_me1 = 0;
+ int lookup_me2 = 0;
+ int lookup_me3 = 0;
+ const int magic1 = (int)random();
+ const int magic2 = (int)random();
+ const int magic3 = (int)random();
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(lookup_me1, magic1);
+ FORKEE_ASSERT_EQ(lookup_me2, magic2);
+ FORKEE_ASSERT_EQ(lookup_me3, magic3);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Write new lookup_me1 to tracee (PID=%d) from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_WRITE_D, child, &lookup_me1, magic1) != -1);
+
+ printf("Write new lookup_me2 to tracee (PID=%d) from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_WRITE_D, child, &lookup_me2, magic2) != -1);
+
+ printf("Write new lookup_me3 to tracee (PID=%d) from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_WRITE_D, child, &lookup_me3, magic3) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(write_d4);
+ATF_TC_HEAD(write_d4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_WRITE_D called four times");
+}
+
+ATF_TC_BODY(write_d4, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int lookup_me1 = 0;
+ int lookup_me2 = 0;
+ int lookup_me3 = 0;
+ int lookup_me4 = 0;
+ const int magic1 = (int)random();
+ const int magic2 = (int)random();
+ const int magic3 = (int)random();
+ const int magic4 = (int)random();
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(lookup_me1, magic1);
+ FORKEE_ASSERT_EQ(lookup_me2, magic2);
+ FORKEE_ASSERT_EQ(lookup_me3, magic3);
+ FORKEE_ASSERT_EQ(lookup_me4, magic4);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Write new lookup_me1 to tracee (PID=%d) from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_WRITE_D, child, &lookup_me1, magic1) != -1);
+
+ printf("Write new lookup_me2 to tracee (PID=%d) from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_WRITE_D, child, &lookup_me2, magic2) != -1);
+
+ printf("Write new lookup_me3 to tracee (PID=%d) from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_WRITE_D, child, &lookup_me3, magic3) != -1);
+
+ printf("Write new lookup_me4 to tracee (PID=%d) from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_WRITE_D, child, &lookup_me4, magic4) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(io_read_d_write_d_handshake1);
+ATF_TC_HEAD(io_read_d_write_d_handshake1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_IO with PIOD_READ_D and PIOD_WRITE_D handshake");
+}
+
+ATF_TC_BODY(io_read_d_write_d_handshake1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ uint8_t lookup_me_fromtracee = 0;
+ const uint8_t magic_fromtracee = (uint8_t)random();
+ uint8_t lookup_me_totracee = 0;
+ const uint8_t magic_totracee = (uint8_t)random();
+ struct ptrace_io_desc io_fromtracee = {
+ .piod_op = PIOD_READ_D,
+ .piod_offs = &lookup_me_fromtracee,
+ .piod_addr = &lookup_me_fromtracee,
+ .piod_len = sizeof(lookup_me_fromtracee)
+ };
+ struct ptrace_io_desc io_totracee = {
+ .piod_op = PIOD_WRITE_D,
+ .piod_offs = &lookup_me_totracee,
+ .piod_addr = &lookup_me_totracee,
+ .piod_len = sizeof(lookup_me_totracee)
+ };
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ lookup_me_fromtracee = magic_fromtracee;
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(lookup_me_totracee, magic_totracee);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read lookup_me_fromtracee PID=%d by tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io_fromtracee, 0) != -1);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me_fromtracee, magic_fromtracee,
+ "got value %" PRIx8 " != expected %" PRIx8, lookup_me_fromtracee,
+ magic_fromtracee);
+
+ lookup_me_totracee = magic_totracee;
+
+ printf("Write lookup_me_totracee to PID=%d by tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io_totracee, 0) != -1);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me_totracee, magic_totracee,
+ "got value %" PRIx8 " != expected %" PRIx8, lookup_me_totracee,
+ magic_totracee);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(io_read_d_write_d_handshake2);
+ATF_TC_HEAD(io_read_d_write_d_handshake2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_IO with PIOD_WRITE_D and PIOD_READ_D handshake");
+}
+
+ATF_TC_BODY(io_read_d_write_d_handshake2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ uint8_t lookup_me_fromtracee = 0;
+ const uint8_t magic_fromtracee = (uint8_t)random();
+ uint8_t lookup_me_totracee = 0;
+ const uint8_t magic_totracee = (uint8_t)random();
+ struct ptrace_io_desc io_fromtracee = {
+ .piod_op = PIOD_READ_D,
+ .piod_offs = &lookup_me_fromtracee,
+ .piod_addr = &lookup_me_fromtracee,
+ .piod_len = sizeof(lookup_me_fromtracee)
+ };
+ struct ptrace_io_desc io_totracee = {
+ .piod_op = PIOD_WRITE_D,
+ .piod_offs = &lookup_me_totracee,
+ .piod_addr = &lookup_me_totracee,
+ .piod_len = sizeof(lookup_me_totracee)
+ };
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ lookup_me_fromtracee = magic_fromtracee;
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(lookup_me_totracee, magic_totracee);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ lookup_me_totracee = magic_totracee;
+
+ printf("Write lookup_me_totracee to PID=%d by tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io_totracee, 0) != -1);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me_totracee, magic_totracee,
+ "got value %" PRIx8 " != expected %" PRIx8, lookup_me_totracee,
+ magic_totracee);
+
+ printf("Read lookup_me_fromtracee PID=%d by tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io_fromtracee, 0) != -1);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me_fromtracee, magic_fromtracee,
+ "got value %" PRIx8 " != expected %" PRIx8, lookup_me_fromtracee,
+ magic_fromtracee);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(read_d_write_d_handshake1);
+ATF_TC_HEAD(read_d_write_d_handshake1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_READ_D with PT_WRITE_D handshake");
+}
+
+ATF_TC_BODY(read_d_write_d_handshake1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int lookup_me_fromtracee = 0;
+ const int magic_fromtracee = (int)random();
+ int lookup_me_totracee = 0;
+ const int magic_totracee = (int)random();
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ lookup_me_fromtracee = magic_fromtracee;
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(lookup_me_totracee, magic_totracee);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read new lookup_me_fromtracee PID=%d by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me_fromtracee =
+ ptrace(PT_READ_D, child, &lookup_me_fromtracee, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me_fromtracee, magic_fromtracee,
+ "got value %#x != expected %#x", lookup_me_fromtracee,
+ magic_fromtracee);
+
+ printf("Write new lookup_me_totracee to PID=%d from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE
+ (ptrace(PT_WRITE_D, child, &lookup_me_totracee, magic_totracee)
+ != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(read_d_write_d_handshake2);
+ATF_TC_HEAD(read_d_write_d_handshake2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_WRITE_D with PT_READ_D handshake");
+}
+
+ATF_TC_BODY(read_d_write_d_handshake2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int lookup_me_fromtracee = 0;
+ const int magic_fromtracee = (int)random();
+ int lookup_me_totracee = 0;
+ const int magic_totracee = (int)random();
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ lookup_me_fromtracee = magic_fromtracee;
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(lookup_me_totracee, magic_totracee);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Write new lookup_me_totracee to PID=%d from tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE
+ (ptrace(PT_WRITE_D, child, &lookup_me_totracee, magic_totracee)
+ != -1);
+
+ printf("Read new lookup_me_fromtracee PID=%d by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me_fromtracee =
+ ptrace(PT_READ_D, child, &lookup_me_fromtracee, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me_fromtracee, magic_fromtracee,
+ "got value %#x != expected %#x", lookup_me_fromtracee,
+ magic_fromtracee);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+/* These dummy functions are used to be copied with ptrace(2) calls */
+static int __used
+dummy_fn1(int a, int b, int c, int d)
+{
+
+ a *= 1;
+ b += 2;
+ c -= 3;
+ d /= 4;
+
+ return a + b * c - d;
+}
+
+static int __used
+dummy_fn2(int a, int b, int c, int d)
+{
+
+ a *= 4;
+ b += 3;
+ c -= 2;
+ d /= 1;
+
+ return a + b * c - d;
+}
+
+static int __used
+dummy_fn3(int a, int b, int c, int d)
+{
+
+ a *= 10;
+ b += 20;
+ c -= 30;
+ d /= 40;
+
+ return a + b * c - d;
+}
+
+static int __used
+dummy_fn4(int a, int b, int c, int d)
+{
+
+ a *= 40;
+ b += 30;
+ c -= 20;
+ d /= 10;
+
+ return a + b * c - d;
+}
+
+ATF_TC(io_read_i1);
+ATF_TC_HEAD(io_read_i1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_IO with PIOD_READ_I and len = sizeof(uint8_t)");
+}
+
+ATF_TC_BODY(io_read_i1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ uint8_t lookup_me = 0;
+ uint8_t magic;
+ memcpy(&magic, dummy_fn1, sizeof(magic));
+ struct ptrace_io_desc io = {
+ .piod_op = PIOD_READ_I,
+ .piod_offs = dummy_fn1,
+ .piod_addr = &lookup_me,
+ .piod_len = sizeof(lookup_me)
+ };
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read lookup_me from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me, magic,
+ "got value %" PRIx8 " != expected %" PRIx8, lookup_me, magic);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(io_read_i2);
+ATF_TC_HEAD(io_read_i2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_IO with PIOD_READ_I and len = sizeof(uint16_t)");
+}
+
+ATF_TC_BODY(io_read_i2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ uint16_t lookup_me = 0;
+ uint16_t magic;
+ memcpy(&magic, dummy_fn1, sizeof(magic));
+ struct ptrace_io_desc io = {
+ .piod_op = PIOD_READ_I,
+ .piod_offs = dummy_fn1,
+ .piod_addr = &lookup_me,
+ .piod_len = sizeof(lookup_me)
+ };
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read lookup_me from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me, magic,
+ "got value %" PRIx16 " != expected %" PRIx16, lookup_me, magic);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(io_read_i3);
+ATF_TC_HEAD(io_read_i3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_IO with PIOD_READ_I and len = sizeof(uint32_t)");
+}
+
+ATF_TC_BODY(io_read_i3, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ uint32_t lookup_me = 0;
+ uint32_t magic;
+ memcpy(&magic, dummy_fn1, sizeof(magic));
+ struct ptrace_io_desc io = {
+ .piod_op = PIOD_READ_I,
+ .piod_offs = dummy_fn1,
+ .piod_addr = &lookup_me,
+ .piod_len = sizeof(lookup_me)
+ };
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read lookup_me from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me, magic,
+ "got value %" PRIx32 " != expected %" PRIx32, lookup_me, magic);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(io_read_i4);
+ATF_TC_HEAD(io_read_i4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_IO with PIOD_READ_I and len = sizeof(uint64_t)");
+}
+
+ATF_TC_BODY(io_read_i4, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ uint64_t lookup_me = 0;
+ uint64_t magic;
+ memcpy(&magic, dummy_fn1, sizeof(magic));
+ struct ptrace_io_desc io = {
+ .piod_op = PIOD_READ_I,
+ .piod_offs = dummy_fn1,
+ .piod_addr = &lookup_me,
+ .piod_len = sizeof(lookup_me)
+ };
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read lookup_me from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ ATF_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me, magic,
+ "got value %" PRIx64 " != expected %" PRIx64, lookup_me, magic);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(read_i1);
+ATF_TC_HEAD(read_i1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_READ_I called once");
+}
+
+ATF_TC_BODY(read_i1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int lookup_me = 0;
+ int magic;
+ memcpy(&magic, dummy_fn1, sizeof(magic));
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read new lookup_me from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me = ptrace(PT_READ_I, child, dummy_fn1, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me, magic,
+ "got value %#x != expected %#x", lookup_me, magic);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(read_i2);
+ATF_TC_HEAD(read_i2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_READ_I called twice");
+}
+
+ATF_TC_BODY(read_i2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int lookup_me1 = 0;
+ int lookup_me2 = 0;
+ int magic1;
+ int magic2;
+ memcpy(&magic1, dummy_fn1, sizeof(magic1));
+ memcpy(&magic2, dummy_fn2, sizeof(magic2));
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read new lookup_me1 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me1 = ptrace(PT_READ_I, child, dummy_fn1, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me1, magic1,
+ "got value %#x != expected %#x", lookup_me1, magic1);
+
+ printf("Read new lookup_me2 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me2 = ptrace(PT_READ_I, child, dummy_fn2, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me2, magic2,
+ "got value %#x != expected %#x", lookup_me2, magic2);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(read_i3);
+ATF_TC_HEAD(read_i3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_READ_I called three times");
+}
+
+ATF_TC_BODY(read_i3, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int lookup_me1 = 0;
+ int lookup_me2 = 0;
+ int lookup_me3 = 0;
+ int magic1;
+ int magic2;
+ int magic3;
+ memcpy(&magic1, dummy_fn1, sizeof(magic1));
+ memcpy(&magic2, dummy_fn2, sizeof(magic2));
+ memcpy(&magic3, dummy_fn3, sizeof(magic3));
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read new lookup_me1 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me1 = ptrace(PT_READ_I, child, dummy_fn1, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me1, magic1,
+ "got value %#x != expected %#x", lookup_me1, magic1);
+
+ printf("Read new lookup_me2 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me2 = ptrace(PT_READ_I, child, dummy_fn2, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me2, magic2,
+ "got value %#x != expected %#x", lookup_me2, magic2);
+
+ printf("Read new lookup_me3 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me3 = ptrace(PT_READ_I, child, dummy_fn3, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me3, magic3,
+ "got value %#x != expected %#x", lookup_me3, magic3);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(read_i4);
+ATF_TC_HEAD(read_i4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_READ_I called four times");
+}
+
+ATF_TC_BODY(read_i4, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int lookup_me1 = 0;
+ int lookup_me2 = 0;
+ int lookup_me3 = 0;
+ int lookup_me4 = 0;
+ int magic1;
+ int magic2;
+ int magic3;
+ int magic4;
+ memcpy(&magic1, dummy_fn1, sizeof(magic1));
+ memcpy(&magic2, dummy_fn2, sizeof(magic2));
+ memcpy(&magic3, dummy_fn3, sizeof(magic3));
+ memcpy(&magic4, dummy_fn4, sizeof(magic4));
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Read new lookup_me1 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me1 = ptrace(PT_READ_I, child, dummy_fn1, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me1, magic1,
+ "got value %#x != expected %#x", lookup_me1, magic1);
+
+ printf("Read new lookup_me2 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me2 = ptrace(PT_READ_I, child, dummy_fn2, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me2, magic2,
+ "got value %#x != expected %#x", lookup_me2, magic2);
+
+ printf("Read new lookup_me3 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me3 = ptrace(PT_READ_I, child, dummy_fn3, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me3, magic3,
+ "got value %#x != expected %#x", lookup_me3, magic3);
+
+ printf("Read new lookup_me4 from tracee (PID=%d) by tracer (PID=%d)\n",
+ child, getpid());
+ errno = 0;
+ lookup_me4 = ptrace(PT_READ_I, child, dummy_fn4, 0);
+ ATF_REQUIRE_EQ(errno, 0);
+
+ ATF_REQUIRE_EQ_MSG(lookup_me4, magic4,
+ "got value %#x != expected %#x", lookup_me4, magic4);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+#if defined(HAVE_GPREGS)
+ATF_TC(regs1);
+ATF_TC_HEAD(regs1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify plain PT_GETREGS call without further steps");
+}
+
+ATF_TC_BODY(regs1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct reg r;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Call GETREGS for the child process\n");
+ ATF_REQUIRE(ptrace(PT_GETREGS, child, &r, 0) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(HAVE_GPREGS)
+ATF_TC(regs2);
+ATF_TC_HEAD(regs2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify plain PT_GETREGS call and retrieve PC");
+}
+
+ATF_TC_BODY(regs2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct reg r;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Call GETREGS for the child process\n");
+ ATF_REQUIRE(ptrace(PT_GETREGS, child, &r, 0) != -1);
+
+ printf("Retrieved PC=%" PRIxREGISTER "\n", PTRACE_REG_PC(&r));
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(HAVE_GPREGS)
+ATF_TC(regs3);
+ATF_TC_HEAD(regs3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify plain PT_GETREGS call and retrieve SP");
+}
+
+ATF_TC_BODY(regs3, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct reg r;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Call GETREGS for the child process\n");
+ ATF_REQUIRE(ptrace(PT_GETREGS, child, &r, 0) != -1);
+
+ printf("Retrieved SP=%" PRIxREGISTER "\n", PTRACE_REG_SP(&r));
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(HAVE_GPREGS)
+ATF_TC(regs4);
+ATF_TC_HEAD(regs4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify plain PT_GETREGS call and retrieve INTRV");
+}
+
+ATF_TC_BODY(regs4, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct reg r;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Call GETREGS for the child process\n");
+ ATF_REQUIRE(ptrace(PT_GETREGS, child, &r, 0) != -1);
+
+ printf("Retrieved INTRV=%" PRIxREGISTER "\n", PTRACE_REG_INTRV(&r));
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(HAVE_GPREGS)
+ATF_TC(regs5);
+ATF_TC_HEAD(regs5, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_GETREGS and PT_SETREGS calls without changing regs");
+}
+
+ATF_TC_BODY(regs5, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct reg r;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Call GETREGS for the child process\n");
+ ATF_REQUIRE(ptrace(PT_GETREGS, child, &r, 0) != -1);
+
+ printf("Call SETREGS for the child process (without changed regs)\n");
+ ATF_REQUIRE(ptrace(PT_GETREGS, child, &r, 0) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(HAVE_FPREGS)
+ATF_TC(fpregs1);
+ATF_TC_HEAD(fpregs1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify plain PT_GETFPREGS call without further steps");
+}
+
+ATF_TC_BODY(fpregs1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct fpreg r;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Call GETFPREGS for the child process\n");
+ ATF_REQUIRE(ptrace(PT_GETFPREGS, child, &r, 0) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(HAVE_FPREGS)
+ATF_TC(fpregs2);
+ATF_TC_HEAD(fpregs2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_GETFPREGS and PT_SETFPREGS calls without changing "
+ "regs");
+}
+
+ATF_TC_BODY(fpregs2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct fpreg r;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Call GETFPREGS for the child process\n");
+ ATF_REQUIRE(ptrace(PT_GETFPREGS, child, &r, 0) != -1);
+
+ printf("Call SETFPREGS for the child (without changed regs)\n");
+ ATF_REQUIRE(ptrace(PT_SETFPREGS, child, &r, 0) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(PT_STEP)
+ATF_TC(step1);
+ATF_TC_HEAD(step1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify single PT_STEP call");
+}
+
+ATF_TC_BODY(step1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ int happy;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ happy = check_happy(100);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(happy, check_happy(100));
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent (use PT_STEP)\n");
+ ATF_REQUIRE(ptrace(PT_STEP, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(PT_STEP)
+ATF_TC(step2);
+ATF_TC_HEAD(step2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_STEP called twice");
+}
+
+ATF_TC_BODY(step2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ int happy;
+ int N = 2;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ happy = check_happy(999);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(happy, check_happy(999));
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ while (N --> 0) {
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent (use PT_STEP)\n");
+ ATF_REQUIRE(ptrace(PT_STEP, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+ child);
+
+ validate_status_stopped(status, SIGTRAP);
+ }
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(PT_STEP)
+ATF_TC(step3);
+ATF_TC_HEAD(step3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_STEP called three times");
+}
+
+ATF_TC_BODY(step3, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ int happy;
+ int N = 3;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ happy = check_happy(999);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(happy, check_happy(999));
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ while (N --> 0) {
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent (use PT_STEP)\n");
+ ATF_REQUIRE(ptrace(PT_STEP, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+ child);
+
+ validate_status_stopped(status, SIGTRAP);
+ }
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(PT_STEP)
+ATF_TC(step4);
+ATF_TC_HEAD(step4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify PT_STEP called four times");
+}
+
+ATF_TC_BODY(step4, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ int happy;
+ int N = 4;
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ happy = check_happy(999);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(happy, check_happy(999));
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ while (N --> 0) {
+ printf("Before resuming the child process where it left off "
+ "and without signal to be sent (use PT_STEP)\n");
+ ATF_REQUIRE(ptrace(PT_STEP, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+ child);
+
+ validate_status_stopped(status, SIGTRAP);
+ }
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+ATF_TC(kill1);
+ATF_TC_HEAD(kill1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that PT_CONTINUE with SIGKILL terminates child");
+}
+
+ATF_TC_BODY(kill1, tc)
+{
+ const int sigval = SIGSTOP, sigsent = SIGKILL;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ /* NOTREACHED */
+ FORKEE_ASSERTX(0 &&
+ "Child should be terminated by a signal from its parent");
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_signaled(status, sigsent, 0);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(kill2);
+ATF_TC_HEAD(kill2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that PT_KILL terminates child");
+}
+
+ATF_TC_BODY(kill2, tc)
+{
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ /* NOTREACHED */
+ FORKEE_ASSERTX(0 &&
+ "Child should be terminated by a signal from its parent");
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_KILL, child, (void*)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_signaled(status, SIGKILL, 0);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(lwpinfo1);
+ATF_TC_HEAD(lwpinfo1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify basic LWPINFO call for single thread (PT_TRACE_ME)");
+}
+
+ATF_TC_BODY(lwpinfo1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct ptrace_lwpinfo info = {0, 0};
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Before calling ptrace(2) with PT_LWPINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_LWPINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Assert that there exists a thread\n");
+ ATF_REQUIRE(info.pl_lwpid > 0);
+
+ printf("Assert that lwp thread %d received event PL_EVENT_SIGNAL\n",
+ info.pl_lwpid);
+ ATF_REQUIRE_EQ_MSG(info.pl_event, PL_EVENT_SIGNAL,
+ "Received event %d != expected event %d",
+ info.pl_event, PL_EVENT_SIGNAL);
+
+ printf("Before calling ptrace(2) with PT_LWPINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_LWPINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Assert that there are no more lwp threads in child\n");
+ ATF_REQUIRE_EQ(info.pl_lwpid, 0);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+#if defined(TWAIT_HAVE_PID)
+ATF_TC(lwpinfo2);
+ATF_TC_HEAD(lwpinfo2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify basic LWPINFO call for single thread (PT_ATTACH from "
+ "tracer)");
+}
+
+ATF_TC_BODY(lwpinfo2, tc)
+{
+ struct msg_fds parent_tracee, parent_tracer;
+ const int exitval_tracee = 5;
+ const int exitval_tracer = 10;
+ pid_t tracee, tracer, wpid;
+ uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct ptrace_lwpinfo info = {0, 0};
+
+ printf("Spawn tracee\n");
+ ATF_REQUIRE(msg_open(&parent_tracee) == 0);
+ ATF_REQUIRE(msg_open(&parent_tracer) == 0);
+ tracee = atf_utils_fork();
+ if (tracee == 0) {
+
+ /* Wait for message from the parent */
+ CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
+ CHILD_FROM_PARENT("tracee exit", parent_tracee, msg);
+
+ _exit(exitval_tracee);
+ }
+ PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
+
+ printf("Spawn debugger\n");
+ tracer = atf_utils_fork();
+ if (tracer == 0) {
+ /* No IPC to communicate with the child */
+ printf("Before calling PT_ATTACH from tracee %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
+
+ /* Wait for tracee and assert that it was stopped w/ SIGSTOP */
+ FORKEE_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
+
+ forkee_status_stopped(status, SIGSTOP);
+
+ printf("Before calling ptrace(2) with PT_LWPINFO for child\n");
+ FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &info, sizeof(info))
+ != -1);
+
+ printf("Assert that there exists a thread\n");
+ FORKEE_ASSERTX(info.pl_lwpid > 0);
+
+ printf("Assert that lwp thread %d received event "
+ "PL_EVENT_SIGNAL\n", info.pl_lwpid);
+ FORKEE_ASSERT_EQ(info.pl_event, PL_EVENT_SIGNAL);
+
+ printf("Before calling ptrace(2) with PT_LWPINFO for child\n");
+ FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &info, sizeof(info))
+ != -1);
+
+ printf("Assert that there are no more lwp threads in child\n");
+ FORKEE_ASSERTX(info.pl_lwpid == 0);
+
+ /* Resume tracee with PT_CONTINUE */
+ FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
+
+ /* Inform parent that tracer has attached to tracee */
+ CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
+ /* Wait for parent */
+ CHILD_FROM_PARENT("tracer wait", parent_tracer, msg);
+
+ /* Wait for tracee and assert that it exited */
+ FORKEE_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
+
+ forkee_status_exited(status, exitval_tracee);
+
+ printf("Before exiting of the tracer process\n");
+ _exit(exitval_tracer);
+ }
+
+ printf("Wait for the tracer to attach to the tracee\n");
+ PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
+
+ printf("Resume the tracee and let it exit\n");
+ PARENT_TO_CHILD("tracee exit", parent_tracee, msg);
+
+ printf("Detect that tracee is zombie\n");
+ await_zombie(tracee);
+
+ printf("Assert that there is no status about tracee - "
+ "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(
+ wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
+
+ printf("Resume the tracer and let it detect exited tracee\n");
+ PARENT_TO_CHILD("tracer wait", parent_tracer, msg);
+
+ printf("Wait for tracer to finish its job and exit - calling %s()\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
+ tracer);
+
+ validate_status_exited(status, exitval_tracer);
+
+ printf("Wait for tracee to finish its job and exit - calling %s()\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
+ tracee);
+
+ validate_status_exited(status, exitval_tracee);
+
+ msg_close(&parent_tracer);
+ msg_close(&parent_tracee);
+}
+#endif
+
+ATF_TC(siginfo1);
+ATF_TC_HEAD(siginfo1, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify basic PT_GET_SIGINFO call for SIGTRAP from tracee");
+}
+
+ATF_TC_BODY(siginfo1, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGTRAP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct ptrace_siginfo info;
+ memset(&info, 0, sizeof(info));
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Signal traced to lwpid=%d\n", info.psi_lwpid);
+ printf("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
+ info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+ info.psi_siginfo.si_errno);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(siginfo2);
+ATF_TC_HEAD(siginfo2, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify basic PT_GET_SIGINFO and PT_SET_SIGINFO calls without "
+ "modification of SIGINT from tracee");
+}
+
+static int siginfo2_caught = 0;
+
+static void
+siginfo2_sighandler(int sig)
+{
+ FORKEE_ASSERT_EQ(sig, SIGINT);
+
+ ++siginfo2_caught;
+}
+
+ATF_TC_BODY(siginfo2, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGINT;
+ pid_t child, wpid;
+ struct sigaction sa;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct ptrace_siginfo info;
+ memset(&info, 0, sizeof(info));
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ sa.sa_handler = siginfo2_sighandler;
+ sa.sa_flags = SA_SIGINFO;
+ sigemptyset(&sa.sa_mask);
+
+ FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(siginfo2_caught, 1);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Signal traced to lwpid=%d\n", info.psi_lwpid);
+ printf("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
+ info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+ info.psi_siginfo.si_errno);
+
+ printf("Before calling ptrace(2) with PT_SET_SIGINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_SET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigval) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(siginfo3);
+ATF_TC_HEAD(siginfo3, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify basic PT_GET_SIGINFO and PT_SET_SIGINFO calls with "
+ "setting signal to new value");
+}
+
+static int siginfo3_caught = 0;
+
+static void
+siginfo3_sigaction(int sig, siginfo_t *info, void *ctx)
+{
+ FORKEE_ASSERT_EQ(sig, SIGTRAP);
+
+ FORKEE_ASSERT_EQ(info->si_signo, SIGTRAP);
+ FORKEE_ASSERT_EQ(info->si_code, TRAP_BRKPT);
+
+ ++siginfo3_caught;
+}
+
+ATF_TC_BODY(siginfo3, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGINT;
+ const int sigfaked = SIGTRAP;
+ const int sicodefaked = TRAP_BRKPT;
+ pid_t child, wpid;
+ struct sigaction sa;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct ptrace_siginfo info;
+ memset(&info, 0, sizeof(info));
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ sa.sa_sigaction = siginfo3_sigaction;
+ sa.sa_flags = SA_SIGINFO;
+ sigemptyset(&sa.sa_mask);
+
+ FORKEE_ASSERT(sigaction(sigfaked, &sa, NULL) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(siginfo3_caught, 1);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Signal traced to lwpid=%d\n", info.psi_lwpid);
+ printf("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
+ info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+ info.psi_siginfo.si_errno);
+
+ printf("Before setting new faked signal to signo=%d si_code=%d\n",
+ sigfaked, sicodefaked);
+ info.psi_siginfo.si_signo = sigfaked;
+ info.psi_siginfo.si_code = sicodefaked;
+
+ printf("Before calling ptrace(2) with PT_SET_SIGINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_SET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Before checking siginfo_t\n");
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigfaked);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, sicodefaked);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigfaked) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(siginfo4);
+ATF_TC_HEAD(siginfo4, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Detect SIGTRAP TRAP_EXEC from tracee");
+}
+
+ATF_TC_BODY(siginfo4, tc)
+{
+ const int sigval = SIGTRAP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+
+ struct ptrace_siginfo info;
+ memset(&info, 0, sizeof(info));
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before calling execve(2) from child\n");
+ execlp("/bin/echo", "/bin/echo", NULL);
+
+ FORKEE_ASSERT(0 && "Not reached");
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Signal traced to lwpid=%d\n", info.psi_lwpid);
+ printf("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
+ info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+ info.psi_siginfo.si_errno);
+
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+#if defined(TWAIT_HAVE_PID)
+ATF_TC(siginfo5);
+ATF_TC_HEAD(siginfo5, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that fork(2) is intercepted by ptrace(2) with EVENT_MASK "
+ "set to PTRACE_FORK and reports correct signal information");
+}
+
+ATF_TC_BODY(siginfo5, tc)
+{
+ const int exitval = 5;
+ const int exitval2 = 15;
+ const int sigval = SIGSTOP;
+ pid_t child, child2, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ ptrace_state_t state;
+ const int slen = sizeof(state);
+ ptrace_event_t event;
+ const int elen = sizeof(event);
+ struct ptrace_siginfo info;
+
+ memset(&info, 0, sizeof(info));
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT((child2 = fork()) != 1);
+
+ if (child2 == 0)
+ _exit(exitval2);
+
+ FORKEE_REQUIRE_SUCCESS
+ (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
+
+ forkee_status_exited(status, exitval2);
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Before checking siginfo_t\n");
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+
+ printf("Enable PTRACE_FORK in EVENT_MASK for the child %d\n", child);
+ event.pe_set_event = PTRACE_FORK;
+ ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child %d\n", TWAIT_FNAME, child);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Before checking siginfo_t\n");
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_CHLD);
+
+ ATF_REQUIRE(ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
+ ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_FORK);
+
+ child2 = state.pe_other_pid;
+ printf("Reported PTRACE_FORK event with forkee %d\n", child2);
+
+ printf("Before calling %s() for the forkee %d of the child %d\n",
+ TWAIT_FNAME, child2, child);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
+ child2);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Before checking siginfo_t\n");
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_CHLD);
+
+ ATF_REQUIRE(ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
+ ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_FORK);
+ ATF_REQUIRE_EQ(state.pe_other_pid, child);
+
+ printf("Before resuming the forkee process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the forkee - expected exited\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
+ child2);
+
+ validate_status_exited(status, exitval2);
+
+ printf("Before calling %s() for the forkee - expected no process\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD,
+ wpid = TWAIT_GENERIC(child2, &status, 0));
+
+ printf("Before calling %s() for the child - expected stopped "
+ "SIGCHLD\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGCHLD);
+
+ printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Before checking siginfo_t\n");
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGCHLD);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, CLD_EXITED);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child - expected exited\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child - expected no process\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(PT_STEP)
+ATF_TC(siginfo6);
+ATF_TC_HEAD(siginfo6, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify single PT_STEP call with signal information check");
+}
+
+ATF_TC_BODY(siginfo6, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ int happy;
+ struct ptrace_siginfo info;
+
+ memset(&info, 0, sizeof(info));
+
+ printf("Before forking process PID=%d\n", getpid());
+ ATF_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ happy = check_happy(100);
+
+ printf("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT_EQ(happy, check_happy(100));
+
+ printf("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Before checking siginfo_t\n");
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent (use PT_STEP)\n");
+ ATF_REQUIRE(ptrace(PT_STEP, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+ ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ printf("Before checking siginfo_t\n");
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_TRACE);
+
+ printf("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ printf("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+ATF_TP_ADD_TCS(tp)
+{
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+ ATF_TP_ADD_TC(tp, traceme1);
+ ATF_TP_ADD_TC(tp, traceme2);
+ ATF_TP_ADD_TC(tp, traceme3);
+ ATF_TP_ADD_TC(tp, traceme4);
+
+ ATF_TP_ADD_TC_HAVE_PID(tp, attach1);
+ ATF_TP_ADD_TC_HAVE_PID(tp, attach2);
+ ATF_TP_ADD_TC(tp, attach3);
+ ATF_TP_ADD_TC(tp, attach4);
+ ATF_TP_ADD_TC_HAVE_PID(tp, attach5);
+ ATF_TP_ADD_TC_HAVE_PID(tp, attach6);
+ ATF_TP_ADD_TC_HAVE_PID(tp, attach7);
+
+ ATF_TP_ADD_TC(tp, eventmask1);
+ ATF_TP_ADD_TC(tp, eventmask2);
+
+ ATF_TP_ADD_TC_HAVE_PID(tp, fork1);
+ ATF_TP_ADD_TC(tp, fork2);
+
+ ATF_TP_ADD_TC_HAVE_PID(tp, vfork1);
+ ATF_TP_ADD_TC(tp, vfork2);
+
+ ATF_TP_ADD_TC(tp, io_read_d1);
+ ATF_TP_ADD_TC(tp, io_read_d2);
+ ATF_TP_ADD_TC(tp, io_read_d3);
+ ATF_TP_ADD_TC(tp, io_read_d4);
+
+ ATF_TP_ADD_TC(tp, io_write_d1);
+ ATF_TP_ADD_TC(tp, io_write_d2);
+ ATF_TP_ADD_TC(tp, io_write_d3);
+ ATF_TP_ADD_TC(tp, io_write_d4);
+
+ ATF_TP_ADD_TC(tp, read_d1);
+ ATF_TP_ADD_TC(tp, read_d2);
+ ATF_TP_ADD_TC(tp, read_d3);
+ ATF_TP_ADD_TC(tp, read_d4);
+
+ ATF_TP_ADD_TC(tp, write_d1);
+ ATF_TP_ADD_TC(tp, write_d2);
+ ATF_TP_ADD_TC(tp, write_d3);
+ ATF_TP_ADD_TC(tp, write_d4);
+
+ ATF_TP_ADD_TC(tp, io_read_d_write_d_handshake1);
+ ATF_TP_ADD_TC(tp, io_read_d_write_d_handshake2);
+
+ ATF_TP_ADD_TC(tp, read_d_write_d_handshake1);
+ ATF_TP_ADD_TC(tp, read_d_write_d_handshake2);
+
+ ATF_TP_ADD_TC(tp, io_read_i1);
+ ATF_TP_ADD_TC(tp, io_read_i2);
+ ATF_TP_ADD_TC(tp, io_read_i3);
+ ATF_TP_ADD_TC(tp, io_read_i4);
+
+ ATF_TP_ADD_TC(tp, read_i1);
+ ATF_TP_ADD_TC(tp, read_i2);
+ ATF_TP_ADD_TC(tp, read_i3);
+ ATF_TP_ADD_TC(tp, read_i4);
+
+ ATF_TP_ADD_TC_HAVE_GPREGS(tp, regs1);
+ ATF_TP_ADD_TC_HAVE_GPREGS(tp, regs2);
+ ATF_TP_ADD_TC_HAVE_GPREGS(tp, regs3);
+ ATF_TP_ADD_TC_HAVE_GPREGS(tp, regs4);
+ ATF_TP_ADD_TC_HAVE_GPREGS(tp, regs5);
+
+ ATF_TP_ADD_TC_HAVE_FPREGS(tp, fpregs1);
+ ATF_TP_ADD_TC_HAVE_FPREGS(tp, fpregs2);
+
+ ATF_TP_ADD_TC_PT_STEP(tp, step1);
+ ATF_TP_ADD_TC_PT_STEP(tp, step2);
+ ATF_TP_ADD_TC_PT_STEP(tp, step3);
+ ATF_TP_ADD_TC_PT_STEP(tp, step4);
+
+ ATF_TP_ADD_TC(tp, kill1);
+ ATF_TP_ADD_TC(tp, kill2);
+
+ ATF_TP_ADD_TC(tp, lwpinfo1);
+ ATF_TP_ADD_TC_HAVE_PID(tp, lwpinfo2);
+
+ ATF_TP_ADD_TC(tp, siginfo1);
+ ATF_TP_ADD_TC(tp, siginfo2);
+ ATF_TP_ADD_TC(tp, siginfo3);
+ ATF_TP_ADD_TC(tp, siginfo4);
+ ATF_TP_ADD_TC_HAVE_PID(tp, siginfo5);
+ ATF_TP_ADD_TC_PT_STEP(tp, siginfo6);
+
+ return atf_no_error();
+}
diff --git a/contrib/netbsd-tests/kernel/t_ptrace_wait.h b/contrib/netbsd-tests/kernel/t_ptrace_wait.h
new file mode 100644
index 0000000..9c6921c
--- /dev/null
+++ b/contrib/netbsd-tests/kernel/t_ptrace_wait.h
@@ -0,0 +1,431 @@
+/* $NetBSD: t_ptrace_wait.h,v 1.7 2017/01/09 22:09:20 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/* Detect plain wait(2) use-case */
+#if !defined(TWAIT_WAITPID) && \
+ !defined(TWAIT_WAITID) && \
+ !defined(TWAIT_WAIT3) && \
+ !defined(TWAIT_WAIT4) && \
+ !defined(TWAIT_WAIT6)
+#define TWAIT_WAIT
+#endif
+
+/*
+ * There are two classes of wait(2)-like functions:
+ * - wait4(2)-like accepting pid_t, optional options parameter, struct rusage*
+ * - wait6(2)-like accepting idtype_t, id_t, struct wrusage, mandatory options
+ *
+ * The TWAIT_FNAME value is to be used for convenience in debug messages.
+ *
+ * The TWAIT_GENERIC() macro is designed to reuse the same unmodified
+ * code with as many wait(2)-like functions as possible.
+ *
+ * In a common use-case wait4(2) and wait6(2)-like function can work the almost
+ * the same way, however there are few important differences:
+ * wait6(2) must specify P_PID for idtype to match wpid from wait4(2).
+ * To behave like wait4(2), wait6(2) the 'options' to wait must include
+ * WEXITED|WTRUNCATED.
+ *
+ * There are two helper macros (they purpose it to mach more than one
+ * wait(2)-like function):
+ * The TWAIT_HAVE_STATUS - specifies whether a function can retrieve
+ * status (as integer value).
+ * The TWAIT_HAVE_PID - specifies whether a function can request
+ * exact process identifier
+ * The TWAIT_HAVE_RUSAGE - specifies whether a function can request
+ * the struct rusage value
+ *
+ */
+
+#if defined(TWAIT_WAIT)
+# define TWAIT_FNAME "wait"
+# define TWAIT_WAIT4TYPE(a,b,c,d) wait((b))
+# define TWAIT_GENERIC(a,b,c) wait((b))
+# define TWAIT_HAVE_STATUS 1
+#elif defined(TWAIT_WAITPID)
+# define TWAIT_FNAME "waitpid"
+# define TWAIT_WAIT4TYPE(a,b,c,d) waitpid((a),(b),(c))
+# define TWAIT_GENERIC(a,b,c) waitpid((a),(b),(c))
+# define TWAIT_HAVE_PID 1
+# define TWAIT_HAVE_STATUS 1
+#elif defined(TWAIT_WAITID)
+# define TWAIT_FNAME "waitid"
+# define TWAIT_GENERIC(a,b,c) \
+ waitid(P_PID,(a),NULL,(c)|WEXITED|WTRAPPED)
+# define TWAIT_WAIT6TYPE(a,b,c,d,e,f) waitid((a),(b),(f),(d))
+# define TWAIT_HAVE_PID 1
+#elif defined(TWAIT_WAIT3)
+# define TWAIT_FNAME "wait3"
+# define TWAIT_WAIT4TYPE(a,b,c,d) wait3((b),(c),(d))
+# define TWAIT_GENERIC(a,b,c) wait3((b),(c),NULL)
+# define TWAIT_HAVE_STATUS 1
+# define TWAIT_HAVE_RUSAGE 1
+#elif defined(TWAIT_WAIT4)
+# define TWAIT_FNAME "wait4"
+# define TWAIT_WAIT4TYPE(a,b,c,d) wait4((a),(b),(c),(d))
+# define TWAIT_GENERIC(a,b,c) wait4((a),(b),(c),NULL)
+# define TWAIT_HAVE_PID 1
+# define TWAIT_HAVE_STATUS 1
+# define TWAIT_HAVE_RUSAGE 1
+#elif defined(TWAIT_WAIT6)
+# define TWAIT_FNAME "wait6"
+# define TWAIT_WAIT6TYPE(a,b,c,d,e,f) wait6((a),(b),(c),(d),(e),(f))
+# define TWAIT_GENERIC(a,b,c) \
+ wait6(P_PID,(a),(b),(c)|WEXITED|WTRAPPED,NULL,NULL)
+# define TWAIT_HAVE_PID 1
+# define TWAIT_HAVE_STATUS 1
+#endif
+
+/*
+ * There are 3 groups of tests:
+ * - TWAIT_GENERIC() (wait, wait2, waitpid, wait3, wait4, wait6)
+ * - TWAIT_WAIT4TYPE() (wait2, waitpid, wait3, wait4)
+ * - TWAIT_WAIT6TYPE() (waitid, wait6)
+ *
+ * Tests only in the above categories are allowed. However some tests are not
+ * possible in the context requested functionality to be verified, therefore
+ * there are helper macros:
+ * - TWAIT_HAVE_PID (wait2, waitpid, waitid, wait4, wait6)
+ * - TWAIT_HAVE_STATUS (wait, wait2, waitpid, wait3, wait4, wait6)
+ * - TWAIT_HAVE_RUSAGE (wait3, wait4)
+ * - TWAIT_HAVE_RETPID (wait, wait2, waitpid, wait3, wait4, wait6)
+ *
+ * If there is an intention to test e.g. wait6(2) specific features in the
+ * ptrace(2) context, find the most matching group and with #ifdefs reduce
+ * functionality of less featured than wait6(2) interface (TWAIT_WAIT6TYPE).
+ *
+ * For clarity never use negative preprocessor checks, like:
+ * #if !defined(TWAIT_WAIT4)
+ * always refer to checks for positive values.
+ */
+
+#define TEST_REQUIRE_EQ(x, y) \
+do { \
+ uintmax_t vx = (x); \
+ uintmax_t vy = (y); \
+ int ret = vx == vy; \
+ if (!ret) \
+ ATF_REQUIRE_EQ_MSG(vx, vy, "%s(%ju) == %s(%ju)", \
+ #x, vx, #y, vy); \
+} while (/*CONSTCOND*/0)
+
+/*
+ * A child process cannot call atf functions and expect them to magically
+ * work like in the parent.
+ * The printf(3) messaging from a child will not work out of the box as well
+ * without estabilishing a communication protocol with its parent. To not
+ * overcomplicate the tests - do not log from a child and use err(3)/errx(3)
+ * wrapped with FORKEE_ASSERT()/FORKEE_ASSERTX() as that is guaranteed to work.
+ */
+#define FORKEE_ASSERT_EQ(x, y) \
+do { \
+ uintmax_t vx = (x); \
+ uintmax_t vy = (y); \
+ int ret = vx == vy; \
+ if (!ret) \
+ errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: " \
+ "%s(%ju) == %s(%ju)", __FILE__, __LINE__, __func__, \
+ #x, vx, #y, vy); \
+} while (/*CONSTCOND*/0)
+
+#define FORKEE_ASSERTX(x) \
+do { \
+ int ret = (x); \
+ if (!ret) \
+ errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s",\
+ __FILE__, __LINE__, __func__, #x); \
+} while (/*CONSTCOND*/0)
+
+#define FORKEE_ASSERT(x) \
+do { \
+ int ret = (x); \
+ if (!ret) \
+ err(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s",\
+ __FILE__, __LINE__, __func__, #x); \
+} while (/*CONSTCOND*/0)
+
+/*
+ * Simplify logic for functions using general purpose registers add HAVE_GPREGS
+ *
+ * For platforms that do not implement all needed calls for simplicity assume
+ * that they are unsupported at all.
+ */
+#if defined(PT_GETREGS) \
+ && defined(PT_SETREGS) \
+ && defined(PTRACE_REG_PC) \
+ && defined(PTRACE_REG_SET_PC) \
+ && defined(PTRACE_REG_SP) \
+ && defined(PTRACE_REG_INTRV)
+#define HAVE_GPREGS
+#endif
+
+/* Add guards for floating point registers */
+#if defined(PT_GETFPREGS) \
+ && defined(PT_SETFPREGS)
+#define HAVE_FPREGS
+#endif
+
+/* Add guards for cpu debug registers */
+#if defined(PT_GETDBREGS) \
+ && defined(PT_SETDBREGS)
+#define HAVE_DBREGS
+#endif
+
+/*
+ * If waitid(2) returns because one or more processes have a state change to
+ * report, 0 is returned. If an error is detected, a value of -1 is returned
+ * and errno is set to indicate the error. If WNOHANG is specified and there
+ * are no stopped, continued or exited children, 0 is returned.
+ */
+#if defined(TWAIT_WAITID)
+#define TWAIT_REQUIRE_SUCCESS(a,b) TEST_REQUIRE_EQ((a), 0)
+#define TWAIT_REQUIRE_FAILURE(a,b) ATF_REQUIRE_ERRNO((a),(b) == -1)
+#define FORKEE_REQUIRE_SUCCESS(a,b) FORKEE_ASSERT_EQ(a, 0)
+#define FORKEE_REQUIRE_FAILURE(a,b) \
+ FORKEE_ASSERTX(((a) == errno) && ((b) == -1))
+#else
+#define TWAIT_REQUIRE_SUCCESS(a,b) TEST_REQUIRE_EQ((a), (b))
+#define TWAIT_REQUIRE_FAILURE(a,b) ATF_REQUIRE_ERRNO((a),(b) == -1)
+#define FORKEE_REQUIRE_SUCCESS(a,b) FORKEE_ASSERT_EQ(a, b)
+#define FORKEE_REQUIRE_FAILURE(a,b) \
+ FORKEE_ASSERTX(((a) == errno) && ((b) == -1))
+#endif
+
+/*
+ * Helper tools to verify whether status reports exited value
+ */
+#if TWAIT_HAVE_STATUS
+static void __used
+validate_status_exited(int status, int expected)
+{
+ ATF_REQUIRE_MSG(WIFEXITED(status), "Reported !exited process");
+ ATF_REQUIRE_MSG(!WIFCONTINUED(status), "Reported continued process");
+ ATF_REQUIRE_MSG(!WIFSIGNALED(status), "Reported signaled process");
+ ATF_REQUIRE_MSG(!WIFSTOPPED(status), "Reported stopped process");
+
+ ATF_REQUIRE_EQ_MSG(WEXITSTATUS(status), expected,
+ "The process has exited with invalid value %d != %d",
+ WEXITSTATUS(status), expected);
+}
+
+static void __used
+forkee_status_exited(int status, int expected)
+{
+ FORKEE_ASSERTX(WIFEXITED(status));
+ FORKEE_ASSERTX(!WIFCONTINUED(status));
+ FORKEE_ASSERTX(!WIFSIGNALED(status));
+ FORKEE_ASSERTX(!WIFSTOPPED(status));
+
+ FORKEE_ASSERT_EQ(WEXITSTATUS(status), expected);
+}
+
+static void __used
+validate_status_continued(int status)
+{
+ ATF_REQUIRE_MSG(!WIFEXITED(status), "Reported exited process");
+ ATF_REQUIRE_MSG(WIFCONTINUED(status), "Reported !continued process");
+ ATF_REQUIRE_MSG(!WIFSIGNALED(status), "Reported signaled process");
+ ATF_REQUIRE_MSG(!WIFSTOPPED(status), "Reported stopped process");
+}
+
+static void __used
+forkee_status_continued(int status)
+{
+ FORKEE_ASSERTX(!WIFEXITED(status));
+ FORKEE_ASSERTX(WIFCONTINUED(status));
+ FORKEE_ASSERTX(!WIFSIGNALED(status));
+ FORKEE_ASSERTX(!WIFSTOPPED(status));
+}
+
+static void __used
+validate_status_signaled(int status, int expected_termsig, int expected_core)
+{
+ ATF_REQUIRE_MSG(!WIFEXITED(status), "Reported exited process");
+ ATF_REQUIRE_MSG(!WIFCONTINUED(status), "Reported continued process");
+ ATF_REQUIRE_MSG(WIFSIGNALED(status), "Reported !signaled process");
+ ATF_REQUIRE_MSG(!WIFSTOPPED(status), "Reported stopped process");
+
+ ATF_REQUIRE_EQ_MSG(WTERMSIG(status), expected_termsig,
+ "Unexpected signal received");
+
+ ATF_REQUIRE_EQ_MSG(WCOREDUMP(status), expected_core,
+ "Unexpectedly core file %s generated", expected_core ? "not" : "");
+}
+
+static void __used
+forkee_status_signaled(int status, int expected_termsig, int expected_core)
+{
+ FORKEE_ASSERTX(!WIFEXITED(status));
+ FORKEE_ASSERTX(!WIFCONTINUED(status));
+ FORKEE_ASSERTX(WIFSIGNALED(status));
+ FORKEE_ASSERTX(!WIFSTOPPED(status));
+
+ FORKEE_ASSERT_EQ(WTERMSIG(status), expected_termsig);
+ FORKEE_ASSERT_EQ(WCOREDUMP(status), expected_core);
+}
+
+static void __used
+validate_status_stopped(int status, int expected)
+{
+ ATF_REQUIRE_MSG(!WIFEXITED(status), "Reported exited process");
+ ATF_REQUIRE_MSG(!WIFCONTINUED(status), "Reported continued process");
+ ATF_REQUIRE_MSG(!WIFSIGNALED(status), "Reported signaled process");
+ ATF_REQUIRE_MSG(WIFSTOPPED(status), "Reported !stopped process");
+
+ char st[128], ex[128];
+ strlcpy(st, strsignal(WSTOPSIG(status)), sizeof(st));
+ strlcpy(ex, strsignal(expected), sizeof(ex));
+
+ ATF_REQUIRE_EQ_MSG(WSTOPSIG(status), expected,
+ "Unexpected stop signal received [%s] != [%s]", st, ex);
+}
+
+static void __used
+forkee_status_stopped(int status, int expected)
+{
+ FORKEE_ASSERTX(!WIFEXITED(status));
+ FORKEE_ASSERTX(!WIFCONTINUED(status));
+ FORKEE_ASSERTX(!WIFSIGNALED(status));
+ FORKEE_ASSERTX(WIFSTOPPED(status));
+
+ FORKEE_ASSERT_EQ(WSTOPSIG(status), expected);
+}
+#else
+#define validate_status_exited(a,b)
+#define forkee_status_exited(a,b)
+#define validate_status_continued(a,b)
+#define forkee_status_continued(a,b)
+#define validate_status_signaled(a,b,c)
+#define forkee_status_signaled(a,b,c)
+#define validate_status_stopped(a,b)
+#define forkee_status_stopped(a,b)
+#endif
+
+/* This function is currently designed to be run in the main/parent process */
+static void __used
+await_zombie(pid_t process)
+{
+ struct kinfo_proc2 p;
+ size_t len = sizeof(p);
+
+ const int name[] = {
+ [0] = CTL_KERN,
+ [1] = KERN_PROC2,
+ [2] = KERN_PROC_PID,
+ [3] = process,
+ [4] = sizeof(p),
+ [5] = 1
+ };
+
+ const size_t namelen = __arraycount(name);
+
+ /* Await the process becoming a zombie */
+ while(1) {
+ ATF_REQUIRE(sysctl(name, namelen, &p, &len, NULL, 0) == 0);
+
+ if (p.p_stat == LSZOMB)
+ break;
+
+ ATF_REQUIRE(usleep(1000) == 0);
+ }
+}
+
+/* Happy number sequence -- this function is used to just consume cpu cycles */
+#define HAPPY_NUMBER 1
+
+/* If n is not happy then its sequence ends in the cycle:
+ * 4, 16, 37, 58, 89, 145, 42, 20, 4, ... */
+#define SAD_NUMBER 4
+
+/* Calculate the sum of the squares of the digits of n */
+static unsigned __used
+dsum(unsigned n)
+{
+ unsigned sum, x;
+ for (sum = 0; n; n /= 10) {
+ x = n % 10;
+ sum += x * x;
+ }
+ return sum;
+}
+
+/*
+ * XXX: Disabled optimization is required to make tests for hardware assisted
+ * traps in .text functional
+ *
+ * Tested with GCC 5.4 on NetBSD 7.99.47 amd64
+ */
+static int __used
+#ifdef __clang__
+__attribute__((__optnone__))
+#else
+__attribute__((__optimize__("O0")))
+#endif
+check_happy(unsigned n)
+{
+ for (;;) {
+ unsigned total = dsum(n);
+
+ if (total == HAPPY_NUMBER)
+ return 1;
+ if (total == SAD_NUMBER)
+ return 0;
+
+ n = total;
+ }
+}
+
+#if defined(TWAIT_HAVE_PID)
+#define ATF_TP_ADD_TC_HAVE_PID(a,b) ATF_TP_ADD_TC(a,b)
+#else
+#define ATF_TP_ADD_TC_HAVE_PID(a,b)
+#endif
+
+#if defined(HAVE_GPREGS)
+#define ATF_TP_ADD_TC_HAVE_GPREGS(a,b) ATF_TP_ADD_TC(a,b)
+#else
+#define ATF_TP_ADD_TC_HAVE_GPREGS(a,b)
+#endif
+
+#if defined(HAVE_FPREGS)
+#define ATF_TP_ADD_TC_HAVE_FPREGS(a,b) ATF_TP_ADD_TC(a,b)
+#else
+#define ATF_TP_ADD_TC_HAVE_FPREGS(a,b)
+#endif
+
+#if defined(PT_STEP)
+#define ATF_TP_ADD_TC_PT_STEP(a,b) ATF_TP_ADD_TC(a,b)
+#else
+#define ATF_TP_ADD_TC_PT_STEP(a,b)
+#endif
+
+#if defined(__HAVE_PTRACE_WATCHPOINTS)
+#define ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(a,b) ATF_TP_ADD_TC(a,b)
+#else
+#define ATF_TP_ADD_TC_HAVE_PTRACE_WATCHPOINTS(a,b)
+#endif
diff --git a/contrib/netbsd-tests/kernel/t_ptrace_wait3.c b/contrib/netbsd-tests/kernel/t_ptrace_wait3.c
new file mode 100644
index 0000000..c136431
--- /dev/null
+++ b/contrib/netbsd-tests/kernel/t_ptrace_wait3.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_wait3.c,v 1.1 2016/11/07 21:09:03 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#define TWAIT_WAIT3
+#include "t_ptrace_wait.c"
diff --git a/contrib/netbsd-tests/kernel/t_ptrace_wait4.c b/contrib/netbsd-tests/kernel/t_ptrace_wait4.c
new file mode 100644
index 0000000..7ae771b
--- /dev/null
+++ b/contrib/netbsd-tests/kernel/t_ptrace_wait4.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_wait4.c,v 1.1 2016/11/07 21:09:03 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#define TWAIT_WAIT4
+#include "t_ptrace_wait.c"
diff --git a/contrib/netbsd-tests/kernel/t_ptrace_wait6.c b/contrib/netbsd-tests/kernel/t_ptrace_wait6.c
new file mode 100644
index 0000000..122cb1d
--- /dev/null
+++ b/contrib/netbsd-tests/kernel/t_ptrace_wait6.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_wait6.c,v 1.1 2016/11/07 21:09:03 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#define TWAIT_WAIT6
+#include "t_ptrace_wait.c"
diff --git a/contrib/netbsd-tests/kernel/t_ptrace_waitid.c b/contrib/netbsd-tests/kernel/t_ptrace_waitid.c
new file mode 100644
index 0000000..1c09be7
--- /dev/null
+++ b/contrib/netbsd-tests/kernel/t_ptrace_waitid.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_waitid.c,v 1.1 2016/11/07 21:09:03 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#define TWAIT_WAITID
+#include "t_ptrace_wait.c"
diff --git a/contrib/netbsd-tests/kernel/t_ptrace_waitpid.c b/contrib/netbsd-tests/kernel/t_ptrace_waitpid.c
new file mode 100644
index 0000000..c8f107d
--- /dev/null
+++ b/contrib/netbsd-tests/kernel/t_ptrace_waitpid.c
@@ -0,0 +1,30 @@
+/* $NetBSD: t_ptrace_waitpid.c,v 1.1 2016/11/07 21:09:03 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#define TWAIT_WAITPID
+#include "t_ptrace_wait.c"
diff --git a/contrib/netbsd-tests/kernel/t_rnd.c b/contrib/netbsd-tests/kernel/t_rnd.c
index 7f1f288..8646130 100644
--- a/contrib/netbsd-tests/kernel/t_rnd.c
+++ b/contrib/netbsd-tests/kernel/t_rnd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_rnd.c,v 1.5 2012/03/18 09:46:50 jruoho Exp $ */
+/* $NetBSD: t_rnd.c,v 1.9 2016/05/22 04:34:44 riastradh Exp $ */
/*
* Copyright (c) 2009 The NetBSD Foundation, Inc.
@@ -27,12 +27,12 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_rnd.c,v 1.5 2012/03/18 09:46:50 jruoho Exp $");
+__RCSID("$NetBSD: t_rnd.c,v 1.9 2016/05/22 04:34:44 riastradh Exp $");
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
-#include <sys/rnd.h>
+#include <sys/rndio.h>
#include <atf-c.h>
@@ -86,10 +86,29 @@ ATF_TC_BODY(RNDADDDATA2, tc)
ATF_REQUIRE_ERRNO(EINVAL, rump_sys_ioctl(fd, RNDADDDATA, &rd) == -1);
}
+ATF_TC(read_random);
+ATF_TC_HEAD(read_random, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "does reading /dev/random return "
+ "within reasonable time");
+ atf_tc_set_md_var(tc, "timeout", "10");
+}
+
+ATF_TC_BODY(read_random, tc)
+{
+ char buf[128];
+ int fd;
+
+ rump_init();
+ RL(fd = rump_sys_open("/dev/random", O_RDONLY));
+ RL(rump_sys_read(fd, buf, sizeof(buf)));
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, RNDADDDATA);
ATF_TP_ADD_TC(tp, RNDADDDATA2);
+ ATF_TP_ADD_TC(tp, read_random);
return atf_no_error();
}
OpenPOWER on IntegriCloud