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