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> 37dfa8ba12SJohn Baldwin #include <stdio.h> 38c209e3e2SJohn Baldwin #include <stdlib.h> 39c209e3e2SJohn Baldwin #include <unistd.h> 40c209e3e2SJohn Baldwin #include <atf-c.h> 41c209e3e2SJohn Baldwin 42c209e3e2SJohn Baldwin /* 43dfa8ba12SJohn Baldwin * A variant of ATF_REQUIRE that is suitable for use in child 44dfa8ba12SJohn Baldwin * processes. This only works if the parent process is tripped up by 45dfa8ba12SJohn Baldwin * the early exit and fails some requirement itself. 46dfa8ba12SJohn Baldwin */ 47dfa8ba12SJohn Baldwin #define CHILD_REQUIRE(exp) do { \ 48dfa8ba12SJohn Baldwin if (!(exp)) \ 49dfa8ba12SJohn Baldwin child_fail_require(__FILE__, __LINE__, \ 50dfa8ba12SJohn Baldwin #exp " not met"); \ 51dfa8ba12SJohn Baldwin } while (0) 52dfa8ba12SJohn Baldwin 5398685dc8SJohn Baldwin static __dead2 void 54dfa8ba12SJohn Baldwin child_fail_require(const char *file, int line, const char *str) 55dfa8ba12SJohn Baldwin { 56dfa8ba12SJohn Baldwin char buf[128]; 57dfa8ba12SJohn Baldwin 58dfa8ba12SJohn Baldwin snprintf(buf, sizeof(buf), "%s:%d: %s\n", file, line, str); 59dfa8ba12SJohn Baldwin write(2, buf, strlen(buf)); 60dfa8ba12SJohn Baldwin _exit(32); 61dfa8ba12SJohn Baldwin } 62dfa8ba12SJohn Baldwin 6398685dc8SJohn Baldwin static void 6498685dc8SJohn Baldwin trace_me(void) 6598685dc8SJohn Baldwin { 6698685dc8SJohn Baldwin 6798685dc8SJohn Baldwin /* Attach the parent process as a tracer of this process. */ 6898685dc8SJohn Baldwin CHILD_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); 6998685dc8SJohn Baldwin 7098685dc8SJohn Baldwin /* Trigger a stop. */ 7198685dc8SJohn Baldwin raise(SIGSTOP); 7298685dc8SJohn Baldwin } 7398685dc8SJohn Baldwin 7498685dc8SJohn Baldwin static void 7598685dc8SJohn Baldwin attach_child(pid_t pid) 7698685dc8SJohn Baldwin { 7798685dc8SJohn Baldwin pid_t wpid; 7898685dc8SJohn Baldwin int status; 7998685dc8SJohn Baldwin 8098685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_ATTACH, pid, NULL, 0) == 0); 8198685dc8SJohn Baldwin 8298685dc8SJohn Baldwin wpid = waitpid(pid, &status, 0); 8398685dc8SJohn Baldwin ATF_REQUIRE(wpid == pid); 8498685dc8SJohn Baldwin ATF_REQUIRE(WIFSTOPPED(status)); 8598685dc8SJohn Baldwin ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); 8698685dc8SJohn Baldwin } 8798685dc8SJohn Baldwin 8898685dc8SJohn Baldwin static void 8998685dc8SJohn Baldwin wait_for_zombie(pid_t pid) 9098685dc8SJohn Baldwin { 9198685dc8SJohn Baldwin 9298685dc8SJohn Baldwin /* 9398685dc8SJohn Baldwin * Wait for a process to exit. This is kind of gross, but 9498685dc8SJohn Baldwin * there is not a better way. 9598685dc8SJohn Baldwin */ 9698685dc8SJohn Baldwin for (;;) { 9798685dc8SJohn Baldwin struct kinfo_proc kp; 9898685dc8SJohn Baldwin size_t len; 9998685dc8SJohn Baldwin int mib[4]; 10098685dc8SJohn Baldwin 10198685dc8SJohn Baldwin mib[0] = CTL_KERN; 10298685dc8SJohn Baldwin mib[1] = KERN_PROC; 10398685dc8SJohn Baldwin mib[2] = KERN_PROC_PID; 10498685dc8SJohn Baldwin mib[3] = pid; 10598685dc8SJohn Baldwin len = sizeof(kp); 10698685dc8SJohn Baldwin if (sysctl(mib, nitems(mib), &kp, &len, NULL, 0) == -1) { 10798685dc8SJohn Baldwin /* The KERN_PROC_PID sysctl fails for zombies. */ 10898685dc8SJohn Baldwin ATF_REQUIRE(errno == ESRCH); 10998685dc8SJohn Baldwin break; 11098685dc8SJohn Baldwin } 11198685dc8SJohn Baldwin usleep(5000); 11298685dc8SJohn Baldwin } 11398685dc8SJohn Baldwin } 11498685dc8SJohn Baldwin 115dfa8ba12SJohn Baldwin /* 116c209e3e2SJohn Baldwin * Verify that a parent debugger process "sees" the exit of a debugged 117c209e3e2SJohn Baldwin * process exactly once when attached via PT_TRACE_ME. 118c209e3e2SJohn Baldwin */ 119c209e3e2SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_trace_me); 120c209e3e2SJohn Baldwin ATF_TC_BODY(ptrace__parent_wait_after_trace_me, tc) 121c209e3e2SJohn Baldwin { 122c209e3e2SJohn Baldwin pid_t child, wpid; 123c209e3e2SJohn Baldwin int status; 124c209e3e2SJohn Baldwin 125c209e3e2SJohn Baldwin ATF_REQUIRE((child = fork()) != -1); 126c209e3e2SJohn Baldwin if (child == 0) { 127c209e3e2SJohn Baldwin /* Child process. */ 12898685dc8SJohn Baldwin trace_me(); 129c209e3e2SJohn Baldwin 130*b98cb919SJohn Baldwin _exit(1); 131c209e3e2SJohn Baldwin } 132c209e3e2SJohn Baldwin 133c209e3e2SJohn Baldwin /* Parent process. */ 134c209e3e2SJohn Baldwin 135c209e3e2SJohn Baldwin /* The first wait() should report the stop from SIGSTOP. */ 136c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 137c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == child); 138c209e3e2SJohn Baldwin ATF_REQUIRE(WIFSTOPPED(status)); 139c209e3e2SJohn Baldwin ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); 140c209e3e2SJohn Baldwin 141c209e3e2SJohn Baldwin /* Continue the child ignoring the SIGSTOP. */ 142c209e3e2SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); 143c209e3e2SJohn Baldwin 144c209e3e2SJohn Baldwin /* The second wait() should report the exit status. */ 145c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 146c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == child); 147c209e3e2SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 148c209e3e2SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 149c209e3e2SJohn Baldwin 150c209e3e2SJohn Baldwin /* The child should no longer exist. */ 151c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 152c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == -1); 153c209e3e2SJohn Baldwin ATF_REQUIRE(errno == ECHILD); 154c209e3e2SJohn Baldwin } 155c209e3e2SJohn Baldwin 156c209e3e2SJohn Baldwin /* 157c209e3e2SJohn Baldwin * Verify that a parent debugger process "sees" the exit of a debugged 158c209e3e2SJohn Baldwin * process exactly once when attached via PT_ATTACH. 159c209e3e2SJohn Baldwin */ 160c209e3e2SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_attach); 161c209e3e2SJohn Baldwin ATF_TC_BODY(ptrace__parent_wait_after_attach, tc) 162c209e3e2SJohn Baldwin { 163c209e3e2SJohn Baldwin pid_t child, wpid; 164c209e3e2SJohn Baldwin int cpipe[2], status; 165c209e3e2SJohn Baldwin char c; 166c209e3e2SJohn Baldwin 167c209e3e2SJohn Baldwin ATF_REQUIRE(pipe(cpipe) == 0); 168c209e3e2SJohn Baldwin ATF_REQUIRE((child = fork()) != -1); 169c209e3e2SJohn Baldwin if (child == 0) { 170c209e3e2SJohn Baldwin /* Child process. */ 171c209e3e2SJohn Baldwin close(cpipe[0]); 172c209e3e2SJohn Baldwin 173c209e3e2SJohn Baldwin /* Wait for the parent to attach. */ 174dfa8ba12SJohn Baldwin CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == 0); 175c209e3e2SJohn Baldwin 176*b98cb919SJohn Baldwin _exit(1); 177c209e3e2SJohn Baldwin } 178c209e3e2SJohn Baldwin close(cpipe[1]); 179c209e3e2SJohn Baldwin 180c209e3e2SJohn Baldwin /* Parent process. */ 181c209e3e2SJohn Baldwin 182c209e3e2SJohn Baldwin /* Attach to the child process. */ 18398685dc8SJohn Baldwin attach_child(child); 184c209e3e2SJohn Baldwin 185c209e3e2SJohn Baldwin /* Continue the child ignoring the SIGSTOP. */ 186c209e3e2SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); 187c209e3e2SJohn Baldwin 188c209e3e2SJohn Baldwin /* Signal the child to exit. */ 189c209e3e2SJohn Baldwin close(cpipe[0]); 190c209e3e2SJohn Baldwin 191c209e3e2SJohn Baldwin /* The second wait() should report the exit status. */ 192c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 193c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == child); 194c209e3e2SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 195c209e3e2SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 196c209e3e2SJohn Baldwin 197c209e3e2SJohn Baldwin /* The child should no longer exist. */ 198c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 199c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == -1); 200c209e3e2SJohn Baldwin ATF_REQUIRE(errno == ECHILD); 201c209e3e2SJohn Baldwin } 202c209e3e2SJohn Baldwin 20357c74f5bSJohn Baldwin /* 20457c74f5bSJohn Baldwin * Verify that a parent process "sees" the exit of a debugged process only 20557c74f5bSJohn Baldwin * after the debugger has seen it. 20657c74f5bSJohn Baldwin */ 20757c74f5bSJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_child_debugger); 20857c74f5bSJohn Baldwin ATF_TC_BODY(ptrace__parent_sees_exit_after_child_debugger, tc) 20957c74f5bSJohn Baldwin { 21057c74f5bSJohn Baldwin pid_t child, debugger, wpid; 21157c74f5bSJohn Baldwin int cpipe[2], dpipe[2], status; 21257c74f5bSJohn Baldwin char c; 21357c74f5bSJohn Baldwin 21457c74f5bSJohn Baldwin ATF_REQUIRE(pipe(cpipe) == 0); 21557c74f5bSJohn Baldwin ATF_REQUIRE((child = fork()) != -1); 21657c74f5bSJohn Baldwin 21757c74f5bSJohn Baldwin if (child == 0) { 21857c74f5bSJohn Baldwin /* Child process. */ 21957c74f5bSJohn Baldwin close(cpipe[0]); 22057c74f5bSJohn Baldwin 22157c74f5bSJohn Baldwin /* Wait for parent to be ready. */ 222dfa8ba12SJohn Baldwin CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c)); 22357c74f5bSJohn Baldwin 224*b98cb919SJohn Baldwin _exit(1); 22557c74f5bSJohn Baldwin } 22657c74f5bSJohn Baldwin close(cpipe[1]); 22757c74f5bSJohn Baldwin 22857c74f5bSJohn Baldwin ATF_REQUIRE(pipe(dpipe) == 0); 22957c74f5bSJohn Baldwin ATF_REQUIRE((debugger = fork()) != -1); 23057c74f5bSJohn Baldwin 23157c74f5bSJohn Baldwin if (debugger == 0) { 23257c74f5bSJohn Baldwin /* Debugger process. */ 23357c74f5bSJohn Baldwin close(dpipe[0]); 23457c74f5bSJohn Baldwin 235dfa8ba12SJohn Baldwin CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1); 23657c74f5bSJohn Baldwin 23757c74f5bSJohn Baldwin wpid = waitpid(child, &status, 0); 238dfa8ba12SJohn Baldwin CHILD_REQUIRE(wpid == child); 239dfa8ba12SJohn Baldwin CHILD_REQUIRE(WIFSTOPPED(status)); 240dfa8ba12SJohn Baldwin CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP); 24157c74f5bSJohn Baldwin 242dfa8ba12SJohn Baldwin CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); 24357c74f5bSJohn Baldwin 24457c74f5bSJohn Baldwin /* Signal parent that debugger is attached. */ 245dfa8ba12SJohn Baldwin CHILD_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c)); 24657c74f5bSJohn Baldwin 24757c74f5bSJohn Baldwin /* Wait for parent's failed wait. */ 248dfa8ba12SJohn Baldwin CHILD_REQUIRE(read(dpipe[1], &c, sizeof(c)) == 0); 24957c74f5bSJohn Baldwin 25057c74f5bSJohn Baldwin wpid = waitpid(child, &status, 0); 251dfa8ba12SJohn Baldwin CHILD_REQUIRE(wpid == child); 252dfa8ba12SJohn Baldwin CHILD_REQUIRE(WIFEXITED(status)); 253dfa8ba12SJohn Baldwin CHILD_REQUIRE(WEXITSTATUS(status) == 1); 25457c74f5bSJohn Baldwin 255*b98cb919SJohn Baldwin _exit(0); 25657c74f5bSJohn Baldwin } 25757c74f5bSJohn Baldwin close(dpipe[1]); 25857c74f5bSJohn Baldwin 25957c74f5bSJohn Baldwin /* Parent process. */ 26057c74f5bSJohn Baldwin 26157c74f5bSJohn Baldwin /* Wait for the debugger to attach to the child. */ 26257c74f5bSJohn Baldwin ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c)); 26357c74f5bSJohn Baldwin 26457c74f5bSJohn Baldwin /* Release the child. */ 26557c74f5bSJohn Baldwin ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c)); 26657c74f5bSJohn Baldwin ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0); 26757c74f5bSJohn Baldwin close(cpipe[0]); 26857c74f5bSJohn Baldwin 26998685dc8SJohn Baldwin wait_for_zombie(child); 27057c74f5bSJohn Baldwin 27157c74f5bSJohn Baldwin /* 2722f021998SJohn Baldwin * This wait should return a pid of 0 to indicate no status to 2732f021998SJohn Baldwin * report. The parent should see the child as non-exited 2742f021998SJohn Baldwin * until the debugger sees the exit. 27557c74f5bSJohn Baldwin */ 27657c74f5bSJohn Baldwin wpid = waitpid(child, &status, WNOHANG); 27757c74f5bSJohn Baldwin ATF_REQUIRE(wpid == 0); 27857c74f5bSJohn Baldwin 27957c74f5bSJohn Baldwin /* Signal the debugger to wait for the child. */ 28057c74f5bSJohn Baldwin close(dpipe[0]); 28157c74f5bSJohn Baldwin 28257c74f5bSJohn Baldwin /* Wait for the debugger. */ 28357c74f5bSJohn Baldwin wpid = waitpid(debugger, &status, 0); 28457c74f5bSJohn Baldwin ATF_REQUIRE(wpid == debugger); 28557c74f5bSJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 28657c74f5bSJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 0); 28757c74f5bSJohn Baldwin 28857c74f5bSJohn Baldwin /* The child process should now be ready. */ 28957c74f5bSJohn Baldwin wpid = waitpid(child, &status, WNOHANG); 29057c74f5bSJohn Baldwin ATF_REQUIRE(wpid == child); 29157c74f5bSJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 29257c74f5bSJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 29357c74f5bSJohn Baldwin } 29457c74f5bSJohn Baldwin 29557c74f5bSJohn Baldwin /* 29657c74f5bSJohn Baldwin * Verify that a parent process "sees" the exit of a debugged process 29757c74f5bSJohn Baldwin * only after a non-direct-child debugger has seen it. In particular, 29857c74f5bSJohn Baldwin * various wait() calls in the parent must avoid failing with ESRCH by 29957c74f5bSJohn Baldwin * checking the parent's orphan list for the debugee. 30057c74f5bSJohn Baldwin */ 30157c74f5bSJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_sees_exit_after_unrelated_debugger); 30257c74f5bSJohn Baldwin ATF_TC_BODY(ptrace__parent_sees_exit_after_unrelated_debugger, tc) 30357c74f5bSJohn Baldwin { 30457c74f5bSJohn Baldwin pid_t child, debugger, fpid, wpid; 30557c74f5bSJohn Baldwin int cpipe[2], dpipe[2], status; 30657c74f5bSJohn Baldwin char c; 30757c74f5bSJohn Baldwin 30857c74f5bSJohn Baldwin ATF_REQUIRE(pipe(cpipe) == 0); 30957c74f5bSJohn Baldwin ATF_REQUIRE((child = fork()) != -1); 31057c74f5bSJohn Baldwin 31157c74f5bSJohn Baldwin if (child == 0) { 31257c74f5bSJohn Baldwin /* Child process. */ 31357c74f5bSJohn Baldwin close(cpipe[0]); 31457c74f5bSJohn Baldwin 31557c74f5bSJohn Baldwin /* Wait for parent to be ready. */ 316dfa8ba12SJohn Baldwin CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c)); 31757c74f5bSJohn Baldwin 318*b98cb919SJohn Baldwin _exit(1); 31957c74f5bSJohn Baldwin } 32057c74f5bSJohn Baldwin close(cpipe[1]); 32157c74f5bSJohn Baldwin 32257c74f5bSJohn Baldwin ATF_REQUIRE(pipe(dpipe) == 0); 32357c74f5bSJohn Baldwin ATF_REQUIRE((debugger = fork()) != -1); 32457c74f5bSJohn Baldwin 32557c74f5bSJohn Baldwin if (debugger == 0) { 32657c74f5bSJohn Baldwin /* Debugger parent. */ 32757c74f5bSJohn Baldwin 32857c74f5bSJohn Baldwin /* 32957c74f5bSJohn Baldwin * Fork again and drop the debugger parent so that the 33057c74f5bSJohn Baldwin * debugger is not a child of the main parent. 33157c74f5bSJohn Baldwin */ 332dfa8ba12SJohn Baldwin CHILD_REQUIRE((fpid = fork()) != -1); 33357c74f5bSJohn Baldwin if (fpid != 0) 334*b98cb919SJohn Baldwin _exit(2); 33557c74f5bSJohn Baldwin 33657c74f5bSJohn Baldwin /* Debugger process. */ 33757c74f5bSJohn Baldwin close(dpipe[0]); 33857c74f5bSJohn Baldwin 339dfa8ba12SJohn Baldwin CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1); 34057c74f5bSJohn Baldwin 34157c74f5bSJohn Baldwin wpid = waitpid(child, &status, 0); 342dfa8ba12SJohn Baldwin CHILD_REQUIRE(wpid == child); 343dfa8ba12SJohn Baldwin CHILD_REQUIRE(WIFSTOPPED(status)); 344dfa8ba12SJohn Baldwin CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP); 34557c74f5bSJohn Baldwin 346dfa8ba12SJohn Baldwin CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); 34757c74f5bSJohn Baldwin 34857c74f5bSJohn Baldwin /* Signal parent that debugger is attached. */ 349dfa8ba12SJohn Baldwin CHILD_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c)); 35057c74f5bSJohn Baldwin 35157c74f5bSJohn Baldwin /* Wait for parent's failed wait. */ 352dfa8ba12SJohn Baldwin CHILD_REQUIRE(read(dpipe[1], &c, sizeof(c)) == sizeof(c)); 35357c74f5bSJohn Baldwin 35457c74f5bSJohn Baldwin wpid = waitpid(child, &status, 0); 355dfa8ba12SJohn Baldwin CHILD_REQUIRE(wpid == child); 356dfa8ba12SJohn Baldwin CHILD_REQUIRE(WIFEXITED(status)); 357dfa8ba12SJohn Baldwin CHILD_REQUIRE(WEXITSTATUS(status) == 1); 35857c74f5bSJohn Baldwin 359*b98cb919SJohn Baldwin _exit(0); 36057c74f5bSJohn Baldwin } 361eddb85c6SJohn Baldwin close(dpipe[1]); 36257c74f5bSJohn Baldwin 36357c74f5bSJohn Baldwin /* Parent process. */ 36457c74f5bSJohn Baldwin 36557c74f5bSJohn Baldwin /* Wait for the debugger parent process to exit. */ 36657c74f5bSJohn Baldwin wpid = waitpid(debugger, &status, 0); 36757c74f5bSJohn Baldwin ATF_REQUIRE(wpid == debugger); 36857c74f5bSJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 36957c74f5bSJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 2); 37057c74f5bSJohn Baldwin 37157c74f5bSJohn Baldwin /* A WNOHANG wait here should see the non-exited child. */ 37257c74f5bSJohn Baldwin wpid = waitpid(child, &status, WNOHANG); 37357c74f5bSJohn Baldwin ATF_REQUIRE(wpid == 0); 37457c74f5bSJohn Baldwin 37557c74f5bSJohn Baldwin /* Wait for the debugger to attach to the child. */ 37657c74f5bSJohn Baldwin ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c)); 37757c74f5bSJohn Baldwin 37857c74f5bSJohn Baldwin /* Release the child. */ 37957c74f5bSJohn Baldwin ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c)); 38057c74f5bSJohn Baldwin ATF_REQUIRE(read(cpipe[0], &c, sizeof(c)) == 0); 38157c74f5bSJohn Baldwin close(cpipe[0]); 38257c74f5bSJohn Baldwin 38398685dc8SJohn Baldwin wait_for_zombie(child); 38457c74f5bSJohn Baldwin 38557c74f5bSJohn Baldwin /* 3862f021998SJohn Baldwin * This wait should return a pid of 0 to indicate no status to 3872f021998SJohn Baldwin * report. The parent should see the child as non-exited 3882f021998SJohn Baldwin * until the debugger sees the exit. 38957c74f5bSJohn Baldwin */ 39057c74f5bSJohn Baldwin wpid = waitpid(child, &status, WNOHANG); 39157c74f5bSJohn Baldwin ATF_REQUIRE(wpid == 0); 39257c74f5bSJohn Baldwin 39357c74f5bSJohn Baldwin /* Signal the debugger to wait for the child. */ 394eddb85c6SJohn Baldwin ATF_REQUIRE(write(dpipe[0], &c, sizeof(c)) == sizeof(c)); 39557c74f5bSJohn Baldwin 39657c74f5bSJohn Baldwin /* Wait for the debugger. */ 397eddb85c6SJohn Baldwin ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == 0); 398eddb85c6SJohn Baldwin close(dpipe[0]); 39957c74f5bSJohn Baldwin 40057c74f5bSJohn Baldwin /* The child process should now be ready. */ 40157c74f5bSJohn Baldwin wpid = waitpid(child, &status, WNOHANG); 40257c74f5bSJohn Baldwin ATF_REQUIRE(wpid == child); 40357c74f5bSJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 40457c74f5bSJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 40557c74f5bSJohn Baldwin } 40657c74f5bSJohn Baldwin 40798685dc8SJohn Baldwin /* 40898685dc8SJohn Baldwin * The parent process should always act the same regardless of how the 40998685dc8SJohn Baldwin * debugger is attached to it. 41098685dc8SJohn Baldwin */ 41198685dc8SJohn Baldwin static __dead2 void 41298685dc8SJohn Baldwin follow_fork_parent(void) 41398685dc8SJohn Baldwin { 41498685dc8SJohn Baldwin pid_t fpid, wpid; 41598685dc8SJohn Baldwin int status; 41698685dc8SJohn Baldwin 41798685dc8SJohn Baldwin CHILD_REQUIRE((fpid = fork()) != -1); 41898685dc8SJohn Baldwin 41998685dc8SJohn Baldwin if (fpid == 0) 42098685dc8SJohn Baldwin /* Child */ 421*b98cb919SJohn Baldwin _exit(2); 42298685dc8SJohn Baldwin 42398685dc8SJohn Baldwin wpid = waitpid(fpid, &status, 0); 42498685dc8SJohn Baldwin CHILD_REQUIRE(wpid == fpid); 42598685dc8SJohn Baldwin CHILD_REQUIRE(WIFEXITED(status)); 42698685dc8SJohn Baldwin CHILD_REQUIRE(WEXITSTATUS(status) == 2); 42798685dc8SJohn Baldwin 428*b98cb919SJohn Baldwin _exit(1); 42998685dc8SJohn Baldwin } 43098685dc8SJohn Baldwin 43198685dc8SJohn Baldwin /* 43298685dc8SJohn Baldwin * Helper routine for follow fork tests. This waits for two stops 43398685dc8SJohn Baldwin * that report both "sides" of a fork. It returns the pid of the new 43498685dc8SJohn Baldwin * child process. 43598685dc8SJohn Baldwin */ 43698685dc8SJohn Baldwin static pid_t 43798685dc8SJohn Baldwin handle_fork_events(pid_t parent) 43898685dc8SJohn Baldwin { 43998685dc8SJohn Baldwin struct ptrace_lwpinfo pl; 44098685dc8SJohn Baldwin bool fork_reported[2]; 44198685dc8SJohn Baldwin pid_t child, wpid; 44298685dc8SJohn Baldwin int i, status; 44398685dc8SJohn Baldwin 44498685dc8SJohn Baldwin fork_reported[0] = false; 44598685dc8SJohn Baldwin fork_reported[1] = false; 44698685dc8SJohn Baldwin child = -1; 44798685dc8SJohn Baldwin 44898685dc8SJohn Baldwin /* 44998685dc8SJohn Baldwin * Each process should report a fork event. The parent should 45098685dc8SJohn Baldwin * report a PL_FLAG_FORKED event, and the child should report 45198685dc8SJohn Baldwin * a PL_FLAG_CHILD event. 45298685dc8SJohn Baldwin */ 45398685dc8SJohn Baldwin for (i = 0; i < 2; i++) { 45498685dc8SJohn Baldwin wpid = wait(&status); 45598685dc8SJohn Baldwin ATF_REQUIRE(wpid > 0); 45698685dc8SJohn Baldwin ATF_REQUIRE(WIFSTOPPED(status)); 45798685dc8SJohn Baldwin 45898685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, 45998685dc8SJohn Baldwin sizeof(pl)) != -1); 46098685dc8SJohn Baldwin ATF_REQUIRE((pl.pl_flags & (PL_FLAG_FORKED | PL_FLAG_CHILD)) != 46198685dc8SJohn Baldwin 0); 46298685dc8SJohn Baldwin ATF_REQUIRE((pl.pl_flags & (PL_FLAG_FORKED | PL_FLAG_CHILD)) != 46398685dc8SJohn Baldwin (PL_FLAG_FORKED | PL_FLAG_CHILD)); 46498685dc8SJohn Baldwin if (pl.pl_flags & PL_FLAG_CHILD) { 46598685dc8SJohn Baldwin ATF_REQUIRE(wpid != parent); 46698685dc8SJohn Baldwin ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); 46798685dc8SJohn Baldwin ATF_REQUIRE(!fork_reported[1]); 46898685dc8SJohn Baldwin if (child == -1) 46998685dc8SJohn Baldwin child = wpid; 47098685dc8SJohn Baldwin else 47198685dc8SJohn Baldwin ATF_REQUIRE(child == wpid); 47298685dc8SJohn Baldwin fork_reported[1] = true; 47398685dc8SJohn Baldwin } else { 47498685dc8SJohn Baldwin ATF_REQUIRE(wpid == parent); 47598685dc8SJohn Baldwin ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); 47698685dc8SJohn Baldwin ATF_REQUIRE(!fork_reported[0]); 47798685dc8SJohn Baldwin if (child == -1) 47898685dc8SJohn Baldwin child = pl.pl_child_pid; 47998685dc8SJohn Baldwin else 48098685dc8SJohn Baldwin ATF_REQUIRE(child == pl.pl_child_pid); 48198685dc8SJohn Baldwin fork_reported[0] = true; 48298685dc8SJohn Baldwin } 48398685dc8SJohn Baldwin } 48498685dc8SJohn Baldwin 48598685dc8SJohn Baldwin return (child); 48698685dc8SJohn Baldwin } 48798685dc8SJohn Baldwin 48898685dc8SJohn Baldwin /* 48998685dc8SJohn Baldwin * Verify that a new child process is stopped after a followed fork and 49098685dc8SJohn Baldwin * that the traced parent sees the exit of the child after the debugger 49198685dc8SJohn Baldwin * when both processes remain attached to the debugger. 49298685dc8SJohn Baldwin */ 49398685dc8SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_both_attached); 49498685dc8SJohn Baldwin ATF_TC_BODY(ptrace__follow_fork_both_attached, tc) 49598685dc8SJohn Baldwin { 496479b610dSJohn Baldwin pid_t children[2], fpid, wpid; 49798685dc8SJohn Baldwin int status; 49898685dc8SJohn Baldwin 49998685dc8SJohn Baldwin ATF_REQUIRE((fpid = fork()) != -1); 50098685dc8SJohn Baldwin if (fpid == 0) { 50198685dc8SJohn Baldwin trace_me(); 50298685dc8SJohn Baldwin follow_fork_parent(); 50398685dc8SJohn Baldwin } 50498685dc8SJohn Baldwin 50598685dc8SJohn Baldwin /* Parent process. */ 50698685dc8SJohn Baldwin children[0] = fpid; 50798685dc8SJohn Baldwin 50898685dc8SJohn Baldwin /* The first wait() should report the stop from SIGSTOP. */ 50998685dc8SJohn Baldwin wpid = waitpid(children[0], &status, 0); 51098685dc8SJohn Baldwin ATF_REQUIRE(wpid == children[0]); 51198685dc8SJohn Baldwin ATF_REQUIRE(WIFSTOPPED(status)); 51298685dc8SJohn Baldwin ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); 51398685dc8SJohn Baldwin 51498685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); 51598685dc8SJohn Baldwin 51698685dc8SJohn Baldwin /* Continue the child ignoring the SIGSTOP. */ 51798685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); 51898685dc8SJohn Baldwin 51998685dc8SJohn Baldwin children[1] = handle_fork_events(children[0]); 52098685dc8SJohn Baldwin ATF_REQUIRE(children[1] > 0); 52198685dc8SJohn Baldwin 52298685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); 52398685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); 52498685dc8SJohn Baldwin 52598685dc8SJohn Baldwin /* 52698685dc8SJohn Baldwin * The child can't exit until the grandchild reports status, so the 52798685dc8SJohn Baldwin * grandchild should report its exit first to the debugger. 52898685dc8SJohn Baldwin */ 52998685dc8SJohn Baldwin wpid = wait(&status); 53098685dc8SJohn Baldwin ATF_REQUIRE(wpid == children[1]); 53198685dc8SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 53298685dc8SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 2); 53398685dc8SJohn Baldwin 53498685dc8SJohn Baldwin wpid = wait(&status); 53598685dc8SJohn Baldwin ATF_REQUIRE(wpid == children[0]); 53698685dc8SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 53798685dc8SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 53898685dc8SJohn Baldwin 53998685dc8SJohn Baldwin wpid = wait(&status); 54098685dc8SJohn Baldwin ATF_REQUIRE(wpid == -1); 54198685dc8SJohn Baldwin ATF_REQUIRE(errno == ECHILD); 54298685dc8SJohn Baldwin } 54398685dc8SJohn Baldwin 54498685dc8SJohn Baldwin /* 54598685dc8SJohn Baldwin * Verify that a new child process is stopped after a followed fork 54698685dc8SJohn Baldwin * and that the traced parent sees the exit of the child when the new 54798685dc8SJohn Baldwin * child process is detached after it reports its fork. 54898685dc8SJohn Baldwin */ 54998685dc8SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached); 55098685dc8SJohn Baldwin ATF_TC_BODY(ptrace__follow_fork_child_detached, tc) 55198685dc8SJohn Baldwin { 552479b610dSJohn Baldwin pid_t children[2], fpid, wpid; 55398685dc8SJohn Baldwin int status; 55498685dc8SJohn Baldwin 55598685dc8SJohn Baldwin ATF_REQUIRE((fpid = fork()) != -1); 55698685dc8SJohn Baldwin if (fpid == 0) { 55798685dc8SJohn Baldwin trace_me(); 55898685dc8SJohn Baldwin follow_fork_parent(); 55998685dc8SJohn Baldwin } 56098685dc8SJohn Baldwin 56198685dc8SJohn Baldwin /* Parent process. */ 56298685dc8SJohn Baldwin children[0] = fpid; 56398685dc8SJohn Baldwin 56498685dc8SJohn Baldwin /* The first wait() should report the stop from SIGSTOP. */ 56598685dc8SJohn Baldwin wpid = waitpid(children[0], &status, 0); 56698685dc8SJohn Baldwin ATF_REQUIRE(wpid == children[0]); 56798685dc8SJohn Baldwin ATF_REQUIRE(WIFSTOPPED(status)); 56898685dc8SJohn Baldwin ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); 56998685dc8SJohn Baldwin 57098685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); 57198685dc8SJohn Baldwin 57298685dc8SJohn Baldwin /* Continue the child ignoring the SIGSTOP. */ 57398685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); 57498685dc8SJohn Baldwin 57598685dc8SJohn Baldwin children[1] = handle_fork_events(children[0]); 57698685dc8SJohn Baldwin ATF_REQUIRE(children[1] > 0); 57798685dc8SJohn Baldwin 57898685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); 57998685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_DETACH, children[1], (caddr_t)1, 0) != -1); 58098685dc8SJohn Baldwin 58198685dc8SJohn Baldwin /* 58298685dc8SJohn Baldwin * Should not see any status from the grandchild now, only the 58398685dc8SJohn Baldwin * child. 58498685dc8SJohn Baldwin */ 58598685dc8SJohn Baldwin wpid = wait(&status); 58698685dc8SJohn Baldwin ATF_REQUIRE(wpid == children[0]); 58798685dc8SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 58898685dc8SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 58998685dc8SJohn Baldwin 59098685dc8SJohn Baldwin wpid = wait(&status); 59198685dc8SJohn Baldwin ATF_REQUIRE(wpid == -1); 59298685dc8SJohn Baldwin ATF_REQUIRE(errno == ECHILD); 59398685dc8SJohn Baldwin } 59498685dc8SJohn Baldwin 59598685dc8SJohn Baldwin /* 59698685dc8SJohn Baldwin * Verify that a new child process is stopped after a followed fork 59798685dc8SJohn Baldwin * and that the traced parent sees the exit of the child when the 59898685dc8SJohn Baldwin * traced parent is detached after the fork. 59998685dc8SJohn Baldwin */ 60098685dc8SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_parent_detached); 60198685dc8SJohn Baldwin ATF_TC_BODY(ptrace__follow_fork_parent_detached, tc) 60298685dc8SJohn Baldwin { 603479b610dSJohn Baldwin pid_t children[2], fpid, wpid; 60498685dc8SJohn Baldwin int status; 60598685dc8SJohn Baldwin 60698685dc8SJohn Baldwin ATF_REQUIRE((fpid = fork()) != -1); 60798685dc8SJohn Baldwin if (fpid == 0) { 60898685dc8SJohn Baldwin trace_me(); 60998685dc8SJohn Baldwin follow_fork_parent(); 61098685dc8SJohn Baldwin } 61198685dc8SJohn Baldwin 61298685dc8SJohn Baldwin /* Parent process. */ 61398685dc8SJohn Baldwin children[0] = fpid; 61498685dc8SJohn Baldwin 61598685dc8SJohn Baldwin /* The first wait() should report the stop from SIGSTOP. */ 61698685dc8SJohn Baldwin wpid = waitpid(children[0], &status, 0); 61798685dc8SJohn Baldwin ATF_REQUIRE(wpid == children[0]); 61898685dc8SJohn Baldwin ATF_REQUIRE(WIFSTOPPED(status)); 61998685dc8SJohn Baldwin ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); 62098685dc8SJohn Baldwin 62198685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); 62298685dc8SJohn Baldwin 62398685dc8SJohn Baldwin /* Continue the child ignoring the SIGSTOP. */ 62498685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); 62598685dc8SJohn Baldwin 62698685dc8SJohn Baldwin children[1] = handle_fork_events(children[0]); 62798685dc8SJohn Baldwin ATF_REQUIRE(children[1] > 0); 62898685dc8SJohn Baldwin 62998685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1); 63098685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); 63198685dc8SJohn Baldwin 63298685dc8SJohn Baldwin /* 63398685dc8SJohn Baldwin * The child can't exit until the grandchild reports status, so the 63498685dc8SJohn Baldwin * grandchild should report its exit first to the debugger. 63598685dc8SJohn Baldwin * 63698685dc8SJohn Baldwin * Even though the child process is detached, it is still a 63798685dc8SJohn Baldwin * child of the debugger, so it will still report it's exit 63898685dc8SJohn Baldwin * after the grandchild. 63998685dc8SJohn Baldwin */ 64098685dc8SJohn Baldwin wpid = wait(&status); 64198685dc8SJohn Baldwin ATF_REQUIRE(wpid == children[1]); 64298685dc8SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 64398685dc8SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 2); 64498685dc8SJohn Baldwin 64598685dc8SJohn Baldwin wpid = wait(&status); 64698685dc8SJohn Baldwin ATF_REQUIRE(wpid == children[0]); 64798685dc8SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 64898685dc8SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 64998685dc8SJohn Baldwin 65098685dc8SJohn Baldwin wpid = wait(&status); 65198685dc8SJohn Baldwin ATF_REQUIRE(wpid == -1); 65298685dc8SJohn Baldwin ATF_REQUIRE(errno == ECHILD); 65398685dc8SJohn Baldwin } 65498685dc8SJohn Baldwin 65598685dc8SJohn Baldwin static void 65698685dc8SJohn Baldwin attach_fork_parent(int cpipe[2]) 65798685dc8SJohn Baldwin { 65898685dc8SJohn Baldwin pid_t fpid; 65998685dc8SJohn Baldwin 66098685dc8SJohn Baldwin close(cpipe[0]); 66198685dc8SJohn Baldwin 66298685dc8SJohn Baldwin /* Double-fork to disassociate from the debugger. */ 66398685dc8SJohn Baldwin CHILD_REQUIRE((fpid = fork()) != -1); 66498685dc8SJohn Baldwin if (fpid != 0) 665*b98cb919SJohn Baldwin _exit(3); 66698685dc8SJohn Baldwin 66798685dc8SJohn Baldwin /* Send the pid of the disassociated child to the debugger. */ 66898685dc8SJohn Baldwin fpid = getpid(); 66998685dc8SJohn Baldwin CHILD_REQUIRE(write(cpipe[1], &fpid, sizeof(fpid)) == sizeof(fpid)); 67098685dc8SJohn Baldwin 67198685dc8SJohn Baldwin /* Wait for the debugger to attach. */ 67298685dc8SJohn Baldwin CHILD_REQUIRE(read(cpipe[1], &fpid, sizeof(fpid)) == 0); 67398685dc8SJohn Baldwin } 67498685dc8SJohn Baldwin 67598685dc8SJohn Baldwin /* 67698685dc8SJohn Baldwin * Verify that a new child process is stopped after a followed fork and 67798685dc8SJohn Baldwin * that the traced parent sees the exit of the child after the debugger 67898685dc8SJohn Baldwin * when both processes remain attached to the debugger. In this test 67998685dc8SJohn Baldwin * the parent that forks is not a direct child of the debugger. 68098685dc8SJohn Baldwin */ 68198685dc8SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_both_attached_unrelated_debugger); 68298685dc8SJohn Baldwin ATF_TC_BODY(ptrace__follow_fork_both_attached_unrelated_debugger, tc) 68398685dc8SJohn Baldwin { 684479b610dSJohn Baldwin pid_t children[2], fpid, wpid; 68598685dc8SJohn Baldwin int cpipe[2], status; 68698685dc8SJohn Baldwin 68798685dc8SJohn Baldwin ATF_REQUIRE(pipe(cpipe) == 0); 68898685dc8SJohn Baldwin ATF_REQUIRE((fpid = fork()) != -1); 68998685dc8SJohn Baldwin if (fpid == 0) { 69098685dc8SJohn Baldwin attach_fork_parent(cpipe); 69198685dc8SJohn Baldwin follow_fork_parent(); 69298685dc8SJohn Baldwin } 69398685dc8SJohn Baldwin 69498685dc8SJohn Baldwin /* Parent process. */ 69598685dc8SJohn Baldwin close(cpipe[1]); 69698685dc8SJohn Baldwin 69798685dc8SJohn Baldwin /* Wait for the direct child to exit. */ 69898685dc8SJohn Baldwin wpid = waitpid(fpid, &status, 0); 69998685dc8SJohn Baldwin ATF_REQUIRE(wpid == fpid); 70098685dc8SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 70198685dc8SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 3); 70298685dc8SJohn Baldwin 70398685dc8SJohn Baldwin /* Read the pid of the fork parent. */ 70498685dc8SJohn Baldwin ATF_REQUIRE(read(cpipe[0], &children[0], sizeof(children[0])) == 70598685dc8SJohn Baldwin sizeof(children[0])); 70698685dc8SJohn Baldwin 70798685dc8SJohn Baldwin /* Attach to the fork parent. */ 70898685dc8SJohn Baldwin attach_child(children[0]); 70998685dc8SJohn Baldwin 71098685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); 71198685dc8SJohn Baldwin 71298685dc8SJohn Baldwin /* Continue the fork parent ignoring the SIGSTOP. */ 71398685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); 71498685dc8SJohn Baldwin 71598685dc8SJohn Baldwin /* Signal the fork parent to continue. */ 71698685dc8SJohn Baldwin close(cpipe[0]); 71798685dc8SJohn Baldwin 71898685dc8SJohn Baldwin children[1] = handle_fork_events(children[0]); 71998685dc8SJohn Baldwin ATF_REQUIRE(children[1] > 0); 72098685dc8SJohn Baldwin 72198685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); 72298685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); 72398685dc8SJohn Baldwin 72498685dc8SJohn Baldwin /* 72598685dc8SJohn Baldwin * The fork parent can't exit until the child reports status, 72698685dc8SJohn Baldwin * so the child should report its exit first to the debugger. 72798685dc8SJohn Baldwin */ 72898685dc8SJohn Baldwin wpid = wait(&status); 72998685dc8SJohn Baldwin ATF_REQUIRE(wpid == children[1]); 73098685dc8SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 73198685dc8SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 2); 73298685dc8SJohn Baldwin 73398685dc8SJohn Baldwin wpid = wait(&status); 73498685dc8SJohn Baldwin ATF_REQUIRE(wpid == children[0]); 73598685dc8SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 73698685dc8SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 73798685dc8SJohn Baldwin 73898685dc8SJohn Baldwin wpid = wait(&status); 73998685dc8SJohn Baldwin ATF_REQUIRE(wpid == -1); 74098685dc8SJohn Baldwin ATF_REQUIRE(errno == ECHILD); 74198685dc8SJohn Baldwin } 74298685dc8SJohn Baldwin 74398685dc8SJohn Baldwin /* 74498685dc8SJohn Baldwin * Verify that a new child process is stopped after a followed fork 74598685dc8SJohn Baldwin * and that the traced parent sees the exit of the child when the new 74698685dc8SJohn Baldwin * child process is detached after it reports its fork. In this test 74798685dc8SJohn Baldwin * the parent that forks is not a direct child of the debugger. 74898685dc8SJohn Baldwin */ 74998685dc8SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_child_detached_unrelated_debugger); 75098685dc8SJohn Baldwin ATF_TC_BODY(ptrace__follow_fork_child_detached_unrelated_debugger, tc) 75198685dc8SJohn Baldwin { 752479b610dSJohn Baldwin pid_t children[2], fpid, wpid; 75398685dc8SJohn Baldwin int cpipe[2], status; 75498685dc8SJohn Baldwin 75598685dc8SJohn Baldwin ATF_REQUIRE(pipe(cpipe) == 0); 75698685dc8SJohn Baldwin ATF_REQUIRE((fpid = fork()) != -1); 75798685dc8SJohn Baldwin if (fpid == 0) { 75898685dc8SJohn Baldwin attach_fork_parent(cpipe); 75998685dc8SJohn Baldwin follow_fork_parent(); 76098685dc8SJohn Baldwin } 76198685dc8SJohn Baldwin 76298685dc8SJohn Baldwin /* Parent process. */ 76398685dc8SJohn Baldwin close(cpipe[1]); 76498685dc8SJohn Baldwin 76598685dc8SJohn Baldwin /* Wait for the direct child to exit. */ 76698685dc8SJohn Baldwin wpid = waitpid(fpid, &status, 0); 76798685dc8SJohn Baldwin ATF_REQUIRE(wpid == fpid); 76898685dc8SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 76998685dc8SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 3); 77098685dc8SJohn Baldwin 77198685dc8SJohn Baldwin /* Read the pid of the fork parent. */ 77298685dc8SJohn Baldwin ATF_REQUIRE(read(cpipe[0], &children[0], sizeof(children[0])) == 77398685dc8SJohn Baldwin sizeof(children[0])); 77498685dc8SJohn Baldwin 77598685dc8SJohn Baldwin /* Attach to the fork parent. */ 77698685dc8SJohn Baldwin attach_child(children[0]); 77798685dc8SJohn Baldwin 77898685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); 77998685dc8SJohn Baldwin 78098685dc8SJohn Baldwin /* Continue the fork parent ignoring the SIGSTOP. */ 78198685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); 78298685dc8SJohn Baldwin 78398685dc8SJohn Baldwin /* Signal the fork parent to continue. */ 78498685dc8SJohn Baldwin close(cpipe[0]); 78598685dc8SJohn Baldwin 78698685dc8SJohn Baldwin children[1] = handle_fork_events(children[0]); 78798685dc8SJohn Baldwin ATF_REQUIRE(children[1] > 0); 78898685dc8SJohn Baldwin 78998685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); 79098685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_DETACH, children[1], (caddr_t)1, 0) != -1); 79198685dc8SJohn Baldwin 79298685dc8SJohn Baldwin /* 79398685dc8SJohn Baldwin * Should not see any status from the child now, only the fork 79498685dc8SJohn Baldwin * parent. 79598685dc8SJohn Baldwin */ 79698685dc8SJohn Baldwin wpid = wait(&status); 79798685dc8SJohn Baldwin ATF_REQUIRE(wpid == children[0]); 79898685dc8SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 79998685dc8SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 80098685dc8SJohn Baldwin 80198685dc8SJohn Baldwin wpid = wait(&status); 80298685dc8SJohn Baldwin ATF_REQUIRE(wpid == -1); 80398685dc8SJohn Baldwin ATF_REQUIRE(errno == ECHILD); 80498685dc8SJohn Baldwin } 80598685dc8SJohn Baldwin 80698685dc8SJohn Baldwin /* 80798685dc8SJohn Baldwin * Verify that a new child process is stopped after a followed fork 80898685dc8SJohn Baldwin * and that the traced parent sees the exit of the child when the 80998685dc8SJohn Baldwin * traced parent is detached after the fork. In this test the parent 81098685dc8SJohn Baldwin * that forks is not a direct child of the debugger. 81198685dc8SJohn Baldwin */ 81298685dc8SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__follow_fork_parent_detached_unrelated_debugger); 81398685dc8SJohn Baldwin ATF_TC_BODY(ptrace__follow_fork_parent_detached_unrelated_debugger, tc) 81498685dc8SJohn Baldwin { 815479b610dSJohn Baldwin pid_t children[2], fpid, wpid; 81698685dc8SJohn Baldwin int cpipe[2], status; 81798685dc8SJohn Baldwin 81898685dc8SJohn Baldwin ATF_REQUIRE(pipe(cpipe) == 0); 81998685dc8SJohn Baldwin ATF_REQUIRE((fpid = fork()) != -1); 82098685dc8SJohn Baldwin if (fpid == 0) { 82198685dc8SJohn Baldwin attach_fork_parent(cpipe); 82298685dc8SJohn Baldwin follow_fork_parent(); 82398685dc8SJohn Baldwin } 82498685dc8SJohn Baldwin 82598685dc8SJohn Baldwin /* Parent process. */ 82698685dc8SJohn Baldwin close(cpipe[1]); 82798685dc8SJohn Baldwin 82898685dc8SJohn Baldwin /* Wait for the direct child to exit. */ 82998685dc8SJohn Baldwin wpid = waitpid(fpid, &status, 0); 83098685dc8SJohn Baldwin ATF_REQUIRE(wpid == fpid); 83198685dc8SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 83298685dc8SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 3); 83398685dc8SJohn Baldwin 83498685dc8SJohn Baldwin /* Read the pid of the fork parent. */ 83598685dc8SJohn Baldwin ATF_REQUIRE(read(cpipe[0], &children[0], sizeof(children[0])) == 83698685dc8SJohn Baldwin sizeof(children[0])); 83798685dc8SJohn Baldwin 83898685dc8SJohn Baldwin /* Attach to the fork parent. */ 83998685dc8SJohn Baldwin attach_child(children[0]); 84098685dc8SJohn Baldwin 84198685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, children[0], NULL, 1) != -1); 84298685dc8SJohn Baldwin 84398685dc8SJohn Baldwin /* Continue the fork parent ignoring the SIGSTOP. */ 84498685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, children[0], (caddr_t)1, 0) != -1); 84598685dc8SJohn Baldwin 84698685dc8SJohn Baldwin /* Signal the fork parent to continue. */ 84798685dc8SJohn Baldwin close(cpipe[0]); 84898685dc8SJohn Baldwin 84998685dc8SJohn Baldwin children[1] = handle_fork_events(children[0]); 85098685dc8SJohn Baldwin ATF_REQUIRE(children[1] > 0); 85198685dc8SJohn Baldwin 85298685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_DETACH, children[0], (caddr_t)1, 0) != -1); 85398685dc8SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, children[1], (caddr_t)1, 0) != -1); 85498685dc8SJohn Baldwin 85598685dc8SJohn Baldwin /* 85698685dc8SJohn Baldwin * Should not see any status from the fork parent now, only 85798685dc8SJohn Baldwin * the child. 85898685dc8SJohn Baldwin */ 85998685dc8SJohn Baldwin wpid = wait(&status); 86098685dc8SJohn Baldwin ATF_REQUIRE(wpid == children[1]); 86198685dc8SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 86298685dc8SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 2); 86398685dc8SJohn Baldwin 86498685dc8SJohn Baldwin wpid = wait(&status); 86598685dc8SJohn Baldwin ATF_REQUIRE(wpid == -1); 86698685dc8SJohn Baldwin ATF_REQUIRE(errno == ECHILD); 86798685dc8SJohn Baldwin } 86898685dc8SJohn Baldwin 869368b2b1cSJohn Baldwin /* 870368b2b1cSJohn Baldwin * Verify that a child process does not see an unrelated debugger as its 871368b2b1cSJohn Baldwin * parent but sees its original parent process. 872368b2b1cSJohn Baldwin */ 873368b2b1cSJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__getppid); 874368b2b1cSJohn Baldwin ATF_TC_BODY(ptrace__getppid, tc) 875368b2b1cSJohn Baldwin { 876368b2b1cSJohn Baldwin pid_t child, debugger, ppid, wpid; 877368b2b1cSJohn Baldwin int cpipe[2], dpipe[2], status; 878368b2b1cSJohn Baldwin char c; 879368b2b1cSJohn Baldwin 880368b2b1cSJohn Baldwin ATF_REQUIRE(pipe(cpipe) == 0); 881368b2b1cSJohn Baldwin ATF_REQUIRE((child = fork()) != -1); 882368b2b1cSJohn Baldwin 883368b2b1cSJohn Baldwin if (child == 0) { 884368b2b1cSJohn Baldwin /* Child process. */ 885368b2b1cSJohn Baldwin close(cpipe[0]); 886368b2b1cSJohn Baldwin 887368b2b1cSJohn Baldwin /* Wait for parent to be ready. */ 888368b2b1cSJohn Baldwin CHILD_REQUIRE(read(cpipe[1], &c, sizeof(c)) == sizeof(c)); 889368b2b1cSJohn Baldwin 890368b2b1cSJohn Baldwin /* Report the parent PID to the parent. */ 891368b2b1cSJohn Baldwin ppid = getppid(); 892368b2b1cSJohn Baldwin CHILD_REQUIRE(write(cpipe[1], &ppid, sizeof(ppid)) == 893368b2b1cSJohn Baldwin sizeof(ppid)); 894368b2b1cSJohn Baldwin 895368b2b1cSJohn Baldwin _exit(1); 896368b2b1cSJohn Baldwin } 897368b2b1cSJohn Baldwin close(cpipe[1]); 898368b2b1cSJohn Baldwin 899368b2b1cSJohn Baldwin ATF_REQUIRE(pipe(dpipe) == 0); 900368b2b1cSJohn Baldwin ATF_REQUIRE((debugger = fork()) != -1); 901368b2b1cSJohn Baldwin 902368b2b1cSJohn Baldwin if (debugger == 0) { 903368b2b1cSJohn Baldwin /* Debugger process. */ 904368b2b1cSJohn Baldwin close(dpipe[0]); 905368b2b1cSJohn Baldwin 906368b2b1cSJohn Baldwin CHILD_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) != -1); 907368b2b1cSJohn Baldwin 908368b2b1cSJohn Baldwin wpid = waitpid(child, &status, 0); 909368b2b1cSJohn Baldwin CHILD_REQUIRE(wpid == child); 910368b2b1cSJohn Baldwin CHILD_REQUIRE(WIFSTOPPED(status)); 911368b2b1cSJohn Baldwin CHILD_REQUIRE(WSTOPSIG(status) == SIGSTOP); 912368b2b1cSJohn Baldwin 913368b2b1cSJohn Baldwin CHILD_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); 914368b2b1cSJohn Baldwin 915368b2b1cSJohn Baldwin /* Signal parent that debugger is attached. */ 916368b2b1cSJohn Baldwin CHILD_REQUIRE(write(dpipe[1], &c, sizeof(c)) == sizeof(c)); 917368b2b1cSJohn Baldwin 918368b2b1cSJohn Baldwin /* Wait for traced child to exit. */ 919368b2b1cSJohn Baldwin wpid = waitpid(child, &status, 0); 920368b2b1cSJohn Baldwin CHILD_REQUIRE(wpid == child); 921368b2b1cSJohn Baldwin CHILD_REQUIRE(WIFEXITED(status)); 922368b2b1cSJohn Baldwin CHILD_REQUIRE(WEXITSTATUS(status) == 1); 923368b2b1cSJohn Baldwin 924368b2b1cSJohn Baldwin _exit(0); 925368b2b1cSJohn Baldwin } 926368b2b1cSJohn Baldwin close(dpipe[1]); 927368b2b1cSJohn Baldwin 928368b2b1cSJohn Baldwin /* Parent process. */ 929368b2b1cSJohn Baldwin 930368b2b1cSJohn Baldwin /* Wait for the debugger to attach to the child. */ 931368b2b1cSJohn Baldwin ATF_REQUIRE(read(dpipe[0], &c, sizeof(c)) == sizeof(c)); 932368b2b1cSJohn Baldwin 933368b2b1cSJohn Baldwin /* Release the child. */ 934368b2b1cSJohn Baldwin ATF_REQUIRE(write(cpipe[0], &c, sizeof(c)) == sizeof(c)); 935368b2b1cSJohn Baldwin 936368b2b1cSJohn Baldwin /* Read the parent PID from the child. */ 937368b2b1cSJohn Baldwin ATF_REQUIRE(read(cpipe[0], &ppid, sizeof(ppid)) == sizeof(ppid)); 938368b2b1cSJohn Baldwin close(cpipe[0]); 939368b2b1cSJohn Baldwin 940368b2b1cSJohn Baldwin ATF_REQUIRE(ppid == getpid()); 941368b2b1cSJohn Baldwin 942368b2b1cSJohn Baldwin /* Wait for the debugger. */ 943368b2b1cSJohn Baldwin wpid = waitpid(debugger, &status, 0); 944368b2b1cSJohn Baldwin ATF_REQUIRE(wpid == debugger); 945368b2b1cSJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 946368b2b1cSJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 0); 947368b2b1cSJohn Baldwin 948368b2b1cSJohn Baldwin /* The child process should now be ready. */ 949368b2b1cSJohn Baldwin wpid = waitpid(child, &status, WNOHANG); 950368b2b1cSJohn Baldwin ATF_REQUIRE(wpid == child); 951368b2b1cSJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 952368b2b1cSJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 953368b2b1cSJohn Baldwin } 954368b2b1cSJohn Baldwin 955c209e3e2SJohn Baldwin ATF_TP_ADD_TCS(tp) 956c209e3e2SJohn Baldwin { 957c209e3e2SJohn Baldwin 958c209e3e2SJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_trace_me); 959c209e3e2SJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_attach); 96057c74f5bSJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_child_debugger); 96157c74f5bSJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__parent_sees_exit_after_unrelated_debugger); 96298685dc8SJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__follow_fork_both_attached); 96398685dc8SJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__follow_fork_child_detached); 96498685dc8SJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__follow_fork_parent_detached); 96598685dc8SJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__follow_fork_both_attached_unrelated_debugger); 96698685dc8SJohn Baldwin ATF_TP_ADD_TC(tp, 96798685dc8SJohn Baldwin ptrace__follow_fork_child_detached_unrelated_debugger); 96898685dc8SJohn Baldwin ATF_TP_ADD_TC(tp, 96998685dc8SJohn Baldwin ptrace__follow_fork_parent_detached_unrelated_debugger); 970368b2b1cSJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__getppid); 971c209e3e2SJohn Baldwin 972c209e3e2SJohn Baldwin return (atf_no_error()); 973c209e3e2SJohn Baldwin } 974