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> 37*dfa8ba12SJohn Baldwin #include <stdio.h> 38c209e3e2SJohn Baldwin #include <stdlib.h> 39c209e3e2SJohn Baldwin #include <unistd.h> 40c209e3e2SJohn Baldwin #include <atf-c.h> 41c209e3e2SJohn Baldwin 42c209e3e2SJohn Baldwin /* 43*dfa8ba12SJohn Baldwin * A variant of ATF_REQUIRE that is suitable for use in child 44*dfa8ba12SJohn Baldwin * processes. This only works if the parent process is tripped up by 45*dfa8ba12SJohn Baldwin * the early exit and fails some requirement itself. 46*dfa8ba12SJohn Baldwin */ 47*dfa8ba12SJohn Baldwin #define CHILD_REQUIRE(exp) do { \ 48*dfa8ba12SJohn Baldwin if (!(exp)) \ 49*dfa8ba12SJohn Baldwin child_fail_require(__FILE__, __LINE__, \ 50*dfa8ba12SJohn Baldwin #exp " not met"); \ 51*dfa8ba12SJohn Baldwin } while (0) 52*dfa8ba12SJohn Baldwin 53*dfa8ba12SJohn Baldwin static void __dead2 54*dfa8ba12SJohn Baldwin child_fail_require(const char *file, int line, const char *str) 55*dfa8ba12SJohn Baldwin { 56*dfa8ba12SJohn Baldwin char buf[128]; 57*dfa8ba12SJohn Baldwin 58*dfa8ba12SJohn Baldwin snprintf(buf, sizeof(buf), "%s:%d: %s\n", file, line, str); 59*dfa8ba12SJohn Baldwin write(2, buf, strlen(buf)); 60*dfa8ba12SJohn Baldwin _exit(32); 61*dfa8ba12SJohn Baldwin } 62*dfa8ba12SJohn Baldwin 63*dfa8ba12SJohn Baldwin /* 64c209e3e2SJohn Baldwin * Verify that a parent debugger process "sees" the exit of a debugged 65c209e3e2SJohn Baldwin * process exactly once when attached via PT_TRACE_ME. 66c209e3e2SJohn Baldwin */ 67c209e3e2SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_trace_me); 68c209e3e2SJohn Baldwin ATF_TC_BODY(ptrace__parent_wait_after_trace_me, tc) 69c209e3e2SJohn Baldwin { 70c209e3e2SJohn Baldwin pid_t child, wpid; 71c209e3e2SJohn Baldwin int status; 72c209e3e2SJohn Baldwin 73c209e3e2SJohn Baldwin ATF_REQUIRE((child = fork()) != -1); 74c209e3e2SJohn Baldwin if (child == 0) { 75c209e3e2SJohn Baldwin /* Child process. */ 76*dfa8ba12SJohn Baldwin CHILD_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); 77c209e3e2SJohn Baldwin 78c209e3e2SJohn Baldwin /* Trigger a stop. */ 79c209e3e2SJohn Baldwin raise(SIGSTOP); 80c209e3e2SJohn Baldwin 81c209e3e2SJohn Baldwin exit(1); 82c209e3e2SJohn Baldwin } 83c209e3e2SJohn Baldwin 84c209e3e2SJohn Baldwin /* Parent process. */ 85c209e3e2SJohn Baldwin 86c209e3e2SJohn Baldwin /* The first wait() should report the stop from SIGSTOP. */ 87c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 88c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == child); 89c209e3e2SJohn Baldwin ATF_REQUIRE(WIFSTOPPED(status)); 90c209e3e2SJohn Baldwin ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); 91c209e3e2SJohn Baldwin 92c209e3e2SJohn Baldwin /* Continue the child ignoring the SIGSTOP. */ 93c209e3e2SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); 94c209e3e2SJohn Baldwin 95c209e3e2SJohn Baldwin /* The second wait() should report the exit status. */ 96c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 97c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == child); 98c209e3e2SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 99c209e3e2SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 100c209e3e2SJohn Baldwin 101c209e3e2SJohn Baldwin /* The child should no longer exist. */ 102c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 103c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == -1); 104c209e3e2SJohn Baldwin ATF_REQUIRE(errno == ECHILD); 105c209e3e2SJohn Baldwin } 106c209e3e2SJohn Baldwin 107c209e3e2SJohn Baldwin /* 108c209e3e2SJohn Baldwin * Verify that a parent debugger process "sees" the exit of a debugged 109c209e3e2SJohn Baldwin * process exactly once when attached via PT_ATTACH. 110c209e3e2SJohn Baldwin */ 111c209e3e2SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_attach); 112c209e3e2SJohn Baldwin ATF_TC_BODY(ptrace__parent_wait_after_attach, tc) 113c209e3e2SJohn Baldwin { 114c209e3e2SJohn Baldwin pid_t child, wpid; 115c209e3e2SJohn Baldwin int cpipe[2], status; 116c209e3e2SJohn Baldwin char c; 117c209e3e2SJohn Baldwin 118c209e3e2SJohn Baldwin ATF_REQUIRE(pipe(cpipe) == 0); 119c209e3e2SJohn Baldwin ATF_REQUIRE((child = fork()) != -1); 120c209e3e2SJohn Baldwin if (child == 0) { 121c209e3e2SJohn Baldwin /* Child process. */ 122c209e3e2SJohn Baldwin close(cpipe[0]); 123c209e3e2SJohn Baldwin 124c209e3e2SJohn Baldwin /* Wait for the parent to attach. */ 125*dfa8ba12SJohn Baldwin CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == 0); 126c209e3e2SJohn Baldwin 127c209e3e2SJohn Baldwin exit(1); 128c209e3e2SJohn Baldwin } 129c209e3e2SJohn Baldwin close(cpipe[1]); 130c209e3e2SJohn Baldwin 131c209e3e2SJohn Baldwin /* Parent process. */ 132c209e3e2SJohn Baldwin 133c209e3e2SJohn Baldwin /* Attach to the child process. */ 134c209e3e2SJohn Baldwin ATF_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) == 0); 135c209e3e2SJohn Baldwin 136c209e3e2SJohn Baldwin /* The first wait() should report the SIGSTOP from PT_ATTACH. */ 137c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 138c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == child); 139c209e3e2SJohn Baldwin ATF_REQUIRE(WIFSTOPPED(status)); 140c209e3e2SJohn Baldwin ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); 141c209e3e2SJohn Baldwin 142c209e3e2SJohn Baldwin /* Continue the child ignoring the SIGSTOP. */ 143c209e3e2SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); 144c209e3e2SJohn Baldwin 145c209e3e2SJohn Baldwin /* Signal the child to exit. */ 146c209e3e2SJohn Baldwin close(cpipe[0]); 147c209e3e2SJohn Baldwin 148c209e3e2SJohn Baldwin /* The second wait() should report the exit status. */ 149c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 150c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == child); 151c209e3e2SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 152c209e3e2SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 153c209e3e2SJohn Baldwin 154c209e3e2SJohn Baldwin /* The child should no longer exist. */ 155c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 156c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == -1); 157c209e3e2SJohn Baldwin ATF_REQUIRE(errno == ECHILD); 158c209e3e2SJohn Baldwin } 159c209e3e2SJohn Baldwin 16057c74f5bSJohn Baldwin /* 16157c74f5bSJohn Baldwin * Verify that a parent process "sees" the exit of a debugged process only 16257c74f5bSJohn Baldwin * after the debugger has seen it. 16357c74f5bSJohn Baldwin */ 16457c74f5bSJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_child_debugger); 16557c74f5bSJohn Baldwin ATF_TC_BODY(ptrace__parent_sees_exit_after_child_debugger, tc) 16657c74f5bSJohn Baldwin { 16757c74f5bSJohn Baldwin pid_t child, debugger, wpid; 16857c74f5bSJohn Baldwin int cpipe[2], dpipe[2], status; 16957c74f5bSJohn Baldwin char c; 17057c74f5bSJohn Baldwin 17157c74f5bSJohn Baldwin ATF_REQUIRE(pipe(cpipe) == 0); 17257c74f5bSJohn Baldwin ATF_REQUIRE((child = fork()) != -1); 17357c74f5bSJohn Baldwin 17457c74f5bSJohn Baldwin if (child == 0) { 17557c74f5bSJohn Baldwin /* Child process. */ 17657c74f5bSJohn Baldwin close(cpipe[0]); 17757c74f5bSJohn Baldwin 17857c74f5bSJohn Baldwin /* Wait for parent to be ready. */ 179*dfa8ba12SJohn Baldwin CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c)); 18057c74f5bSJohn Baldwin 18157c74f5bSJohn Baldwin exit(1); 18257c74f5bSJohn Baldwin } 18357c74f5bSJohn Baldwin close(cpipe[1]); 18457c74f5bSJohn Baldwin 18557c74f5bSJohn Baldwin ATF_REQUIRE(pipe(dpipe) == 0); 18657c74f5bSJohn Baldwin ATF_REQUIRE((debugger = fork()) != -1); 18757c74f5bSJohn Baldwin 18857c74f5bSJohn Baldwin if (debugger == 0) { 18957c74f5bSJohn Baldwin /* Debugger process. */ 19057c74f5bSJohn Baldwin close(dpipe[0]); 19157c74f5bSJohn Baldwin 192*dfa8ba12SJohn Baldwin CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1); 19357c74f5bSJohn Baldwin 19457c74f5bSJohn Baldwin wpid = waitpid(child, &status, 0); 195*dfa8ba12SJohn Baldwin CHILD_REQUIRE(wpid == child); 196*dfa8ba12SJohn Baldwin CHILD_REQUIRE(WIFSTOPPED(status)); 197*dfa8ba12SJohn Baldwin CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP); 19857c74f5bSJohn Baldwin 199*dfa8ba12SJohn Baldwin CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); 20057c74f5bSJohn Baldwin 20157c74f5bSJohn Baldwin /* Signal parent that debugger is attached. */ 202*dfa8ba12SJohn Baldwin CHILD_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c)); 20357c74f5bSJohn Baldwin 20457c74f5bSJohn Baldwin /* Wait for parent's failed wait. */ 205*dfa8ba12SJohn Baldwin CHILD_REQUIRE(read(dpipe[1], &c, sizeof(c)) == 0); 20657c74f5bSJohn Baldwin 20757c74f5bSJohn Baldwin wpid = waitpid(child, &status, 0); 208*dfa8ba12SJohn Baldwin CHILD_REQUIRE(wpid == child); 209*dfa8ba12SJohn Baldwin CHILD_REQUIRE(WIFEXITED(status)); 210*dfa8ba12SJohn Baldwin CHILD_REQUIRE(WEXITSTATUS(status) == 1); 21157c74f5bSJohn Baldwin 21257c74f5bSJohn Baldwin exit(0); 21357c74f5bSJohn Baldwin } 21457c74f5bSJohn Baldwin close(dpipe[1]); 21557c74f5bSJohn Baldwin 21657c74f5bSJohn Baldwin /* Parent process. */ 21757c74f5bSJohn Baldwin 21857c74f5bSJohn Baldwin /* Wait for the debugger to attach to the child. */ 21957c74f5bSJohn Baldwin ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c)); 22057c74f5bSJohn Baldwin 22157c74f5bSJohn Baldwin /* Release the child. */ 22257c74f5bSJohn Baldwin ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c)); 22357c74f5bSJohn Baldwin ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0); 22457c74f5bSJohn Baldwin close(cpipe[0]); 22557c74f5bSJohn Baldwin 22657c74f5bSJohn Baldwin /* 22757c74f5bSJohn Baldwin * Wait for the child to exit. This is kind of gross, but 22857c74f5bSJohn Baldwin * there is not a better way. 22957c74f5bSJohn Baldwin */ 23057c74f5bSJohn Baldwin for (;;) { 23157c74f5bSJohn Baldwin struct kinfo_proc kp; 23257c74f5bSJohn Baldwin size_t len; 23357c74f5bSJohn Baldwin int mib[4]; 23457c74f5bSJohn Baldwin 23557c74f5bSJohn Baldwin mib[0] = CTL_KERN; 23657c74f5bSJohn Baldwin mib[1] = KERN_PROC; 23757c74f5bSJohn Baldwin mib[2] = KERN_PROC_PID; 23857c74f5bSJohn Baldwin mib[3] = child; 23957c74f5bSJohn Baldwin len = sizeof(kp); 24057c74f5bSJohn Baldwin if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) { 24157c74f5bSJohn Baldwin /* The KERN_PROC_PID sysctl fails for zombies. */ 24257c74f5bSJohn Baldwin ATF_REQUIRE(errno == ESRCH); 24357c74f5bSJohn Baldwin break; 24457c74f5bSJohn Baldwin } 24557c74f5bSJohn Baldwin usleep(5000); 24657c74f5bSJohn Baldwin } 24757c74f5bSJohn Baldwin 24857c74f5bSJohn Baldwin /* 2492f021998SJohn Baldwin * This wait should return a pid of 0 to indicate no status to 2502f021998SJohn Baldwin * report. The parent should see the child as non-exited 2512f021998SJohn Baldwin * until the debugger sees the exit. 25257c74f5bSJohn Baldwin */ 25357c74f5bSJohn Baldwin wpid = waitpid(child, &status, WNOHANG); 25457c74f5bSJohn Baldwin ATF_REQUIRE(wpid == 0); 25557c74f5bSJohn Baldwin 25657c74f5bSJohn Baldwin /* Signal the debugger to wait for the child. */ 25757c74f5bSJohn Baldwin close(dpipe[0]); 25857c74f5bSJohn Baldwin 25957c74f5bSJohn Baldwin /* Wait for the debugger. */ 26057c74f5bSJohn Baldwin wpid = waitpid(debugger, &status, 0); 26157c74f5bSJohn Baldwin ATF_REQUIRE(wpid == debugger); 26257c74f5bSJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 26357c74f5bSJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 0); 26457c74f5bSJohn Baldwin 26557c74f5bSJohn Baldwin /* The child process should now be ready. */ 26657c74f5bSJohn Baldwin wpid = waitpid(child, &status, WNOHANG); 26757c74f5bSJohn Baldwin ATF_REQUIRE(wpid == child); 26857c74f5bSJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 26957c74f5bSJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 27057c74f5bSJohn Baldwin } 27157c74f5bSJohn Baldwin 27257c74f5bSJohn Baldwin /* 27357c74f5bSJohn Baldwin * Verify that a parent process "sees" the exit of a debugged process 27457c74f5bSJohn Baldwin * only after a non-direct-child debugger has seen it. In particular, 27557c74f5bSJohn Baldwin * various wait() calls in the parent must avoid failing with ESRCH by 27657c74f5bSJohn Baldwin * checking the parent's orphan list for the debugee. 27757c74f5bSJohn Baldwin */ 27857c74f5bSJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_unrelated_debugger); 27957c74f5bSJohn Baldwin ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc) 28057c74f5bSJohn Baldwin { 28157c74f5bSJohn Baldwin pid_t child, debugger, fpid, wpid; 28257c74f5bSJohn Baldwin int cpipe[2], dpipe[2], status; 28357c74f5bSJohn Baldwin char c; 28457c74f5bSJohn Baldwin 28557c74f5bSJohn Baldwin ATF_REQUIRE(pipe(cpipe) == 0); 28657c74f5bSJohn Baldwin ATF_REQUIRE((child = fork()) != -1); 28757c74f5bSJohn Baldwin 28857c74f5bSJohn Baldwin if (child == 0) { 28957c74f5bSJohn Baldwin /* Child process. */ 29057c74f5bSJohn Baldwin close(cpipe[0]); 29157c74f5bSJohn Baldwin 29257c74f5bSJohn Baldwin /* Wait for parent to be ready. */ 293*dfa8ba12SJohn Baldwin CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c)); 29457c74f5bSJohn Baldwin 29557c74f5bSJohn Baldwin exit(1); 29657c74f5bSJohn Baldwin } 29757c74f5bSJohn Baldwin close(cpipe[1]); 29857c74f5bSJohn Baldwin 29957c74f5bSJohn Baldwin ATF_REQUIRE(pipe(dpipe) == 0); 30057c74f5bSJohn Baldwin ATF_REQUIRE((debugger = fork()) != -1); 30157c74f5bSJohn Baldwin 30257c74f5bSJohn Baldwin if (debugger == 0) { 30357c74f5bSJohn Baldwin /* Debugger parent. */ 30457c74f5bSJohn Baldwin 30557c74f5bSJohn Baldwin /* 30657c74f5bSJohn Baldwin * Fork again and drop the debugger parent so that the 30757c74f5bSJohn Baldwin * debugger is not a child of the main parent. 30857c74f5bSJohn Baldwin */ 309*dfa8ba12SJohn Baldwin CHILD_REQUIRE((fpid = fork()) != -1); 31057c74f5bSJohn Baldwin if (fpid != 0) 31157c74f5bSJohn Baldwin exit(2); 31257c74f5bSJohn Baldwin 31357c74f5bSJohn Baldwin /* Debugger process. */ 31457c74f5bSJohn Baldwin close(dpipe[0]); 31557c74f5bSJohn Baldwin 316*dfa8ba12SJohn Baldwin CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1); 31757c74f5bSJohn Baldwin 31857c74f5bSJohn Baldwin wpid = waitpid(child, &status, 0); 319*dfa8ba12SJohn Baldwin CHILD_REQUIRE(wpid == child); 320*dfa8ba12SJohn Baldwin CHILD_REQUIRE(WIFSTOPPED(status)); 321*dfa8ba12SJohn Baldwin CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP); 32257c74f5bSJohn Baldwin 323*dfa8ba12SJohn Baldwin CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); 32457c74f5bSJohn Baldwin 32557c74f5bSJohn Baldwin /* Signal parent that debugger is attached. */ 326*dfa8ba12SJohn Baldwin CHILD_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c)); 32757c74f5bSJohn Baldwin 32857c74f5bSJohn Baldwin /* Wait for parent's failed wait. */ 329*dfa8ba12SJohn Baldwin CHILD_REQUIRE(read(dpipe[1], &c, sizeof(c)) == sizeof(c)); 33057c74f5bSJohn Baldwin 33157c74f5bSJohn Baldwin wpid = waitpid(child, &status, 0); 332*dfa8ba12SJohn Baldwin CHILD_REQUIRE(wpid == child); 333*dfa8ba12SJohn Baldwin CHILD_REQUIRE(WIFEXITED(status)); 334*dfa8ba12SJohn Baldwin CHILD_REQUIRE(WEXITSTATUS(status) == 1); 33557c74f5bSJohn Baldwin 33657c74f5bSJohn Baldwin exit(0); 33757c74f5bSJohn Baldwin } 338eddb85c6SJohn Baldwin close(dpipe[1]); 33957c74f5bSJohn Baldwin 34057c74f5bSJohn Baldwin /* Parent process. */ 34157c74f5bSJohn Baldwin 34257c74f5bSJohn Baldwin /* Wait for the debugger parent process to exit. */ 34357c74f5bSJohn Baldwin wpid = waitpid(debugger, &status, 0); 34457c74f5bSJohn Baldwin ATF_REQUIRE(wpid == debugger); 34557c74f5bSJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 34657c74f5bSJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 2); 34757c74f5bSJohn Baldwin 34857c74f5bSJohn Baldwin /* A WNOHANG wait here should see the non-exited child. */ 34957c74f5bSJohn Baldwin wpid = waitpid(child, &status, WNOHANG); 35057c74f5bSJohn Baldwin ATF_REQUIRE(wpid == 0); 35157c74f5bSJohn Baldwin 35257c74f5bSJohn Baldwin /* Wait for the debugger to attach to the child. */ 35357c74f5bSJohn Baldwin ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c)); 35457c74f5bSJohn Baldwin 35557c74f5bSJohn Baldwin /* Release the child. */ 35657c74f5bSJohn Baldwin ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c)); 35757c74f5bSJohn Baldwin ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0); 35857c74f5bSJohn Baldwin close(cpipe[0]); 35957c74f5bSJohn Baldwin 36057c74f5bSJohn Baldwin /* 36157c74f5bSJohn Baldwin * Wait for the child to exit. This is kind of gross, but 36257c74f5bSJohn Baldwin * there is not a better way. 36357c74f5bSJohn Baldwin */ 36457c74f5bSJohn Baldwin for (;;) { 36557c74f5bSJohn Baldwin struct kinfo_proc kp; 36657c74f5bSJohn Baldwin size_t len; 36757c74f5bSJohn Baldwin int mib[4]; 36857c74f5bSJohn Baldwin 36957c74f5bSJohn Baldwin mib[0] = CTL_KERN; 37057c74f5bSJohn Baldwin mib[1] = KERN_PROC; 37157c74f5bSJohn Baldwin mib[2] = KERN_PROC_PID; 37257c74f5bSJohn Baldwin mib[3] = child; 37357c74f5bSJohn Baldwin len = sizeof(kp); 37457c74f5bSJohn Baldwin if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) { 37557c74f5bSJohn Baldwin /* The KERN_PROC_PID sysctl fails for zombies. */ 37657c74f5bSJohn Baldwin ATF_REQUIRE(errno == ESRCH); 37757c74f5bSJohn Baldwin break; 37857c74f5bSJohn Baldwin } 37957c74f5bSJohn Baldwin usleep(5000); 38057c74f5bSJohn Baldwin } 38157c74f5bSJohn Baldwin 38257c74f5bSJohn Baldwin /* 3832f021998SJohn Baldwin * This wait should return a pid of 0 to indicate no status to 3842f021998SJohn Baldwin * report. The parent should see the child as non-exited 3852f021998SJohn Baldwin * until the debugger sees the exit. 38657c74f5bSJohn Baldwin */ 38757c74f5bSJohn Baldwin wpid = waitpid(child, &status, WNOHANG); 38857c74f5bSJohn Baldwin ATF_REQUIRE(wpid == 0); 38957c74f5bSJohn Baldwin 39057c74f5bSJohn Baldwin /* Signal the debugger to wait for the child. */ 391eddb85c6SJohn Baldwin ATF_REQUIRE(write(dpipe[0], &c, sizeof(c)) == sizeof(c)); 39257c74f5bSJohn Baldwin 39357c74f5bSJohn Baldwin /* Wait for the debugger. */ 394eddb85c6SJohn Baldwin ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == 0); 395eddb85c6SJohn Baldwin close(dpipe[0]); 39657c74f5bSJohn Baldwin 39757c74f5bSJohn Baldwin /* The child process should now be ready. */ 39857c74f5bSJohn Baldwin wpid = waitpid(child, &status, WNOHANG); 39957c74f5bSJohn Baldwin ATF_REQUIRE(wpid == child); 40057c74f5bSJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 40157c74f5bSJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 40257c74f5bSJohn Baldwin } 40357c74f5bSJohn Baldwin 404c209e3e2SJohn Baldwin ATF_TP_ADD_TCS(tp) 405c209e3e2SJohn Baldwin { 406c209e3e2SJohn Baldwin 407c209e3e2SJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_trace_me); 408c209e3e2SJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_attach); 40957c74f5bSJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_child_debugger); 41057c74f5bSJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_unrelated_debugger); 411c209e3e2SJohn Baldwin 412c209e3e2SJohn Baldwin return (atf_no_error()); 413c209e3e2SJohn Baldwin } 414