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