xref: /freebsd/tests/sys/kern/ptrace_test.c (revision b98cb919dec2697af74f4e7bbea8a14f1c1a3d6e)
1c209e3e2SJohn Baldwin /*-
2c209e3e2SJohn Baldwin  * Copyright (c) 2015 John Baldwin <jhb@FreeBSD.org>
3c209e3e2SJohn Baldwin  * All rights reserved.
4c209e3e2SJohn Baldwin  *
5c209e3e2SJohn Baldwin  * Redistribution and use in source and binary forms, with or without
6c209e3e2SJohn Baldwin  * modification, are permitted provided that the following conditions
7c209e3e2SJohn Baldwin  * are met:
8c209e3e2SJohn Baldwin  * 1. Redistributions of source code must retain the above copyright
9c209e3e2SJohn Baldwin  *    notice, this list of conditions and the following disclaimer.
10c209e3e2SJohn Baldwin  * 2. Redistributions in binary form must reproduce the above copyright
11c209e3e2SJohn Baldwin  *    notice, this list of conditions and the following disclaimer in the
12c209e3e2SJohn Baldwin  *    documentation and/or other materials provided with the distribution.
13c209e3e2SJohn Baldwin  *
14c209e3e2SJohn Baldwin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15c209e3e2SJohn Baldwin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16c209e3e2SJohn Baldwin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17c209e3e2SJohn Baldwin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18c209e3e2SJohn Baldwin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19c209e3e2SJohn Baldwin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20c209e3e2SJohn Baldwin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21c209e3e2SJohn Baldwin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22c209e3e2SJohn Baldwin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23c209e3e2SJohn Baldwin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24c209e3e2SJohn Baldwin  * SUCH DAMAGE.
25c209e3e2SJohn Baldwin  */
26c209e3e2SJohn Baldwin 
27c209e3e2SJohn Baldwin #include <sys/cdefs.h>
28c209e3e2SJohn Baldwin __FBSDID("$FreeBSD$");
29c209e3e2SJohn Baldwin 
30c209e3e2SJohn Baldwin #include <sys/types.h>
31c209e3e2SJohn Baldwin #include <sys/ptrace.h>
3257c74f5bSJohn Baldwin #include <sys/sysctl.h>
3357c74f5bSJohn Baldwin #include <sys/user.h>
34c209e3e2SJohn Baldwin #include <sys/wait.h>
35c209e3e2SJohn Baldwin #include <errno.h>
36c209e3e2SJohn Baldwin #include <signal.h>
37dfa8ba12SJohn Baldwin #include <stdio.h>
38c209e3e2SJohn Baldwin #include <stdlib.h>
39c209e3e2SJohn Baldwin #include <unistd.h>
40c209e3e2SJohn Baldwin #include <atf-c.h>
41c209e3e2SJohn Baldwin 
42c209e3e2SJohn Baldwin /*
43dfa8ba12SJohn Baldwin  * A variant of ATF_REQUIRE that is suitable for use in child
44dfa8ba12SJohn Baldwin  * processes.  This only works if the parent process is tripped up by
45dfa8ba12SJohn Baldwin  * the early exit and fails some requirement itself.
46dfa8ba12SJohn Baldwin  */
47dfa8ba12SJohn Baldwin #define	CHILD_REQUIRE(exp) do {						\
48dfa8ba12SJohn Baldwin 		if (!(exp))						\
49dfa8ba12SJohn Baldwin 			child_fail_require(__FILE__, __LINE__,		\
50dfa8ba12SJohn Baldwin 			    #exp " not met");				\
51dfa8ba12SJohn Baldwin 	} while (0)
52dfa8ba12SJohn Baldwin 
5398685dc8SJohn Baldwin static __dead2 void
54dfa8ba12SJohn Baldwin child_fail_require(const char *file, int line, const char *str)
55dfa8ba12SJohn Baldwin {
56dfa8ba12SJohn Baldwin 	char buf[128];
57dfa8ba12SJohn Baldwin 
58dfa8ba12SJohn Baldwin 	snprintf(buf, sizeof(buf), "%s:%d: %s\n", file, line, str);
59dfa8ba12SJohn Baldwin 	write(2, buf, strlen(buf));
60dfa8ba12SJohn Baldwin 	_exit(32);
61dfa8ba12SJohn Baldwin }
62dfa8ba12SJohn Baldwin 
6398685dc8SJohn Baldwin static void
6498685dc8SJohn Baldwin trace_me(void)
6598685dc8SJohn Baldwin {
6698685dc8SJohn Baldwin 
6798685dc8SJohn Baldwin 	/* Attach the parent process as a tracer of this process. */
6898685dc8SJohn Baldwin 	CHILD_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
6998685dc8SJohn Baldwin 
7098685dc8SJohn Baldwin 	/* Trigger a stop. */
7198685dc8SJohn Baldwin 	raise(SIGSTOP);
7298685dc8SJohn Baldwin }
7398685dc8SJohn Baldwin 
7498685dc8SJohn Baldwin static void
7598685dc8SJohn Baldwin attach_child(pid_t pid)
7698685dc8SJohn Baldwin {
7798685dc8SJohn Baldwin 	pid_t wpid;
7898685dc8SJohn Baldwin 	int status;
7998685dc8SJohn Baldwin 
8098685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_ATTACH, pid, NULL, 0) == 0);
8198685dc8SJohn Baldwin 
8298685dc8SJohn Baldwin 	wpid = waitpid(pid, &status, 0);
8398685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == pid);
8498685dc8SJohn Baldwin 	ATF_REQUIRE(WIFSTOPPED(status));
8598685dc8SJohn Baldwin 	ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
8698685dc8SJohn Baldwin }
8798685dc8SJohn Baldwin 
8898685dc8SJohn Baldwin static void
8998685dc8SJohn Baldwin wait_for_zombie(pid_t pid)
9098685dc8SJohn Baldwin {
9198685dc8SJohn Baldwin 
9298685dc8SJohn Baldwin 	/*
9398685dc8SJohn Baldwin 	 * Wait for a process to exit.  This is kind of gross, but
9498685dc8SJohn Baldwin 	 * there is not a better way.
9598685dc8SJohn Baldwin 	 */
9698685dc8SJohn Baldwin 	for (;;) {
9798685dc8SJohn Baldwin 		struct kinfo_proc kp;
9898685dc8SJohn Baldwin 		size_t len;
9998685dc8SJohn Baldwin 		int mib[4];
10098685dc8SJohn Baldwin 
10198685dc8SJohn Baldwin 		mib[0] = CTL_KERN;
10298685dc8SJohn Baldwin 		mib[1] = KERN_PROC;
10398685dc8SJohn Baldwin 		mib[2] = KERN_PROC_PID;
10498685dc8SJohn Baldwin 		mib[3] = pid;
10598685dc8SJohn Baldwin 		len = sizeof(kp);
10698685dc8SJohn Baldwin 		if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) {
10798685dc8SJohn Baldwin 			/* The KERN_PROC_PID sysctl fails for zombies. */
10898685dc8SJohn Baldwin 			ATF_REQUIRE(errno == ESRCH);
10998685dc8SJohn Baldwin 			break;
11098685dc8SJohn Baldwin 		}
11198685dc8SJohn Baldwin 		usleep(5000);
11298685dc8SJohn Baldwin 	}
11398685dc8SJohn Baldwin }
11498685dc8SJohn Baldwin 
115dfa8ba12SJohn Baldwin /*
116c209e3e2SJohn Baldwin  * Verify that a parent debugger process "sees" the exit of a debugged
117c209e3e2SJohn Baldwin  * process exactly once when attached via PT_TRACE_ME.
118c209e3e2SJohn Baldwin  */
119c209e3e2SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_trace_me);
120c209e3e2SJohn Baldwin ATF_TC_BODY(ptrace__parent_wait_after_trace_me, tc)
121c209e3e2SJohn Baldwin {
122c209e3e2SJohn Baldwin 	pid_t child, wpid;
123c209e3e2SJohn Baldwin 	int status;
124c209e3e2SJohn Baldwin 
125c209e3e2SJohn Baldwin 	ATF_REQUIRE((child = fork()) != -1);
126c209e3e2SJohn Baldwin 	if (child == 0) {
127c209e3e2SJohn Baldwin 		/* Child process. */
12898685dc8SJohn Baldwin 		trace_me();
129c209e3e2SJohn Baldwin 
130*b98cb919SJohn Baldwin 		_exit(1);
131c209e3e2SJohn Baldwin 	}
132c209e3e2SJohn Baldwin 
133c209e3e2SJohn Baldwin 	/* Parent process. */
134c209e3e2SJohn Baldwin 
135c209e3e2SJohn Baldwin 	/* The first wait() should report the stop from SIGSTOP. */
136c209e3e2SJohn Baldwin 	wpid = waitpid(child, &status, 0);
137c209e3e2SJohn Baldwin 	ATF_REQUIRE(wpid == child);
138c209e3e2SJohn Baldwin 	ATF_REQUIRE(WIFSTOPPED(status));
139c209e3e2SJohn Baldwin 	ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
140c209e3e2SJohn Baldwin 
141c209e3e2SJohn Baldwin 	/* Continue the child ignoring the SIGSTOP. */
142c209e3e2SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
143c209e3e2SJohn Baldwin 
144c209e3e2SJohn Baldwin 	/* The second wait() should report the exit status. */
145c209e3e2SJohn Baldwin 	wpid = waitpid(child, &status, 0);
146c209e3e2SJohn Baldwin 	ATF_REQUIRE(wpid == child);
147c209e3e2SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
148c209e3e2SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
149c209e3e2SJohn Baldwin 
150c209e3e2SJohn Baldwin 	/* The child should no longer exist. */
151c209e3e2SJohn Baldwin 	wpid = waitpid(child, &status, 0);
152c209e3e2SJohn Baldwin 	ATF_REQUIRE(wpid == -1);
153c209e3e2SJohn Baldwin 	ATF_REQUIRE(errno == ECHILD);
154c209e3e2SJohn Baldwin }
155c209e3e2SJohn Baldwin 
156c209e3e2SJohn Baldwin /*
157c209e3e2SJohn Baldwin  * Verify that a parent debugger process "sees" the exit of a debugged
158c209e3e2SJohn Baldwin  * process exactly once when attached via PT_ATTACH.
159c209e3e2SJohn Baldwin  */
160c209e3e2SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_attach);
161c209e3e2SJohn Baldwin ATF_TC_BODY(ptrace__parent_wait_after_attach, tc)
162c209e3e2SJohn Baldwin {
163c209e3e2SJohn Baldwin 	pid_t child, wpid;
164c209e3e2SJohn Baldwin 	int cpipe[2], status;
165c209e3e2SJohn Baldwin 	char c;
166c209e3e2SJohn Baldwin 
167c209e3e2SJohn Baldwin 	ATF_REQUIRE(pipe(cpipe) == 0);
168c209e3e2SJohn Baldwin 	ATF_REQUIRE((child = fork()) != -1);
169c209e3e2SJohn Baldwin 	if (child == 0) {
170c209e3e2SJohn Baldwin 		/* Child process. */
171c209e3e2SJohn Baldwin 		close(cpipe[0]);
172c209e3e2SJohn Baldwin 
173c209e3e2SJohn Baldwin 		/* Wait for the parent to attach. */
174dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == 0);
175c209e3e2SJohn Baldwin 
176*b98cb919SJohn Baldwin 		_exit(1);
177c209e3e2SJohn Baldwin 	}
178c209e3e2SJohn Baldwin 	close(cpipe[1]);
179c209e3e2SJohn Baldwin 
180c209e3e2SJohn Baldwin 	/* Parent process. */
181c209e3e2SJohn Baldwin 
182c209e3e2SJohn Baldwin 	/* Attach to the child process. */
18398685dc8SJohn Baldwin 	attach_child(child);
184c209e3e2SJohn Baldwin 
185c209e3e2SJohn Baldwin 	/* Continue the child ignoring the SIGSTOP. */
186c209e3e2SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
187c209e3e2SJohn Baldwin 
188c209e3e2SJohn Baldwin 	/* Signal the child to exit. */
189c209e3e2SJohn Baldwin 	close(cpipe[0]);
190c209e3e2SJohn Baldwin 
191c209e3e2SJohn Baldwin 	/* The second wait() should report the exit status. */
192c209e3e2SJohn Baldwin 	wpid = waitpid(child, &status, 0);
193c209e3e2SJohn Baldwin 	ATF_REQUIRE(wpid == child);
194c209e3e2SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
195c209e3e2SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
196c209e3e2SJohn Baldwin 
197c209e3e2SJohn Baldwin 	/* The child should no longer exist. */
198c209e3e2SJohn Baldwin 	wpid = waitpid(child, &status, 0);
199c209e3e2SJohn Baldwin 	ATF_REQUIRE(wpid == -1);
200c209e3e2SJohn Baldwin 	ATF_REQUIRE(errno == ECHILD);
201c209e3e2SJohn Baldwin }
202c209e3e2SJohn Baldwin 
20357c74f5bSJohn Baldwin /*
20457c74f5bSJohn Baldwin  * Verify that a parent process "sees" the exit of a debugged process only
20557c74f5bSJohn Baldwin  * after the debugger has seen it.
20657c74f5bSJohn Baldwin  */
20757c74f5bSJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_child_debugger);
20857c74f5bSJohn Baldwin ATF_TC_BODY(ptrace__parent_sees_exit_after_child_debugger, tc)
20957c74f5bSJohn Baldwin {
21057c74f5bSJohn Baldwin 	pid_t child, debugger, wpid;
21157c74f5bSJohn Baldwin 	int cpipe[2], dpipe[2], status;
21257c74f5bSJohn Baldwin 	char c;
21357c74f5bSJohn Baldwin 
21457c74f5bSJohn Baldwin 	ATF_REQUIRE(pipe(cpipe) == 0);
21557c74f5bSJohn Baldwin 	ATF_REQUIRE((child = fork()) != -1);
21657c74f5bSJohn Baldwin 
21757c74f5bSJohn Baldwin 	if (child == 0) {
21857c74f5bSJohn Baldwin 		/* Child process. */
21957c74f5bSJohn Baldwin 		close(cpipe[0]);
22057c74f5bSJohn Baldwin 
22157c74f5bSJohn Baldwin 		/* Wait for parent to be ready. */
222dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c));
22357c74f5bSJohn Baldwin 
224*b98cb919SJohn Baldwin 		_exit(1);
22557c74f5bSJohn Baldwin 	}
22657c74f5bSJohn Baldwin 	close(cpipe[1]);
22757c74f5bSJohn Baldwin 
22857c74f5bSJohn Baldwin 	ATF_REQUIRE(pipe(dpipe) == 0);
22957c74f5bSJohn Baldwin 	ATF_REQUIRE((debugger = fork()) != -1);
23057c74f5bSJohn Baldwin 
23157c74f5bSJohn Baldwin 	if (debugger == 0) {
23257c74f5bSJohn Baldwin 		/* Debugger process. */
23357c74f5bSJohn Baldwin 		close(dpipe[0]);
23457c74f5bSJohn Baldwin 
235dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1);
23657c74f5bSJohn Baldwin 
23757c74f5bSJohn Baldwin 		wpid = waitpid(child, &status, 0);
238dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(wpid == child);
239dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(WIFSTOPPED(status));
240dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP);
24157c74f5bSJohn Baldwin 
242dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
24357c74f5bSJohn Baldwin 
24457c74f5bSJohn Baldwin 		/* Signal parent that debugger is attached. */
245dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c));
24657c74f5bSJohn Baldwin 
24757c74f5bSJohn Baldwin 		/* Wait for parent's failed wait. */
248dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(read(dpipe[1], &c, sizeof(c)) == 0);
24957c74f5bSJohn Baldwin 
25057c74f5bSJohn Baldwin 		wpid = waitpid(child, &status, 0);
251dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(wpid == child);
252dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(WIFEXITED(status));
253dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(WEXITSTATUS(status) == 1);
25457c74f5bSJohn Baldwin 
255*b98cb919SJohn Baldwin 		_exit(0);
25657c74f5bSJohn Baldwin 	}
25757c74f5bSJohn Baldwin 	close(dpipe[1]);
25857c74f5bSJohn Baldwin 
25957c74f5bSJohn Baldwin 	/* Parent process. */
26057c74f5bSJohn Baldwin 
26157c74f5bSJohn Baldwin 	/* Wait for the debugger to attach to the child. */
26257c74f5bSJohn Baldwin 	ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c));
26357c74f5bSJohn Baldwin 
26457c74f5bSJohn Baldwin 	/* Release the child. */
26557c74f5bSJohn Baldwin 	ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c));
26657c74f5bSJohn Baldwin 	ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0);
26757c74f5bSJohn Baldwin 	close(cpipe[0]);
26857c74f5bSJohn Baldwin 
26998685dc8SJohn Baldwin 	wait_for_zombie(child);
27057c74f5bSJohn Baldwin 
27157c74f5bSJohn Baldwin 	/*
2722f021998SJohn Baldwin 	 * This wait should return a pid of 0 to indicate no status to
2732f021998SJohn Baldwin 	 * report.  The parent should see the child as non-exited
2742f021998SJohn Baldwin 	 * until the debugger sees the exit.
27557c74f5bSJohn Baldwin 	 */
27657c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
27757c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == 0);
27857c74f5bSJohn Baldwin 
27957c74f5bSJohn Baldwin 	/* Signal the debugger to wait for the child. */
28057c74f5bSJohn Baldwin 	close(dpipe[0]);
28157c74f5bSJohn Baldwin 
28257c74f5bSJohn Baldwin 	/* Wait for the debugger. */
28357c74f5bSJohn Baldwin 	wpid = waitpid(debugger, &status, 0);
28457c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == debugger);
28557c74f5bSJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
28657c74f5bSJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 0);
28757c74f5bSJohn Baldwin 
28857c74f5bSJohn Baldwin 	/* The child process should now be ready. */
28957c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
29057c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == child);
29157c74f5bSJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
29257c74f5bSJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
29357c74f5bSJohn Baldwin }
29457c74f5bSJohn Baldwin 
29557c74f5bSJohn Baldwin /*
29657c74f5bSJohn Baldwin  * Verify that a parent process "sees" the exit of a debugged process
29757c74f5bSJohn Baldwin  * only after a non-direct-child debugger has seen it.  In particular,
29857c74f5bSJohn Baldwin  * various wait() calls in the parent must avoid failing with ESRCH by
29957c74f5bSJohn Baldwin  * checking the parent's orphan list for the debugee.
30057c74f5bSJohn Baldwin  */
30157c74f5bSJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_unrelated_debugger);
30257c74f5bSJohn Baldwin ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc)
30357c74f5bSJohn Baldwin {
30457c74f5bSJohn Baldwin 	pid_t child, debugger, fpid, wpid;
30557c74f5bSJohn Baldwin 	int cpipe[2], dpipe[2], status;
30657c74f5bSJohn Baldwin 	char c;
30757c74f5bSJohn Baldwin 
30857c74f5bSJohn Baldwin 	ATF_REQUIRE(pipe(cpipe) == 0);
30957c74f5bSJohn Baldwin 	ATF_REQUIRE((child = fork()) != -1);
31057c74f5bSJohn Baldwin 
31157c74f5bSJohn Baldwin 	if (child == 0) {
31257c74f5bSJohn Baldwin 		/* Child process. */
31357c74f5bSJohn Baldwin 		close(cpipe[0]);
31457c74f5bSJohn Baldwin 
31557c74f5bSJohn Baldwin 		/* Wait for parent to be ready. */
316dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c));
31757c74f5bSJohn Baldwin 
318*b98cb919SJohn Baldwin 		_exit(1);
31957c74f5bSJohn Baldwin 	}
32057c74f5bSJohn Baldwin 	close(cpipe[1]);
32157c74f5bSJohn Baldwin 
32257c74f5bSJohn Baldwin 	ATF_REQUIRE(pipe(dpipe) == 0);
32357c74f5bSJohn Baldwin 	ATF_REQUIRE((debugger = fork()) != -1);
32457c74f5bSJohn Baldwin 
32557c74f5bSJohn Baldwin 	if (debugger == 0) {
32657c74f5bSJohn Baldwin 		/* Debugger parent. */
32757c74f5bSJohn Baldwin 
32857c74f5bSJohn Baldwin 		/*
32957c74f5bSJohn Baldwin 		 * Fork again and drop the debugger parent so that the
33057c74f5bSJohn Baldwin 		 * debugger is not a child of the main parent.
33157c74f5bSJohn Baldwin 		 */
332dfa8ba12SJohn Baldwin 		CHILD_REQUIRE((fpid = fork()) != -1);
33357c74f5bSJohn Baldwin 		if (fpid != 0)
334*b98cb919SJohn Baldwin 			_exit(2);
33557c74f5bSJohn Baldwin 
33657c74f5bSJohn Baldwin 		/* Debugger process. */
33757c74f5bSJohn Baldwin 		close(dpipe[0]);
33857c74f5bSJohn Baldwin 
339dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1);
34057c74f5bSJohn Baldwin 
34157c74f5bSJohn Baldwin 		wpid = waitpid(child, &status, 0);
342dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(wpid == child);
343dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(WIFSTOPPED(status));
344dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP);
34557c74f5bSJohn Baldwin 
346dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
34757c74f5bSJohn Baldwin 
34857c74f5bSJohn Baldwin 		/* Signal parent that debugger is attached. */
349dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c));
35057c74f5bSJohn Baldwin 
35157c74f5bSJohn Baldwin 		/* Wait for parent's failed wait. */
352dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(read(dpipe[1], &c, sizeof(c)) == sizeof(c));
35357c74f5bSJohn Baldwin 
35457c74f5bSJohn Baldwin 		wpid = waitpid(child, &status, 0);
355dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(wpid == child);
356dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(WIFEXITED(status));
357dfa8ba12SJohn Baldwin 		CHILD_REQUIRE(WEXITSTATUS(status) == 1);
35857c74f5bSJohn Baldwin 
359*b98cb919SJohn Baldwin 		_exit(0);
36057c74f5bSJohn Baldwin 	}
361eddb85c6SJohn Baldwin 	close(dpipe[1]);
36257c74f5bSJohn Baldwin 
36357c74f5bSJohn Baldwin 	/* Parent process. */
36457c74f5bSJohn Baldwin 
36557c74f5bSJohn Baldwin 	/* Wait for the debugger parent process to exit. */
36657c74f5bSJohn Baldwin 	wpid = waitpid(debugger, &status, 0);
36757c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == debugger);
36857c74f5bSJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
36957c74f5bSJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 2);
37057c74f5bSJohn Baldwin 
37157c74f5bSJohn Baldwin 	/* A WNOHANG wait here should see the non-exited child. */
37257c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
37357c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == 0);
37457c74f5bSJohn Baldwin 
37557c74f5bSJohn Baldwin 	/* Wait for the debugger to attach to the child. */
37657c74f5bSJohn Baldwin 	ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c));
37757c74f5bSJohn Baldwin 
37857c74f5bSJohn Baldwin 	/* Release the child. */
37957c74f5bSJohn Baldwin 	ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c));
38057c74f5bSJohn Baldwin 	ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0);
38157c74f5bSJohn Baldwin 	close(cpipe[0]);
38257c74f5bSJohn Baldwin 
38398685dc8SJohn Baldwin 	wait_for_zombie(child);
38457c74f5bSJohn Baldwin 
38557c74f5bSJohn Baldwin 	/*
3862f021998SJohn Baldwin 	 * This wait should return a pid of 0 to indicate no status to
3872f021998SJohn Baldwin 	 * report.  The parent should see the child as non-exited
3882f021998SJohn Baldwin 	 * until the debugger sees the exit.
38957c74f5bSJohn Baldwin 	 */
39057c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
39157c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == 0);
39257c74f5bSJohn Baldwin 
39357c74f5bSJohn Baldwin 	/* Signal the debugger to wait for the child. */
394eddb85c6SJohn Baldwin 	ATF_REQUIRE(write(dpipe[0], &c, sizeof(c)) == sizeof(c));
39557c74f5bSJohn Baldwin 
39657c74f5bSJohn Baldwin 	/* Wait for the debugger. */
397eddb85c6SJohn Baldwin 	ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == 0);
398eddb85c6SJohn Baldwin 	close(dpipe[0]);
39957c74f5bSJohn Baldwin 
40057c74f5bSJohn Baldwin 	/* The child process should now be ready. */
40157c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
40257c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == child);
40357c74f5bSJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
40457c74f5bSJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
40557c74f5bSJohn Baldwin }
40657c74f5bSJohn Baldwin 
40798685dc8SJohn Baldwin /*
40898685dc8SJohn Baldwin  * The parent process should always act the same regardless of how the
40998685dc8SJohn Baldwin  * debugger is attached to it.
41098685dc8SJohn Baldwin  */
41198685dc8SJohn Baldwin static __dead2 void
41298685dc8SJohn Baldwin follow_fork_parent(void)
41398685dc8SJohn Baldwin {
41498685dc8SJohn Baldwin 	pid_t fpid, wpid;
41598685dc8SJohn Baldwin 	int status;
41698685dc8SJohn Baldwin 
41798685dc8SJohn Baldwin 	CHILD_REQUIRE((fpid = fork()) != -1);
41898685dc8SJohn Baldwin 
41998685dc8SJohn Baldwin 	if (fpid == 0)
42098685dc8SJohn Baldwin 		/* Child */
421*b98cb919SJohn Baldwin 		_exit(2);
42298685dc8SJohn Baldwin 
42398685dc8SJohn Baldwin 	wpid = waitpid(fpid, &status, 0);
42498685dc8SJohn Baldwin 	CHILD_REQUIRE(wpid == fpid);
42598685dc8SJohn Baldwin 	CHILD_REQUIRE(WIFEXITED(status));
42698685dc8SJohn Baldwin 	CHILD_REQUIRE(WEXITSTATUS(status) == 2);
42798685dc8SJohn Baldwin 
428*b98cb919SJohn Baldwin 	_exit(1);
42998685dc8SJohn Baldwin }
43098685dc8SJohn Baldwin 
43198685dc8SJohn Baldwin /*
43298685dc8SJohn Baldwin  * Helper routine for follow fork tests.  This waits for two stops
43398685dc8SJohn Baldwin  * that report both "sides" of a fork.  It returns the pid of the new
43498685dc8SJohn Baldwin  * child process.
43598685dc8SJohn Baldwin  */
43698685dc8SJohn Baldwin static pid_t
43798685dc8SJohn Baldwin handle_fork_events(pid_t parent)
43898685dc8SJohn Baldwin {
43998685dc8SJohn Baldwin 	struct ptrace_lwpinfo pl;
44098685dc8SJohn Baldwin 	bool fork_reported[2];
44198685dc8SJohn Baldwin 	pid_t child, wpid;
44298685dc8SJohn Baldwin 	int i, status;
44398685dc8SJohn Baldwin 
44498685dc8SJohn Baldwin 	fork_reported[0] = false;
44598685dc8SJohn Baldwin 	fork_reported[1] = false;
44698685dc8SJohn Baldwin 	child = -1;
44798685dc8SJohn Baldwin 
44898685dc8SJohn Baldwin 	/*
44998685dc8SJohn Baldwin 	 * Each process should report a fork event.  The parent should
45098685dc8SJohn Baldwin 	 * report a PL_FLAG_FORKED event, and the child should report
45198685dc8SJohn Baldwin 	 * a PL_FLAG_CHILD event.
45298685dc8SJohn Baldwin 	 */
45398685dc8SJohn Baldwin 	for (i = 0; i < 2; i++) {
45498685dc8SJohn Baldwin 		wpid = wait(&status);
45598685dc8SJohn Baldwin 		ATF_REQUIRE(wpid > 0);
45698685dc8SJohn Baldwin 		ATF_REQUIRE(WIFSTOPPED(status));
45798685dc8SJohn Baldwin 
45898685dc8SJohn Baldwin 		ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl,
45998685dc8SJohn Baldwin 		    sizeof(pl)) != -1);
46098685dc8SJohn Baldwin 		ATF_REQUIRE((pl.pl_flags & (PL_FLAG_FORKED | PL_FLAG_CHILD)) !=
46198685dc8SJohn Baldwin 		    0);
46298685dc8SJohn Baldwin 		ATF_REQUIRE((pl.pl_flags & (PL_FLAG_FORKED | PL_FLAG_CHILD)) !=
46398685dc8SJohn Baldwin 		    (PL_FLAG_FORKED | PL_FLAG_CHILD));
46498685dc8SJohn Baldwin 		if (pl.pl_flags & PL_FLAG_CHILD) {
46598685dc8SJohn Baldwin 			ATF_REQUIRE(wpid != parent);
46698685dc8SJohn Baldwin 			ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
46798685dc8SJohn Baldwin 			ATF_REQUIRE(!fork_reported[1]);
46898685dc8SJohn Baldwin 			if (child == -1)
46998685dc8SJohn Baldwin 				child = wpid;
47098685dc8SJohn Baldwin 			else
47198685dc8SJohn Baldwin 				ATF_REQUIRE(child == wpid);
47298685dc8SJohn Baldwin 			fork_reported[1] = true;
47398685dc8SJohn Baldwin 		} else {
47498685dc8SJohn Baldwin 			ATF_REQUIRE(wpid == parent);
47598685dc8SJohn Baldwin 			ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
47698685dc8SJohn Baldwin 			ATF_REQUIRE(!fork_reported[0]);
47798685dc8SJohn Baldwin 			if (child == -1)
47898685dc8SJohn Baldwin 				child = pl.pl_child_pid;
47998685dc8SJohn Baldwin 			else
48098685dc8SJohn Baldwin 				ATF_REQUIRE(child == pl.pl_child_pid);
48198685dc8SJohn Baldwin 			fork_reported[0] = true;
48298685dc8SJohn Baldwin 		}
48398685dc8SJohn Baldwin 	}
48498685dc8SJohn Baldwin 
48598685dc8SJohn Baldwin 	return (child);
48698685dc8SJohn Baldwin }
48798685dc8SJohn Baldwin 
48898685dc8SJohn Baldwin /*
48998685dc8SJohn Baldwin  * Verify that a new child process is stopped after a followed fork and
49098685dc8SJohn Baldwin  * that the traced parent sees the exit of the child after the debugger
49198685dc8SJohn Baldwin  * when both processes remain attached to the debugger.
49298685dc8SJohn Baldwin  */
49398685dc8SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_both_attached);
49498685dc8SJohn Baldwin ATF_TC_BODY(ptrace__follow_fork_both_attached, tc)
49598685dc8SJohn Baldwin {
496479b610dSJohn Baldwin 	pid_t children[2], fpid, wpid;
49798685dc8SJohn Baldwin 	int status;
49898685dc8SJohn Baldwin 
49998685dc8SJohn Baldwin 	ATF_REQUIRE((fpid = fork()) != -1);
50098685dc8SJohn Baldwin 	if (fpid == 0) {
50198685dc8SJohn Baldwin 		trace_me();
50298685dc8SJohn Baldwin 		follow_fork_parent();
50398685dc8SJohn Baldwin 	}
50498685dc8SJohn Baldwin 
50598685dc8SJohn Baldwin 	/* Parent process. */
50698685dc8SJohn Baldwin 	children[0] = fpid;
50798685dc8SJohn Baldwin 
50898685dc8SJohn Baldwin 	/* The first wait() should report the stop from SIGSTOP. */
50998685dc8SJohn Baldwin 	wpid = waitpid(children[0], &status, 0);
51098685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == children[0]);
51198685dc8SJohn Baldwin 	ATF_REQUIRE(WIFSTOPPED(status));
51298685dc8SJohn Baldwin 	ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
51398685dc8SJohn Baldwin 
51498685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
51598685dc8SJohn Baldwin 
51698685dc8SJohn Baldwin 	/* Continue the child ignoring the SIGSTOP. */
51798685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
51898685dc8SJohn Baldwin 
51998685dc8SJohn Baldwin 	children[1] = handle_fork_events(children[0]);
52098685dc8SJohn Baldwin 	ATF_REQUIRE(children[1] > 0);
52198685dc8SJohn Baldwin 
52298685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
52398685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1);
52498685dc8SJohn Baldwin 
52598685dc8SJohn Baldwin 	/*
52698685dc8SJohn Baldwin 	 * The child can't exit until the grandchild reports status, so the
52798685dc8SJohn Baldwin 	 * grandchild should report its exit first to the debugger.
52898685dc8SJohn Baldwin 	 */
52998685dc8SJohn Baldwin 	wpid = wait(&status);
53098685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == children[1]);
53198685dc8SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
53298685dc8SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 2);
53398685dc8SJohn Baldwin 
53498685dc8SJohn Baldwin 	wpid = wait(&status);
53598685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == children[0]);
53698685dc8SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
53798685dc8SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
53898685dc8SJohn Baldwin 
53998685dc8SJohn Baldwin 	wpid = wait(&status);
54098685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == -1);
54198685dc8SJohn Baldwin 	ATF_REQUIRE(errno == ECHILD);
54298685dc8SJohn Baldwin }
54398685dc8SJohn Baldwin 
54498685dc8SJohn Baldwin /*
54598685dc8SJohn Baldwin  * Verify that a new child process is stopped after a followed fork
54698685dc8SJohn Baldwin  * and that the traced parent sees the exit of the child when the new
54798685dc8SJohn Baldwin  * child process is detached after it reports its fork.
54898685dc8SJohn Baldwin  */
54998685dc8SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached);
55098685dc8SJohn Baldwin ATF_TC_BODY(ptrace__follow_fork_child_detached, tc)
55198685dc8SJohn Baldwin {
552479b610dSJohn Baldwin 	pid_t children[2], fpid, wpid;
55398685dc8SJohn Baldwin 	int status;
55498685dc8SJohn Baldwin 
55598685dc8SJohn Baldwin 	ATF_REQUIRE((fpid = fork()) != -1);
55698685dc8SJohn Baldwin 	if (fpid == 0) {
55798685dc8SJohn Baldwin 		trace_me();
55898685dc8SJohn Baldwin 		follow_fork_parent();
55998685dc8SJohn Baldwin 	}
56098685dc8SJohn Baldwin 
56198685dc8SJohn Baldwin 	/* Parent process. */
56298685dc8SJohn Baldwin 	children[0] = fpid;
56398685dc8SJohn Baldwin 
56498685dc8SJohn Baldwin 	/* The first wait() should report the stop from SIGSTOP. */
56598685dc8SJohn Baldwin 	wpid = waitpid(children[0], &status, 0);
56698685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == children[0]);
56798685dc8SJohn Baldwin 	ATF_REQUIRE(WIFSTOPPED(status));
56898685dc8SJohn Baldwin 	ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
56998685dc8SJohn Baldwin 
57098685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
57198685dc8SJohn Baldwin 
57298685dc8SJohn Baldwin 	/* Continue the child ignoring the SIGSTOP. */
57398685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
57498685dc8SJohn Baldwin 
57598685dc8SJohn Baldwin 	children[1] = handle_fork_events(children[0]);
57698685dc8SJohn Baldwin 	ATF_REQUIRE(children[1] > 0);
57798685dc8SJohn Baldwin 
57898685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
57998685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_DETACH, children[1], (caddr_t)1, 0) != -1);
58098685dc8SJohn Baldwin 
58198685dc8SJohn Baldwin 	/*
58298685dc8SJohn Baldwin 	 * Should not see any status from the grandchild now, only the
58398685dc8SJohn Baldwin 	 * child.
58498685dc8SJohn Baldwin 	 */
58598685dc8SJohn Baldwin 	wpid = wait(&status);
58698685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == children[0]);
58798685dc8SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
58898685dc8SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
58998685dc8SJohn Baldwin 
59098685dc8SJohn Baldwin 	wpid = wait(&status);
59198685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == -1);
59298685dc8SJohn Baldwin 	ATF_REQUIRE(errno == ECHILD);
59398685dc8SJohn Baldwin }
59498685dc8SJohn Baldwin 
59598685dc8SJohn Baldwin /*
59698685dc8SJohn Baldwin  * Verify that a new child process is stopped after a followed fork
59798685dc8SJohn Baldwin  * and that the traced parent sees the exit of the child when the
59898685dc8SJohn Baldwin  * traced parent is detached after the fork.
59998685dc8SJohn Baldwin  */
60098685dc8SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_parent_detached);
60198685dc8SJohn Baldwin ATF_TC_BODY(ptrace__follow_fork_parent_detached, tc)
60298685dc8SJohn Baldwin {
603479b610dSJohn Baldwin 	pid_t children[2], fpid, wpid;
60498685dc8SJohn Baldwin 	int status;
60598685dc8SJohn Baldwin 
60698685dc8SJohn Baldwin 	ATF_REQUIRE((fpid = fork()) != -1);
60798685dc8SJohn Baldwin 	if (fpid == 0) {
60898685dc8SJohn Baldwin 		trace_me();
60998685dc8SJohn Baldwin 		follow_fork_parent();
61098685dc8SJohn Baldwin 	}
61198685dc8SJohn Baldwin 
61298685dc8SJohn Baldwin 	/* Parent process. */
61398685dc8SJohn Baldwin 	children[0] = fpid;
61498685dc8SJohn Baldwin 
61598685dc8SJohn Baldwin 	/* The first wait() should report the stop from SIGSTOP. */
61698685dc8SJohn Baldwin 	wpid = waitpid(children[0], &status, 0);
61798685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == children[0]);
61898685dc8SJohn Baldwin 	ATF_REQUIRE(WIFSTOPPED(status));
61998685dc8SJohn Baldwin 	ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
62098685dc8SJohn Baldwin 
62198685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
62298685dc8SJohn Baldwin 
62398685dc8SJohn Baldwin 	/* Continue the child ignoring the SIGSTOP. */
62498685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
62598685dc8SJohn Baldwin 
62698685dc8SJohn Baldwin 	children[1] = handle_fork_events(children[0]);
62798685dc8SJohn Baldwin 	ATF_REQUIRE(children[1] > 0);
62898685dc8SJohn Baldwin 
62998685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1);
63098685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1);
63198685dc8SJohn Baldwin 
63298685dc8SJohn Baldwin 	/*
63398685dc8SJohn Baldwin 	 * The child can't exit until the grandchild reports status, so the
63498685dc8SJohn Baldwin 	 * grandchild should report its exit first to the debugger.
63598685dc8SJohn Baldwin 	 *
63698685dc8SJohn Baldwin 	 * Even though the child process is detached, it is still a
63798685dc8SJohn Baldwin 	 * child of the debugger, so it will still report it's exit
63898685dc8SJohn Baldwin 	 * after the grandchild.
63998685dc8SJohn Baldwin 	 */
64098685dc8SJohn Baldwin 	wpid = wait(&status);
64198685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == children[1]);
64298685dc8SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
64398685dc8SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 2);
64498685dc8SJohn Baldwin 
64598685dc8SJohn Baldwin 	wpid = wait(&status);
64698685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == children[0]);
64798685dc8SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
64898685dc8SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
64998685dc8SJohn Baldwin 
65098685dc8SJohn Baldwin 	wpid = wait(&status);
65198685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == -1);
65298685dc8SJohn Baldwin 	ATF_REQUIRE(errno == ECHILD);
65398685dc8SJohn Baldwin }
65498685dc8SJohn Baldwin 
65598685dc8SJohn Baldwin static void
65698685dc8SJohn Baldwin attach_fork_parent(int cpipe[2])
65798685dc8SJohn Baldwin {
65898685dc8SJohn Baldwin 	pid_t fpid;
65998685dc8SJohn Baldwin 
66098685dc8SJohn Baldwin 	close(cpipe[0]);
66198685dc8SJohn Baldwin 
66298685dc8SJohn Baldwin 	/* Double-fork to disassociate from the debugger. */
66398685dc8SJohn Baldwin 	CHILD_REQUIRE((fpid = fork()) != -1);
66498685dc8SJohn Baldwin 	if (fpid != 0)
665*b98cb919SJohn Baldwin 		_exit(3);
66698685dc8SJohn Baldwin 
66798685dc8SJohn Baldwin 	/* Send the pid of the disassociated child to the debugger. */
66898685dc8SJohn Baldwin 	fpid = getpid();
66998685dc8SJohn Baldwin 	CHILD_REQUIRE(write(cpipe[1], &fpid, sizeof(fpid)) == sizeof(fpid));
67098685dc8SJohn Baldwin 
67198685dc8SJohn Baldwin 	/* Wait for the debugger to attach. */
67298685dc8SJohn Baldwin 	CHILD_REQUIRE(read(cpipe[1], &fpid, sizeof(fpid)) == 0);
67398685dc8SJohn Baldwin }
67498685dc8SJohn Baldwin 
67598685dc8SJohn Baldwin /*
67698685dc8SJohn Baldwin  * Verify that a new child process is stopped after a followed fork and
67798685dc8SJohn Baldwin  * that the traced parent sees the exit of the child after the debugger
67898685dc8SJohn Baldwin  * when both processes remain attached to the debugger.  In this test
67998685dc8SJohn Baldwin  * the parent that forks is not a direct child of the debugger.
68098685dc8SJohn Baldwin  */
68198685dc8SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_both_attached_unrelated_debugger);
68298685dc8SJohn Baldwin ATF_TC_BODY(ptrace__follow_fork_both_attached_unrelated_debugger, tc)
68398685dc8SJohn Baldwin {
684479b610dSJohn Baldwin 	pid_t children[2], fpid, wpid;
68598685dc8SJohn Baldwin 	int cpipe[2], status;
68698685dc8SJohn Baldwin 
68798685dc8SJohn Baldwin 	ATF_REQUIRE(pipe(cpipe) == 0);
68898685dc8SJohn Baldwin 	ATF_REQUIRE((fpid = fork()) != -1);
68998685dc8SJohn Baldwin 	if (fpid == 0) {
69098685dc8SJohn Baldwin 		attach_fork_parent(cpipe);
69198685dc8SJohn Baldwin 		follow_fork_parent();
69298685dc8SJohn Baldwin 	}
69398685dc8SJohn Baldwin 
69498685dc8SJohn Baldwin 	/* Parent process. */
69598685dc8SJohn Baldwin 	close(cpipe[1]);
69698685dc8SJohn Baldwin 
69798685dc8SJohn Baldwin 	/* Wait for the direct child to exit. */
69898685dc8SJohn Baldwin 	wpid = waitpid(fpid, &status, 0);
69998685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == fpid);
70098685dc8SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
70198685dc8SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 3);
70298685dc8SJohn Baldwin 
70398685dc8SJohn Baldwin 	/* Read the pid of the fork parent. */
70498685dc8SJohn Baldwin 	ATF_REQUIRE(read(cpipe[0], &children[0], sizeof(children[0])) ==
70598685dc8SJohn Baldwin 	    sizeof(children[0]));
70698685dc8SJohn Baldwin 
70798685dc8SJohn Baldwin 	/* Attach to the fork parent. */
70898685dc8SJohn Baldwin 	attach_child(children[0]);
70998685dc8SJohn Baldwin 
71098685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
71198685dc8SJohn Baldwin 
71298685dc8SJohn Baldwin 	/* Continue the fork parent ignoring the SIGSTOP. */
71398685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
71498685dc8SJohn Baldwin 
71598685dc8SJohn Baldwin 	/* Signal the fork parent to continue. */
71698685dc8SJohn Baldwin 	close(cpipe[0]);
71798685dc8SJohn Baldwin 
71898685dc8SJohn Baldwin 	children[1] = handle_fork_events(children[0]);
71998685dc8SJohn Baldwin 	ATF_REQUIRE(children[1] > 0);
72098685dc8SJohn Baldwin 
72198685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
72298685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1);
72398685dc8SJohn Baldwin 
72498685dc8SJohn Baldwin 	/*
72598685dc8SJohn Baldwin 	 * The fork parent can't exit until the child reports status,
72698685dc8SJohn Baldwin 	 * so the child should report its exit first to the debugger.
72798685dc8SJohn Baldwin 	 */
72898685dc8SJohn Baldwin 	wpid = wait(&status);
72998685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == children[1]);
73098685dc8SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
73198685dc8SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 2);
73298685dc8SJohn Baldwin 
73398685dc8SJohn Baldwin 	wpid = wait(&status);
73498685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == children[0]);
73598685dc8SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
73698685dc8SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
73798685dc8SJohn Baldwin 
73898685dc8SJohn Baldwin 	wpid = wait(&status);
73998685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == -1);
74098685dc8SJohn Baldwin 	ATF_REQUIRE(errno == ECHILD);
74198685dc8SJohn Baldwin }
74298685dc8SJohn Baldwin 
74398685dc8SJohn Baldwin /*
74498685dc8SJohn Baldwin  * Verify that a new child process is stopped after a followed fork
74598685dc8SJohn Baldwin  * and that the traced parent sees the exit of the child when the new
74698685dc8SJohn Baldwin  * child process is detached after it reports its fork.  In this test
74798685dc8SJohn Baldwin  * the parent that forks is not a direct child of the debugger.
74898685dc8SJohn Baldwin  */
74998685dc8SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached_unrelated_debugger);
75098685dc8SJohn Baldwin ATF_TC_BODY(ptrace__follow_fork_child_detached_unrelated_debugger, tc)
75198685dc8SJohn Baldwin {
752479b610dSJohn Baldwin 	pid_t children[2], fpid, wpid;
75398685dc8SJohn Baldwin 	int cpipe[2], status;
75498685dc8SJohn Baldwin 
75598685dc8SJohn Baldwin 	ATF_REQUIRE(pipe(cpipe) == 0);
75698685dc8SJohn Baldwin 	ATF_REQUIRE((fpid = fork()) != -1);
75798685dc8SJohn Baldwin 	if (fpid == 0) {
75898685dc8SJohn Baldwin 		attach_fork_parent(cpipe);
75998685dc8SJohn Baldwin 		follow_fork_parent();
76098685dc8SJohn Baldwin 	}
76198685dc8SJohn Baldwin 
76298685dc8SJohn Baldwin 	/* Parent process. */
76398685dc8SJohn Baldwin 	close(cpipe[1]);
76498685dc8SJohn Baldwin 
76598685dc8SJohn Baldwin 	/* Wait for the direct child to exit. */
76698685dc8SJohn Baldwin 	wpid = waitpid(fpid, &status, 0);
76798685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == fpid);
76898685dc8SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
76998685dc8SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 3);
77098685dc8SJohn Baldwin 
77198685dc8SJohn Baldwin 	/* Read the pid of the fork parent. */
77298685dc8SJohn Baldwin 	ATF_REQUIRE(read(cpipe[0], &children[0], sizeof(children[0])) ==
77398685dc8SJohn Baldwin 	    sizeof(children[0]));
77498685dc8SJohn Baldwin 
77598685dc8SJohn Baldwin 	/* Attach to the fork parent. */
77698685dc8SJohn Baldwin 	attach_child(children[0]);
77798685dc8SJohn Baldwin 
77898685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
77998685dc8SJohn Baldwin 
78098685dc8SJohn Baldwin 	/* Continue the fork parent ignoring the SIGSTOP. */
78198685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
78298685dc8SJohn Baldwin 
78398685dc8SJohn Baldwin 	/* Signal the fork parent to continue. */
78498685dc8SJohn Baldwin 	close(cpipe[0]);
78598685dc8SJohn Baldwin 
78698685dc8SJohn Baldwin 	children[1] = handle_fork_events(children[0]);
78798685dc8SJohn Baldwin 	ATF_REQUIRE(children[1] > 0);
78898685dc8SJohn Baldwin 
78998685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
79098685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_DETACH, children[1], (caddr_t)1, 0) != -1);
79198685dc8SJohn Baldwin 
79298685dc8SJohn Baldwin 	/*
79398685dc8SJohn Baldwin 	 * Should not see any status from the child now, only the fork
79498685dc8SJohn Baldwin 	 * parent.
79598685dc8SJohn Baldwin 	 */
79698685dc8SJohn Baldwin 	wpid = wait(&status);
79798685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == children[0]);
79898685dc8SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
79998685dc8SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
80098685dc8SJohn Baldwin 
80198685dc8SJohn Baldwin 	wpid = wait(&status);
80298685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == -1);
80398685dc8SJohn Baldwin 	ATF_REQUIRE(errno == ECHILD);
80498685dc8SJohn Baldwin }
80598685dc8SJohn Baldwin 
80698685dc8SJohn Baldwin /*
80798685dc8SJohn Baldwin  * Verify that a new child process is stopped after a followed fork
80898685dc8SJohn Baldwin  * and that the traced parent sees the exit of the child when the
80998685dc8SJohn Baldwin  * traced parent is detached after the fork.  In this test the parent
81098685dc8SJohn Baldwin  * that forks is not a direct child of the debugger.
81198685dc8SJohn Baldwin  */
81298685dc8SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_parent_detached_unrelated_debugger);
81398685dc8SJohn Baldwin ATF_TC_BODY(ptrace__follow_fork_parent_detached_unrelated_debugger, tc)
81498685dc8SJohn Baldwin {
815479b610dSJohn Baldwin 	pid_t children[2], fpid, wpid;
81698685dc8SJohn Baldwin 	int cpipe[2], status;
81798685dc8SJohn Baldwin 
81898685dc8SJohn Baldwin 	ATF_REQUIRE(pipe(cpipe) == 0);
81998685dc8SJohn Baldwin 	ATF_REQUIRE((fpid = fork()) != -1);
82098685dc8SJohn Baldwin 	if (fpid == 0) {
82198685dc8SJohn Baldwin 		attach_fork_parent(cpipe);
82298685dc8SJohn Baldwin 		follow_fork_parent();
82398685dc8SJohn Baldwin 	}
82498685dc8SJohn Baldwin 
82598685dc8SJohn Baldwin 	/* Parent process. */
82698685dc8SJohn Baldwin 	close(cpipe[1]);
82798685dc8SJohn Baldwin 
82898685dc8SJohn Baldwin 	/* Wait for the direct child to exit. */
82998685dc8SJohn Baldwin 	wpid = waitpid(fpid, &status, 0);
83098685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == fpid);
83198685dc8SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
83298685dc8SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 3);
83398685dc8SJohn Baldwin 
83498685dc8SJohn Baldwin 	/* Read the pid of the fork parent. */
83598685dc8SJohn Baldwin 	ATF_REQUIRE(read(cpipe[0], &children[0], sizeof(children[0])) ==
83698685dc8SJohn Baldwin 	    sizeof(children[0]));
83798685dc8SJohn Baldwin 
83898685dc8SJohn Baldwin 	/* Attach to the fork parent. */
83998685dc8SJohn Baldwin 	attach_child(children[0]);
84098685dc8SJohn Baldwin 
84198685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1);
84298685dc8SJohn Baldwin 
84398685dc8SJohn Baldwin 	/* Continue the fork parent ignoring the SIGSTOP. */
84498685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1);
84598685dc8SJohn Baldwin 
84698685dc8SJohn Baldwin 	/* Signal the fork parent to continue. */
84798685dc8SJohn Baldwin 	close(cpipe[0]);
84898685dc8SJohn Baldwin 
84998685dc8SJohn Baldwin 	children[1] = handle_fork_events(children[0]);
85098685dc8SJohn Baldwin 	ATF_REQUIRE(children[1] > 0);
85198685dc8SJohn Baldwin 
85298685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1);
85398685dc8SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1);
85498685dc8SJohn Baldwin 
85598685dc8SJohn Baldwin 	/*
85698685dc8SJohn Baldwin 	 * Should not see any status from the fork parent now, only
85798685dc8SJohn Baldwin 	 * the child.
85898685dc8SJohn Baldwin 	 */
85998685dc8SJohn Baldwin 	wpid = wait(&status);
86098685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == children[1]);
86198685dc8SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
86298685dc8SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 2);
86398685dc8SJohn Baldwin 
86498685dc8SJohn Baldwin 	wpid = wait(&status);
86598685dc8SJohn Baldwin 	ATF_REQUIRE(wpid == -1);
86698685dc8SJohn Baldwin 	ATF_REQUIRE(errno == ECHILD);
86798685dc8SJohn Baldwin }
86898685dc8SJohn Baldwin 
869368b2b1cSJohn Baldwin /*
870368b2b1cSJohn Baldwin  * Verify that a child process does not see an unrelated debugger as its
871368b2b1cSJohn Baldwin  * parent but sees its original parent process.
872368b2b1cSJohn Baldwin  */
873368b2b1cSJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__getppid);
874368b2b1cSJohn Baldwin ATF_TC_BODY(ptrace__getppid, tc)
875368b2b1cSJohn Baldwin {
876368b2b1cSJohn Baldwin 	pid_t child, debugger, ppid, wpid;
877368b2b1cSJohn Baldwin 	int cpipe[2], dpipe[2], status;
878368b2b1cSJohn Baldwin 	char c;
879368b2b1cSJohn Baldwin 
880368b2b1cSJohn Baldwin 	ATF_REQUIRE(pipe(cpipe) == 0);
881368b2b1cSJohn Baldwin 	ATF_REQUIRE((child = fork()) != -1);
882368b2b1cSJohn Baldwin 
883368b2b1cSJohn Baldwin 	if (child == 0) {
884368b2b1cSJohn Baldwin 		/* Child process. */
885368b2b1cSJohn Baldwin 		close(cpipe[0]);
886368b2b1cSJohn Baldwin 
887368b2b1cSJohn Baldwin 		/* Wait for parent to be ready. */
888368b2b1cSJohn Baldwin 		CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c));
889368b2b1cSJohn Baldwin 
890368b2b1cSJohn Baldwin 		/* Report the parent PID to the parent. */
891368b2b1cSJohn Baldwin 		ppid = getppid();
892368b2b1cSJohn Baldwin 		CHILD_REQUIRE(write(cpipe[1], &ppid, sizeof(ppid)) ==
893368b2b1cSJohn Baldwin 		    sizeof(ppid));
894368b2b1cSJohn Baldwin 
895368b2b1cSJohn Baldwin 		_exit(1);
896368b2b1cSJohn Baldwin 	}
897368b2b1cSJohn Baldwin 	close(cpipe[1]);
898368b2b1cSJohn Baldwin 
899368b2b1cSJohn Baldwin 	ATF_REQUIRE(pipe(dpipe) == 0);
900368b2b1cSJohn Baldwin 	ATF_REQUIRE((debugger = fork()) != -1);
901368b2b1cSJohn Baldwin 
902368b2b1cSJohn Baldwin 	if (debugger == 0) {
903368b2b1cSJohn Baldwin 		/* Debugger process. */
904368b2b1cSJohn Baldwin 		close(dpipe[0]);
905368b2b1cSJohn Baldwin 
906368b2b1cSJohn Baldwin 		CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1);
907368b2b1cSJohn Baldwin 
908368b2b1cSJohn Baldwin 		wpid = waitpid(child, &status, 0);
909368b2b1cSJohn Baldwin 		CHILD_REQUIRE(wpid == child);
910368b2b1cSJohn Baldwin 		CHILD_REQUIRE(WIFSTOPPED(status));
911368b2b1cSJohn Baldwin 		CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP);
912368b2b1cSJohn Baldwin 
913368b2b1cSJohn Baldwin 		CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
914368b2b1cSJohn Baldwin 
915368b2b1cSJohn Baldwin 		/* Signal parent that debugger is attached. */
916368b2b1cSJohn Baldwin 		CHILD_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c));
917368b2b1cSJohn Baldwin 
918368b2b1cSJohn Baldwin 		/* Wait for traced child to exit. */
919368b2b1cSJohn Baldwin 		wpid = waitpid(child, &status, 0);
920368b2b1cSJohn Baldwin 		CHILD_REQUIRE(wpid == child);
921368b2b1cSJohn Baldwin 		CHILD_REQUIRE(WIFEXITED(status));
922368b2b1cSJohn Baldwin 		CHILD_REQUIRE(WEXITSTATUS(status) == 1);
923368b2b1cSJohn Baldwin 
924368b2b1cSJohn Baldwin 		_exit(0);
925368b2b1cSJohn Baldwin 	}
926368b2b1cSJohn Baldwin 	close(dpipe[1]);
927368b2b1cSJohn Baldwin 
928368b2b1cSJohn Baldwin 	/* Parent process. */
929368b2b1cSJohn Baldwin 
930368b2b1cSJohn Baldwin 	/* Wait for the debugger to attach to the child. */
931368b2b1cSJohn Baldwin 	ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c));
932368b2b1cSJohn Baldwin 
933368b2b1cSJohn Baldwin 	/* Release the child. */
934368b2b1cSJohn Baldwin 	ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c));
935368b2b1cSJohn Baldwin 
936368b2b1cSJohn Baldwin 	/* Read the parent PID from the child. */
937368b2b1cSJohn Baldwin 	ATF_REQUIRE(read(cpipe[0], &ppid, sizeof(ppid)) == sizeof(ppid));
938368b2b1cSJohn Baldwin 	close(cpipe[0]);
939368b2b1cSJohn Baldwin 
940368b2b1cSJohn Baldwin 	ATF_REQUIRE(ppid == getpid());
941368b2b1cSJohn Baldwin 
942368b2b1cSJohn Baldwin 	/* Wait for the debugger. */
943368b2b1cSJohn Baldwin 	wpid = waitpid(debugger, &status, 0);
944368b2b1cSJohn Baldwin 	ATF_REQUIRE(wpid == debugger);
945368b2b1cSJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
946368b2b1cSJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 0);
947368b2b1cSJohn Baldwin 
948368b2b1cSJohn Baldwin 	/* The child process should now be ready. */
949368b2b1cSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
950368b2b1cSJohn Baldwin 	ATF_REQUIRE(wpid == child);
951368b2b1cSJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
952368b2b1cSJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
953368b2b1cSJohn Baldwin }
954368b2b1cSJohn Baldwin 
955c209e3e2SJohn Baldwin ATF_TP_ADD_TCS(tp)
956c209e3e2SJohn Baldwin {
957c209e3e2SJohn Baldwin 
958c209e3e2SJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_trace_me);
959c209e3e2SJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_attach);
96057c74f5bSJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_child_debugger);
96157c74f5bSJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_unrelated_debugger);
96298685dc8SJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__follow_fork_both_attached);
96398685dc8SJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__follow_fork_child_detached);
96498685dc8SJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__follow_fork_parent_detached);
96598685dc8SJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__follow_fork_both_attached_unrelated_debugger);
96698685dc8SJohn Baldwin 	ATF_TP_ADD_TC(tp,
96798685dc8SJohn Baldwin 	    ptrace__follow_fork_child_detached_unrelated_debugger);
96898685dc8SJohn Baldwin 	ATF_TP_ADD_TC(tp,
96998685dc8SJohn Baldwin 	    ptrace__follow_fork_parent_detached_unrelated_debugger);
970368b2b1cSJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__getppid);
971c209e3e2SJohn Baldwin 
972c209e3e2SJohn Baldwin 	return (atf_no_error());
973c209e3e2SJohn Baldwin }
974