xref: /freebsd/tests/sys/kern/ptrace_test.c (revision 57c74f5b64581aa3a7e1369a001a09333e6db8dd)
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>
32*57c74f5bSJohn Baldwin #include <sys/sysctl.h>
33*57c74f5bSJohn Baldwin #include <sys/user.h>
34c209e3e2SJohn Baldwin #include <sys/wait.h>
35c209e3e2SJohn Baldwin #include <errno.h>
36c209e3e2SJohn Baldwin #include <signal.h>
37c209e3e2SJohn Baldwin #include <stdlib.h>
38c209e3e2SJohn Baldwin #include <unistd.h>
39c209e3e2SJohn Baldwin #include <atf-c.h>
40c209e3e2SJohn Baldwin 
41c209e3e2SJohn Baldwin /*
42c209e3e2SJohn Baldwin  * Verify that a parent debugger process "sees" the exit of a debugged
43c209e3e2SJohn Baldwin  * process exactly once when attached via PT_TRACE_ME.
44c209e3e2SJohn Baldwin  */
45c209e3e2SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_trace_me);
46c209e3e2SJohn Baldwin ATF_TC_BODY(ptrace__parent_wait_after_trace_me, tc)
47c209e3e2SJohn Baldwin {
48c209e3e2SJohn Baldwin 	pid_t child, wpid;
49c209e3e2SJohn Baldwin 	int status;
50c209e3e2SJohn Baldwin 
51c209e3e2SJohn Baldwin 	ATF_REQUIRE((child = fork()) != -1);
52c209e3e2SJohn Baldwin 	if (child == 0) {
53c209e3e2SJohn Baldwin 		/* Child process. */
54c209e3e2SJohn Baldwin 		ATF_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
55c209e3e2SJohn Baldwin 
56c209e3e2SJohn Baldwin 		/* Trigger a stop. */
57c209e3e2SJohn Baldwin 		raise(SIGSTOP);
58c209e3e2SJohn Baldwin 
59c209e3e2SJohn Baldwin 		exit(1);
60c209e3e2SJohn Baldwin 	}
61c209e3e2SJohn Baldwin 
62c209e3e2SJohn Baldwin 	/* Parent process. */
63c209e3e2SJohn Baldwin 
64c209e3e2SJohn Baldwin 	/* The first wait() should report the stop from SIGSTOP. */
65c209e3e2SJohn Baldwin 	wpid = waitpid(child, &status, 0);
66c209e3e2SJohn Baldwin 	ATF_REQUIRE(wpid == child);
67c209e3e2SJohn Baldwin 	ATF_REQUIRE(WIFSTOPPED(status));
68c209e3e2SJohn Baldwin 	ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
69c209e3e2SJohn Baldwin 
70c209e3e2SJohn Baldwin 	/* Continue the child ignoring the SIGSTOP. */
71c209e3e2SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
72c209e3e2SJohn Baldwin 
73c209e3e2SJohn Baldwin 	/* The second wait() should report the exit status. */
74c209e3e2SJohn Baldwin 	wpid = waitpid(child, &status, 0);
75c209e3e2SJohn Baldwin 	ATF_REQUIRE(wpid == child);
76c209e3e2SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
77c209e3e2SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
78c209e3e2SJohn Baldwin 
79c209e3e2SJohn Baldwin 	/* The child should no longer exist. */
80c209e3e2SJohn Baldwin 	wpid = waitpid(child, &status, 0);
81c209e3e2SJohn Baldwin 	ATF_REQUIRE(wpid == -1);
82c209e3e2SJohn Baldwin 	ATF_REQUIRE(errno == ECHILD);
83c209e3e2SJohn Baldwin }
84c209e3e2SJohn Baldwin 
85c209e3e2SJohn Baldwin /*
86c209e3e2SJohn Baldwin  * Verify that a parent debugger process "sees" the exit of a debugged
87c209e3e2SJohn Baldwin  * process exactly once when attached via PT_ATTACH.
88c209e3e2SJohn Baldwin  */
89c209e3e2SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_attach);
90c209e3e2SJohn Baldwin ATF_TC_BODY(ptrace__parent_wait_after_attach, tc)
91c209e3e2SJohn Baldwin {
92c209e3e2SJohn Baldwin 	pid_t child, wpid;
93c209e3e2SJohn Baldwin 	int cpipe[2], status;
94c209e3e2SJohn Baldwin 	char c;
95c209e3e2SJohn Baldwin 
96c209e3e2SJohn Baldwin 	ATF_REQUIRE(pipe(cpipe) == 0);
97c209e3e2SJohn Baldwin 	ATF_REQUIRE((child = fork()) != -1);
98c209e3e2SJohn Baldwin 	if (child == 0) {
99c209e3e2SJohn Baldwin 		/* Child process. */
100c209e3e2SJohn Baldwin 		close(cpipe[0]);
101c209e3e2SJohn Baldwin 
102c209e3e2SJohn Baldwin 		/* Wait for the parent to attach. */
103c209e3e2SJohn Baldwin 		ATF_REQUIRE(read(cpipe[1], &c, sizeof(c)) == 0);
104c209e3e2SJohn Baldwin 
105c209e3e2SJohn Baldwin 		exit(1);
106c209e3e2SJohn Baldwin 	}
107c209e3e2SJohn Baldwin 	close(cpipe[1]);
108c209e3e2SJohn Baldwin 
109c209e3e2SJohn Baldwin 	/* Parent process. */
110c209e3e2SJohn Baldwin 
111c209e3e2SJohn Baldwin 	/* Attach to the child process. */
112c209e3e2SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) == 0);
113c209e3e2SJohn Baldwin 
114c209e3e2SJohn Baldwin 	/* The first wait() should report the SIGSTOP from PT_ATTACH. */
115c209e3e2SJohn Baldwin 	wpid = waitpid(child, &status, 0);
116c209e3e2SJohn Baldwin 	ATF_REQUIRE(wpid == child);
117c209e3e2SJohn Baldwin 	ATF_REQUIRE(WIFSTOPPED(status));
118c209e3e2SJohn Baldwin 	ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
119c209e3e2SJohn Baldwin 
120c209e3e2SJohn Baldwin 	/* Continue the child ignoring the SIGSTOP. */
121c209e3e2SJohn Baldwin 	ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
122c209e3e2SJohn Baldwin 
123c209e3e2SJohn Baldwin 	/* Signal the child to exit. */
124c209e3e2SJohn Baldwin 	close(cpipe[0]);
125c209e3e2SJohn Baldwin 
126c209e3e2SJohn Baldwin 	/* The second wait() should report the exit status. */
127c209e3e2SJohn Baldwin 	wpid = waitpid(child, &status, 0);
128c209e3e2SJohn Baldwin 	ATF_REQUIRE(wpid == child);
129c209e3e2SJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
130c209e3e2SJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
131c209e3e2SJohn Baldwin 
132c209e3e2SJohn Baldwin 	/* The child should no longer exist. */
133c209e3e2SJohn Baldwin 	wpid = waitpid(child, &status, 0);
134c209e3e2SJohn Baldwin 	ATF_REQUIRE(wpid == -1);
135c209e3e2SJohn Baldwin 	ATF_REQUIRE(errno == ECHILD);
136c209e3e2SJohn Baldwin }
137c209e3e2SJohn Baldwin 
138*57c74f5bSJohn Baldwin /*
139*57c74f5bSJohn Baldwin  * Verify that a parent process "sees" the exit of a debugged process only
140*57c74f5bSJohn Baldwin  * after the debugger has seen it.
141*57c74f5bSJohn Baldwin  */
142*57c74f5bSJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_child_debugger);
143*57c74f5bSJohn Baldwin ATF_TC_BODY(ptrace__parent_sees_exit_after_child_debugger, tc)
144*57c74f5bSJohn Baldwin {
145*57c74f5bSJohn Baldwin 	pid_t child, debugger, wpid;
146*57c74f5bSJohn Baldwin 	int cpipe[2], dpipe[2], status;
147*57c74f5bSJohn Baldwin 	char c;
148*57c74f5bSJohn Baldwin 
149*57c74f5bSJohn Baldwin 	ATF_REQUIRE(pipe(cpipe) == 0);
150*57c74f5bSJohn Baldwin 	ATF_REQUIRE((child = fork()) != -1);
151*57c74f5bSJohn Baldwin 
152*57c74f5bSJohn Baldwin 	if (child == 0) {
153*57c74f5bSJohn Baldwin 		/* Child process. */
154*57c74f5bSJohn Baldwin 		close(cpipe[0]);
155*57c74f5bSJohn Baldwin 
156*57c74f5bSJohn Baldwin 		/* Wait for parent to be ready. */
157*57c74f5bSJohn Baldwin 		ATF_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c));
158*57c74f5bSJohn Baldwin 
159*57c74f5bSJohn Baldwin 		exit(1);
160*57c74f5bSJohn Baldwin 	}
161*57c74f5bSJohn Baldwin 	close(cpipe[1]);
162*57c74f5bSJohn Baldwin 
163*57c74f5bSJohn Baldwin 	ATF_REQUIRE(pipe(dpipe) == 0);
164*57c74f5bSJohn Baldwin 	ATF_REQUIRE((debugger = fork()) != -1);
165*57c74f5bSJohn Baldwin 
166*57c74f5bSJohn Baldwin 	if (debugger == 0) {
167*57c74f5bSJohn Baldwin 		/* Debugger process. */
168*57c74f5bSJohn Baldwin 		close(dpipe[0]);
169*57c74f5bSJohn Baldwin 
170*57c74f5bSJohn Baldwin 		ATF_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1);
171*57c74f5bSJohn Baldwin 
172*57c74f5bSJohn Baldwin 		wpid = waitpid(child, &status, 0);
173*57c74f5bSJohn Baldwin 		ATF_REQUIRE(wpid == child);
174*57c74f5bSJohn Baldwin 		ATF_REQUIRE(WIFSTOPPED(status));
175*57c74f5bSJohn Baldwin 		ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
176*57c74f5bSJohn Baldwin 
177*57c74f5bSJohn Baldwin 		ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
178*57c74f5bSJohn Baldwin 
179*57c74f5bSJohn Baldwin 		/* Signal parent that debugger is attached. */
180*57c74f5bSJohn Baldwin 		ATF_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c));
181*57c74f5bSJohn Baldwin 
182*57c74f5bSJohn Baldwin 		/* Wait for parent's failed wait. */
183*57c74f5bSJohn Baldwin 		ATF_REQUIRE(read(dpipe[1], &c, sizeof(c)) == 0);
184*57c74f5bSJohn Baldwin 
185*57c74f5bSJohn Baldwin 		wpid = waitpid(child, &status, 0);
186*57c74f5bSJohn Baldwin 		ATF_REQUIRE(wpid == child);
187*57c74f5bSJohn Baldwin 		ATF_REQUIRE(WIFEXITED(status));
188*57c74f5bSJohn Baldwin 		ATF_REQUIRE(WEXITSTATUS(status) == 1);
189*57c74f5bSJohn Baldwin 
190*57c74f5bSJohn Baldwin 		exit(0);
191*57c74f5bSJohn Baldwin 	}
192*57c74f5bSJohn Baldwin 	close(dpipe[1]);
193*57c74f5bSJohn Baldwin 
194*57c74f5bSJohn Baldwin 	/* Parent process. */
195*57c74f5bSJohn Baldwin 
196*57c74f5bSJohn Baldwin 	/* Wait for the debugger to attach to the child. */
197*57c74f5bSJohn Baldwin 	ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c));
198*57c74f5bSJohn Baldwin 
199*57c74f5bSJohn Baldwin 	/* Release the child. */
200*57c74f5bSJohn Baldwin 	ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c));
201*57c74f5bSJohn Baldwin 	ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0);
202*57c74f5bSJohn Baldwin 	close(cpipe[0]);
203*57c74f5bSJohn Baldwin 
204*57c74f5bSJohn Baldwin 	/*
205*57c74f5bSJohn Baldwin 	 * Wait for the child to exit.  This is kind of gross, but
206*57c74f5bSJohn Baldwin 	 * there is not a better way.
207*57c74f5bSJohn Baldwin 	 */
208*57c74f5bSJohn Baldwin 	for (;;) {
209*57c74f5bSJohn Baldwin 		struct kinfo_proc kp;
210*57c74f5bSJohn Baldwin 		size_t len;
211*57c74f5bSJohn Baldwin 		int mib[4];
212*57c74f5bSJohn Baldwin 
213*57c74f5bSJohn Baldwin 		mib[0] = CTL_KERN;
214*57c74f5bSJohn Baldwin 		mib[1] = KERN_PROC;
215*57c74f5bSJohn Baldwin 		mib[2] = KERN_PROC_PID;
216*57c74f5bSJohn Baldwin 		mib[3] = child;
217*57c74f5bSJohn Baldwin 		len = sizeof(kp);
218*57c74f5bSJohn Baldwin 		if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) {
219*57c74f5bSJohn Baldwin 			/* The KERN_PROC_PID sysctl fails for zombies. */
220*57c74f5bSJohn Baldwin 			ATF_REQUIRE(errno == ESRCH);
221*57c74f5bSJohn Baldwin 			break;
222*57c74f5bSJohn Baldwin 		}
223*57c74f5bSJohn Baldwin 		usleep(5000);
224*57c74f5bSJohn Baldwin 	}
225*57c74f5bSJohn Baldwin 
226*57c74f5bSJohn Baldwin 	/*
227*57c74f5bSJohn Baldwin 	 * This wait should return an empty pid.  The parent should
228*57c74f5bSJohn Baldwin 	 * see the child as non-exited until the debugger sees the
229*57c74f5bSJohn Baldwin 	 * exit.
230*57c74f5bSJohn Baldwin 	 */
231*57c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
232*57c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == 0);
233*57c74f5bSJohn Baldwin 
234*57c74f5bSJohn Baldwin 	/* Signal the debugger to wait for the child. */
235*57c74f5bSJohn Baldwin 	close(dpipe[0]);
236*57c74f5bSJohn Baldwin 
237*57c74f5bSJohn Baldwin 	/* Wait for the debugger. */
238*57c74f5bSJohn Baldwin 	wpid = waitpid(debugger, &status, 0);
239*57c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == debugger);
240*57c74f5bSJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
241*57c74f5bSJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 0);
242*57c74f5bSJohn Baldwin 
243*57c74f5bSJohn Baldwin 	/* The child process should now be ready. */
244*57c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
245*57c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == child);
246*57c74f5bSJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
247*57c74f5bSJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
248*57c74f5bSJohn Baldwin }
249*57c74f5bSJohn Baldwin 
250*57c74f5bSJohn Baldwin /*
251*57c74f5bSJohn Baldwin  * Verify that a parent process "sees" the exit of a debugged process
252*57c74f5bSJohn Baldwin  * only after a non-direct-child debugger has seen it.  In particular,
253*57c74f5bSJohn Baldwin  * various wait() calls in the parent must avoid failing with ESRCH by
254*57c74f5bSJohn Baldwin  * checking the parent's orphan list for the debugee.
255*57c74f5bSJohn Baldwin  */
256*57c74f5bSJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_unrelated_debugger);
257*57c74f5bSJohn Baldwin ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc)
258*57c74f5bSJohn Baldwin {
259*57c74f5bSJohn Baldwin 	pid_t child, debugger, fpid, wpid;
260*57c74f5bSJohn Baldwin 	int cpipe[2], dpipe[2], status;
261*57c74f5bSJohn Baldwin 	char c;
262*57c74f5bSJohn Baldwin 
263*57c74f5bSJohn Baldwin 	ATF_REQUIRE(pipe(cpipe) == 0);
264*57c74f5bSJohn Baldwin 	ATF_REQUIRE((child = fork()) != -1);
265*57c74f5bSJohn Baldwin 
266*57c74f5bSJohn Baldwin 	if (child == 0) {
267*57c74f5bSJohn Baldwin 		/* Child process. */
268*57c74f5bSJohn Baldwin 		close(cpipe[0]);
269*57c74f5bSJohn Baldwin 
270*57c74f5bSJohn Baldwin 		/* Wait for parent to be ready. */
271*57c74f5bSJohn Baldwin 		ATF_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c));
272*57c74f5bSJohn Baldwin 
273*57c74f5bSJohn Baldwin 		exit(1);
274*57c74f5bSJohn Baldwin 	}
275*57c74f5bSJohn Baldwin 	close(cpipe[1]);
276*57c74f5bSJohn Baldwin 
277*57c74f5bSJohn Baldwin 	ATF_REQUIRE(pipe(dpipe) == 0);
278*57c74f5bSJohn Baldwin 	ATF_REQUIRE((debugger = fork()) != -1);
279*57c74f5bSJohn Baldwin 
280*57c74f5bSJohn Baldwin 	if (debugger == 0) {
281*57c74f5bSJohn Baldwin 		/* Debugger parent. */
282*57c74f5bSJohn Baldwin 
283*57c74f5bSJohn Baldwin 		/*
284*57c74f5bSJohn Baldwin 		 * Fork again and drop the debugger parent so that the
285*57c74f5bSJohn Baldwin 		 * debugger is not a child of the main parent.
286*57c74f5bSJohn Baldwin 		 */
287*57c74f5bSJohn Baldwin 		ATF_REQUIRE((fpid = fork()) != -1);
288*57c74f5bSJohn Baldwin 		if (fpid != 0)
289*57c74f5bSJohn Baldwin 			exit(2);
290*57c74f5bSJohn Baldwin 
291*57c74f5bSJohn Baldwin 		/* Debugger process. */
292*57c74f5bSJohn Baldwin 		close(dpipe[0]);
293*57c74f5bSJohn Baldwin 
294*57c74f5bSJohn Baldwin 		ATF_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1);
295*57c74f5bSJohn Baldwin 
296*57c74f5bSJohn Baldwin 		wpid = waitpid(child, &status, 0);
297*57c74f5bSJohn Baldwin 		ATF_REQUIRE(wpid == child);
298*57c74f5bSJohn Baldwin 		ATF_REQUIRE(WIFSTOPPED(status));
299*57c74f5bSJohn Baldwin 		ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
300*57c74f5bSJohn Baldwin 
301*57c74f5bSJohn Baldwin 		ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
302*57c74f5bSJohn Baldwin 
303*57c74f5bSJohn Baldwin 		/* Signal parent that debugger is attached. */
304*57c74f5bSJohn Baldwin 		ATF_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c));
305*57c74f5bSJohn Baldwin 
306*57c74f5bSJohn Baldwin 		/* Wait for parent's failed wait. */
307*57c74f5bSJohn Baldwin 		ATF_REQUIRE(read(dpipe[1], &c, sizeof(c)) == 0);
308*57c74f5bSJohn Baldwin 
309*57c74f5bSJohn Baldwin 		wpid = waitpid(child, &status, 0);
310*57c74f5bSJohn Baldwin 		ATF_REQUIRE(wpid == child);
311*57c74f5bSJohn Baldwin 		ATF_REQUIRE(WIFEXITED(status));
312*57c74f5bSJohn Baldwin 		ATF_REQUIRE(WEXITSTATUS(status) == 1);
313*57c74f5bSJohn Baldwin 
314*57c74f5bSJohn Baldwin 		exit(0);
315*57c74f5bSJohn Baldwin 	}
316*57c74f5bSJohn Baldwin 
317*57c74f5bSJohn Baldwin 	/* Parent process. */
318*57c74f5bSJohn Baldwin 
319*57c74f5bSJohn Baldwin 	/* Wait for the debugger parent process to exit. */
320*57c74f5bSJohn Baldwin 	wpid = waitpid(debugger, &status, 0);
321*57c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == debugger);
322*57c74f5bSJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
323*57c74f5bSJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 2);
324*57c74f5bSJohn Baldwin 
325*57c74f5bSJohn Baldwin 	/* A WNOHANG wait here should see the non-exited child. */
326*57c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
327*57c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == 0);
328*57c74f5bSJohn Baldwin 
329*57c74f5bSJohn Baldwin 	/* Wait for the debugger to attach to the child. */
330*57c74f5bSJohn Baldwin 	ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c));
331*57c74f5bSJohn Baldwin 
332*57c74f5bSJohn Baldwin 	/* Release the child. */
333*57c74f5bSJohn Baldwin 	ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c));
334*57c74f5bSJohn Baldwin 	ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0);
335*57c74f5bSJohn Baldwin 	close(cpipe[0]);
336*57c74f5bSJohn Baldwin 
337*57c74f5bSJohn Baldwin 	/*
338*57c74f5bSJohn Baldwin 	 * Wait for the child to exit.  This is kind of gross, but
339*57c74f5bSJohn Baldwin 	 * there is not a better way.
340*57c74f5bSJohn Baldwin 	 */
341*57c74f5bSJohn Baldwin 	for (;;) {
342*57c74f5bSJohn Baldwin 		struct kinfo_proc kp;
343*57c74f5bSJohn Baldwin 		size_t len;
344*57c74f5bSJohn Baldwin 		int mib[4];
345*57c74f5bSJohn Baldwin 
346*57c74f5bSJohn Baldwin 		mib[0] = CTL_KERN;
347*57c74f5bSJohn Baldwin 		mib[1] = KERN_PROC;
348*57c74f5bSJohn Baldwin 		mib[2] = KERN_PROC_PID;
349*57c74f5bSJohn Baldwin 		mib[3] = child;
350*57c74f5bSJohn Baldwin 		len = sizeof(kp);
351*57c74f5bSJohn Baldwin 		if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) {
352*57c74f5bSJohn Baldwin 			/* The KERN_PROC_PID sysctl fails for zombies. */
353*57c74f5bSJohn Baldwin 			ATF_REQUIRE(errno == ESRCH);
354*57c74f5bSJohn Baldwin 			break;
355*57c74f5bSJohn Baldwin 		}
356*57c74f5bSJohn Baldwin 		usleep(5000);
357*57c74f5bSJohn Baldwin 	}
358*57c74f5bSJohn Baldwin 
359*57c74f5bSJohn Baldwin 	/*
360*57c74f5bSJohn Baldwin 	 * This wait should return an empty pid.  The parent should
361*57c74f5bSJohn Baldwin 	 * see the child as non-exited until the debugger sees the
362*57c74f5bSJohn Baldwin 	 * exit.
363*57c74f5bSJohn Baldwin 	 */
364*57c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
365*57c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == 0);
366*57c74f5bSJohn Baldwin 
367*57c74f5bSJohn Baldwin 	/* Signal the debugger to wait for the child. */
368*57c74f5bSJohn Baldwin 	close(dpipe[0]);
369*57c74f5bSJohn Baldwin 
370*57c74f5bSJohn Baldwin 	/* Wait for the debugger. */
371*57c74f5bSJohn Baldwin 	ATF_REQUIRE(read(dpipe[1], &c, sizeof(c)) == 0);
372*57c74f5bSJohn Baldwin 
373*57c74f5bSJohn Baldwin 	/* The child process should now be ready. */
374*57c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
375*57c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == child);
376*57c74f5bSJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
377*57c74f5bSJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
378*57c74f5bSJohn Baldwin }
379*57c74f5bSJohn Baldwin 
380c209e3e2SJohn Baldwin ATF_TP_ADD_TCS(tp)
381c209e3e2SJohn Baldwin {
382c209e3e2SJohn Baldwin 
383c209e3e2SJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_trace_me);
384c209e3e2SJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_attach);
385*57c74f5bSJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_child_debugger);
386*57c74f5bSJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_unrelated_debugger);
387c209e3e2SJohn Baldwin 
388c209e3e2SJohn Baldwin 	return (atf_no_error());
389c209e3e2SJohn Baldwin }
390