xref: /freebsd/tests/sys/kern/ptrace_test.c (revision eddb85c663040c345d1d4e006665239080df21f6)
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>
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 
13857c74f5bSJohn Baldwin /*
13957c74f5bSJohn Baldwin  * Verify that a parent process "sees" the exit of a debugged process only
14057c74f5bSJohn Baldwin  * after the debugger has seen it.
14157c74f5bSJohn Baldwin  */
14257c74f5bSJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_child_debugger);
14357c74f5bSJohn Baldwin ATF_TC_BODY(ptrace__parent_sees_exit_after_child_debugger, tc)
14457c74f5bSJohn Baldwin {
14557c74f5bSJohn Baldwin 	pid_t child, debugger, wpid;
14657c74f5bSJohn Baldwin 	int cpipe[2], dpipe[2], status;
14757c74f5bSJohn Baldwin 	char c;
14857c74f5bSJohn Baldwin 
14957c74f5bSJohn Baldwin 	ATF_REQUIRE(pipe(cpipe) == 0);
15057c74f5bSJohn Baldwin 	ATF_REQUIRE((child = fork()) != -1);
15157c74f5bSJohn Baldwin 
15257c74f5bSJohn Baldwin 	if (child == 0) {
15357c74f5bSJohn Baldwin 		/* Child process. */
15457c74f5bSJohn Baldwin 		close(cpipe[0]);
15557c74f5bSJohn Baldwin 
15657c74f5bSJohn Baldwin 		/* Wait for parent to be ready. */
15757c74f5bSJohn Baldwin 		ATF_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c));
15857c74f5bSJohn Baldwin 
15957c74f5bSJohn Baldwin 		exit(1);
16057c74f5bSJohn Baldwin 	}
16157c74f5bSJohn Baldwin 	close(cpipe[1]);
16257c74f5bSJohn Baldwin 
16357c74f5bSJohn Baldwin 	ATF_REQUIRE(pipe(dpipe) == 0);
16457c74f5bSJohn Baldwin 	ATF_REQUIRE((debugger = fork()) != -1);
16557c74f5bSJohn Baldwin 
16657c74f5bSJohn Baldwin 	if (debugger == 0) {
16757c74f5bSJohn Baldwin 		/* Debugger process. */
16857c74f5bSJohn Baldwin 		close(dpipe[0]);
16957c74f5bSJohn Baldwin 
17057c74f5bSJohn Baldwin 		ATF_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1);
17157c74f5bSJohn Baldwin 
17257c74f5bSJohn Baldwin 		wpid = waitpid(child, &status, 0);
17357c74f5bSJohn Baldwin 		ATF_REQUIRE(wpid == child);
17457c74f5bSJohn Baldwin 		ATF_REQUIRE(WIFSTOPPED(status));
17557c74f5bSJohn Baldwin 		ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
17657c74f5bSJohn Baldwin 
17757c74f5bSJohn Baldwin 		ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
17857c74f5bSJohn Baldwin 
17957c74f5bSJohn Baldwin 		/* Signal parent that debugger is attached. */
18057c74f5bSJohn Baldwin 		ATF_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c));
18157c74f5bSJohn Baldwin 
18257c74f5bSJohn Baldwin 		/* Wait for parent's failed wait. */
18357c74f5bSJohn Baldwin 		ATF_REQUIRE(read(dpipe[1], &c, sizeof(c)) == 0);
18457c74f5bSJohn Baldwin 
18557c74f5bSJohn Baldwin 		wpid = waitpid(child, &status, 0);
18657c74f5bSJohn Baldwin 		ATF_REQUIRE(wpid == child);
18757c74f5bSJohn Baldwin 		ATF_REQUIRE(WIFEXITED(status));
18857c74f5bSJohn Baldwin 		ATF_REQUIRE(WEXITSTATUS(status) == 1);
18957c74f5bSJohn Baldwin 
19057c74f5bSJohn Baldwin 		exit(0);
19157c74f5bSJohn Baldwin 	}
19257c74f5bSJohn Baldwin 	close(dpipe[1]);
19357c74f5bSJohn Baldwin 
19457c74f5bSJohn Baldwin 	/* Parent process. */
19557c74f5bSJohn Baldwin 
19657c74f5bSJohn Baldwin 	/* Wait for the debugger to attach to the child. */
19757c74f5bSJohn Baldwin 	ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c));
19857c74f5bSJohn Baldwin 
19957c74f5bSJohn Baldwin 	/* Release the child. */
20057c74f5bSJohn Baldwin 	ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c));
20157c74f5bSJohn Baldwin 	ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0);
20257c74f5bSJohn Baldwin 	close(cpipe[0]);
20357c74f5bSJohn Baldwin 
20457c74f5bSJohn Baldwin 	/*
20557c74f5bSJohn Baldwin 	 * Wait for the child to exit.  This is kind of gross, but
20657c74f5bSJohn Baldwin 	 * there is not a better way.
20757c74f5bSJohn Baldwin 	 */
20857c74f5bSJohn Baldwin 	for (;;) {
20957c74f5bSJohn Baldwin 		struct kinfo_proc kp;
21057c74f5bSJohn Baldwin 		size_t len;
21157c74f5bSJohn Baldwin 		int mib[4];
21257c74f5bSJohn Baldwin 
21357c74f5bSJohn Baldwin 		mib[0] = CTL_KERN;
21457c74f5bSJohn Baldwin 		mib[1] = KERN_PROC;
21557c74f5bSJohn Baldwin 		mib[2] = KERN_PROC_PID;
21657c74f5bSJohn Baldwin 		mib[3] = child;
21757c74f5bSJohn Baldwin 		len = sizeof(kp);
21857c74f5bSJohn Baldwin 		if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) {
21957c74f5bSJohn Baldwin 			/* The KERN_PROC_PID sysctl fails for zombies. */
22057c74f5bSJohn Baldwin 			ATF_REQUIRE(errno == ESRCH);
22157c74f5bSJohn Baldwin 			break;
22257c74f5bSJohn Baldwin 		}
22357c74f5bSJohn Baldwin 		usleep(5000);
22457c74f5bSJohn Baldwin 	}
22557c74f5bSJohn Baldwin 
22657c74f5bSJohn Baldwin 	/*
2272f021998SJohn Baldwin 	 * This wait should return a pid of 0 to indicate no status to
2282f021998SJohn Baldwin 	 * report.  The parent should see the child as non-exited
2292f021998SJohn Baldwin 	 * until the debugger sees the exit.
23057c74f5bSJohn Baldwin 	 */
23157c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
23257c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == 0);
23357c74f5bSJohn Baldwin 
23457c74f5bSJohn Baldwin 	/* Signal the debugger to wait for the child. */
23557c74f5bSJohn Baldwin 	close(dpipe[0]);
23657c74f5bSJohn Baldwin 
23757c74f5bSJohn Baldwin 	/* Wait for the debugger. */
23857c74f5bSJohn Baldwin 	wpid = waitpid(debugger, &status, 0);
23957c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == debugger);
24057c74f5bSJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
24157c74f5bSJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 0);
24257c74f5bSJohn Baldwin 
24357c74f5bSJohn Baldwin 	/* The child process should now be ready. */
24457c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
24557c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == child);
24657c74f5bSJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
24757c74f5bSJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
24857c74f5bSJohn Baldwin }
24957c74f5bSJohn Baldwin 
25057c74f5bSJohn Baldwin /*
25157c74f5bSJohn Baldwin  * Verify that a parent process "sees" the exit of a debugged process
25257c74f5bSJohn Baldwin  * only after a non-direct-child debugger has seen it.  In particular,
25357c74f5bSJohn Baldwin  * various wait() calls in the parent must avoid failing with ESRCH by
25457c74f5bSJohn Baldwin  * checking the parent's orphan list for the debugee.
25557c74f5bSJohn Baldwin  */
25657c74f5bSJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_unrelated_debugger);
25757c74f5bSJohn Baldwin ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc)
25857c74f5bSJohn Baldwin {
25957c74f5bSJohn Baldwin 	pid_t child, debugger, fpid, wpid;
26057c74f5bSJohn Baldwin 	int cpipe[2], dpipe[2], status;
26157c74f5bSJohn Baldwin 	char c;
26257c74f5bSJohn Baldwin 
26357c74f5bSJohn Baldwin 	ATF_REQUIRE(pipe(cpipe) == 0);
26457c74f5bSJohn Baldwin 	ATF_REQUIRE((child = fork()) != -1);
26557c74f5bSJohn Baldwin 
26657c74f5bSJohn Baldwin 	if (child == 0) {
26757c74f5bSJohn Baldwin 		/* Child process. */
26857c74f5bSJohn Baldwin 		close(cpipe[0]);
26957c74f5bSJohn Baldwin 
27057c74f5bSJohn Baldwin 		/* Wait for parent to be ready. */
27157c74f5bSJohn Baldwin 		ATF_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c));
27257c74f5bSJohn Baldwin 
27357c74f5bSJohn Baldwin 		exit(1);
27457c74f5bSJohn Baldwin 	}
27557c74f5bSJohn Baldwin 	close(cpipe[1]);
27657c74f5bSJohn Baldwin 
27757c74f5bSJohn Baldwin 	ATF_REQUIRE(pipe(dpipe) == 0);
27857c74f5bSJohn Baldwin 	ATF_REQUIRE((debugger = fork()) != -1);
27957c74f5bSJohn Baldwin 
28057c74f5bSJohn Baldwin 	if (debugger == 0) {
28157c74f5bSJohn Baldwin 		/* Debugger parent. */
28257c74f5bSJohn Baldwin 
28357c74f5bSJohn Baldwin 		/*
28457c74f5bSJohn Baldwin 		 * Fork again and drop the debugger parent so that the
28557c74f5bSJohn Baldwin 		 * debugger is not a child of the main parent.
28657c74f5bSJohn Baldwin 		 */
28757c74f5bSJohn Baldwin 		ATF_REQUIRE((fpid = fork()) != -1);
28857c74f5bSJohn Baldwin 		if (fpid != 0)
28957c74f5bSJohn Baldwin 			exit(2);
29057c74f5bSJohn Baldwin 
29157c74f5bSJohn Baldwin 		/* Debugger process. */
29257c74f5bSJohn Baldwin 		close(dpipe[0]);
29357c74f5bSJohn Baldwin 
29457c74f5bSJohn Baldwin 		ATF_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1);
29557c74f5bSJohn Baldwin 
29657c74f5bSJohn Baldwin 		wpid = waitpid(child, &status, 0);
29757c74f5bSJohn Baldwin 		ATF_REQUIRE(wpid == child);
29857c74f5bSJohn Baldwin 		ATF_REQUIRE(WIFSTOPPED(status));
29957c74f5bSJohn Baldwin 		ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
30057c74f5bSJohn Baldwin 
30157c74f5bSJohn Baldwin 		ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1);
30257c74f5bSJohn Baldwin 
30357c74f5bSJohn Baldwin 		/* Signal parent that debugger is attached. */
30457c74f5bSJohn Baldwin 		ATF_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c));
30557c74f5bSJohn Baldwin 
30657c74f5bSJohn Baldwin 		/* Wait for parent's failed wait. */
307*eddb85c6SJohn Baldwin 		ATF_REQUIRE(read(dpipe[1], &c, sizeof(c)) == sizeof(c));
30857c74f5bSJohn Baldwin 
30957c74f5bSJohn Baldwin 		wpid = waitpid(child, &status, 0);
31057c74f5bSJohn Baldwin 		ATF_REQUIRE(wpid == child);
31157c74f5bSJohn Baldwin 		ATF_REQUIRE(WIFEXITED(status));
31257c74f5bSJohn Baldwin 		ATF_REQUIRE(WEXITSTATUS(status) == 1);
31357c74f5bSJohn Baldwin 
31457c74f5bSJohn Baldwin 		exit(0);
31557c74f5bSJohn Baldwin 	}
316*eddb85c6SJohn Baldwin 	close(dpipe[1]);
31757c74f5bSJohn Baldwin 
31857c74f5bSJohn Baldwin 	/* Parent process. */
31957c74f5bSJohn Baldwin 
32057c74f5bSJohn Baldwin 	/* Wait for the debugger parent process to exit. */
32157c74f5bSJohn Baldwin 	wpid = waitpid(debugger, &status, 0);
32257c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == debugger);
32357c74f5bSJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
32457c74f5bSJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 2);
32557c74f5bSJohn Baldwin 
32657c74f5bSJohn Baldwin 	/* A WNOHANG wait here should see the non-exited child. */
32757c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
32857c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == 0);
32957c74f5bSJohn Baldwin 
33057c74f5bSJohn Baldwin 	/* Wait for the debugger to attach to the child. */
33157c74f5bSJohn Baldwin 	ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c));
33257c74f5bSJohn Baldwin 
33357c74f5bSJohn Baldwin 	/* Release the child. */
33457c74f5bSJohn Baldwin 	ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c));
33557c74f5bSJohn Baldwin 	ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0);
33657c74f5bSJohn Baldwin 	close(cpipe[0]);
33757c74f5bSJohn Baldwin 
33857c74f5bSJohn Baldwin 	/*
33957c74f5bSJohn Baldwin 	 * Wait for the child to exit.  This is kind of gross, but
34057c74f5bSJohn Baldwin 	 * there is not a better way.
34157c74f5bSJohn Baldwin 	 */
34257c74f5bSJohn Baldwin 	for (;;) {
34357c74f5bSJohn Baldwin 		struct kinfo_proc kp;
34457c74f5bSJohn Baldwin 		size_t len;
34557c74f5bSJohn Baldwin 		int mib[4];
34657c74f5bSJohn Baldwin 
34757c74f5bSJohn Baldwin 		mib[0] = CTL_KERN;
34857c74f5bSJohn Baldwin 		mib[1] = KERN_PROC;
34957c74f5bSJohn Baldwin 		mib[2] = KERN_PROC_PID;
35057c74f5bSJohn Baldwin 		mib[3] = child;
35157c74f5bSJohn Baldwin 		len = sizeof(kp);
35257c74f5bSJohn Baldwin 		if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) {
35357c74f5bSJohn Baldwin 			/* The KERN_PROC_PID sysctl fails for zombies. */
35457c74f5bSJohn Baldwin 			ATF_REQUIRE(errno == ESRCH);
35557c74f5bSJohn Baldwin 			break;
35657c74f5bSJohn Baldwin 		}
35757c74f5bSJohn Baldwin 		usleep(5000);
35857c74f5bSJohn Baldwin 	}
35957c74f5bSJohn Baldwin 
36057c74f5bSJohn Baldwin 	/*
3612f021998SJohn Baldwin 	 * This wait should return a pid of 0 to indicate no status to
3622f021998SJohn Baldwin 	 * report.  The parent should see the child as non-exited
3632f021998SJohn Baldwin 	 * until the debugger sees the exit.
36457c74f5bSJohn Baldwin 	 */
36557c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
36657c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == 0);
36757c74f5bSJohn Baldwin 
36857c74f5bSJohn Baldwin 	/* Signal the debugger to wait for the child. */
369*eddb85c6SJohn Baldwin 	ATF_REQUIRE(write(dpipe[0], &c, sizeof(c)) == sizeof(c));
37057c74f5bSJohn Baldwin 
37157c74f5bSJohn Baldwin 	/* Wait for the debugger. */
372*eddb85c6SJohn Baldwin 	ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == 0);
373*eddb85c6SJohn Baldwin 	close(dpipe[0]);
37457c74f5bSJohn Baldwin 
37557c74f5bSJohn Baldwin 	/* The child process should now be ready. */
37657c74f5bSJohn Baldwin 	wpid = waitpid(child, &status, WNOHANG);
37757c74f5bSJohn Baldwin 	ATF_REQUIRE(wpid == child);
37857c74f5bSJohn Baldwin 	ATF_REQUIRE(WIFEXITED(status));
37957c74f5bSJohn Baldwin 	ATF_REQUIRE(WEXITSTATUS(status) == 1);
38057c74f5bSJohn Baldwin }
38157c74f5bSJohn Baldwin 
382c209e3e2SJohn Baldwin ATF_TP_ADD_TCS(tp)
383c209e3e2SJohn Baldwin {
384c209e3e2SJohn Baldwin 
385c209e3e2SJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_trace_me);
386c209e3e2SJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_attach);
38757c74f5bSJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_child_debugger);
38857c74f5bSJohn Baldwin 	ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_unrelated_debugger);
389c209e3e2SJohn Baldwin 
390c209e3e2SJohn Baldwin 	return (atf_no_error());
391c209e3e2SJohn Baldwin }
392