1*c209e3e2SJohn Baldwin /*- 2*c209e3e2SJohn Baldwin * Copyright (c) 2015 John Baldwin <jhb@FreeBSD.org> 3*c209e3e2SJohn Baldwin * All rights reserved. 4*c209e3e2SJohn Baldwin * 5*c209e3e2SJohn Baldwin * Redistribution and use in source and binary forms, with or without 6*c209e3e2SJohn Baldwin * modification, are permitted provided that the following conditions 7*c209e3e2SJohn Baldwin * are met: 8*c209e3e2SJohn Baldwin * 1. Redistributions of source code must retain the above copyright 9*c209e3e2SJohn Baldwin * notice, this list of conditions and the following disclaimer. 10*c209e3e2SJohn Baldwin * 2. Redistributions in binary form must reproduce the above copyright 11*c209e3e2SJohn Baldwin * notice, this list of conditions and the following disclaimer in the 12*c209e3e2SJohn Baldwin * documentation and/or other materials provided with the distribution. 13*c209e3e2SJohn Baldwin * 14*c209e3e2SJohn Baldwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*c209e3e2SJohn Baldwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*c209e3e2SJohn Baldwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*c209e3e2SJohn Baldwin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*c209e3e2SJohn Baldwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*c209e3e2SJohn Baldwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*c209e3e2SJohn Baldwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*c209e3e2SJohn Baldwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*c209e3e2SJohn Baldwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*c209e3e2SJohn Baldwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*c209e3e2SJohn Baldwin * SUCH DAMAGE. 25*c209e3e2SJohn Baldwin */ 26*c209e3e2SJohn Baldwin 27*c209e3e2SJohn Baldwin #include <sys/cdefs.h> 28*c209e3e2SJohn Baldwin __FBSDID("$FreeBSD$"); 29*c209e3e2SJohn Baldwin 30*c209e3e2SJohn Baldwin #include <sys/types.h> 31*c209e3e2SJohn Baldwin #include <sys/ptrace.h> 32*c209e3e2SJohn Baldwin #include <sys/wait.h> 33*c209e3e2SJohn Baldwin #include <errno.h> 34*c209e3e2SJohn Baldwin #include <signal.h> 35*c209e3e2SJohn Baldwin #include <stdlib.h> 36*c209e3e2SJohn Baldwin #include <unistd.h> 37*c209e3e2SJohn Baldwin #include <atf-c.h> 38*c209e3e2SJohn Baldwin 39*c209e3e2SJohn Baldwin /* 40*c209e3e2SJohn Baldwin * Verify that a parent debugger process "sees" the exit of a debugged 41*c209e3e2SJohn Baldwin * process exactly once when attached via PT_TRACE_ME. 42*c209e3e2SJohn Baldwin */ 43*c209e3e2SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_trace_me); 44*c209e3e2SJohn Baldwin ATF_TC_BODY(ptrace__parent_wait_after_trace_me, tc) 45*c209e3e2SJohn Baldwin { 46*c209e3e2SJohn Baldwin pid_t child, wpid; 47*c209e3e2SJohn Baldwin int status; 48*c209e3e2SJohn Baldwin 49*c209e3e2SJohn Baldwin ATF_REQUIRE((child = fork()) != -1); 50*c209e3e2SJohn Baldwin if (child == 0) { 51*c209e3e2SJohn Baldwin /* Child process. */ 52*c209e3e2SJohn Baldwin ATF_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); 53*c209e3e2SJohn Baldwin 54*c209e3e2SJohn Baldwin /* Trigger a stop. */ 55*c209e3e2SJohn Baldwin raise(SIGSTOP); 56*c209e3e2SJohn Baldwin 57*c209e3e2SJohn Baldwin exit(1); 58*c209e3e2SJohn Baldwin } 59*c209e3e2SJohn Baldwin 60*c209e3e2SJohn Baldwin /* Parent process. */ 61*c209e3e2SJohn Baldwin 62*c209e3e2SJohn Baldwin /* The first wait() should report the stop from SIGSTOP. */ 63*c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 64*c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == child); 65*c209e3e2SJohn Baldwin ATF_REQUIRE(WIFSTOPPED(status)); 66*c209e3e2SJohn Baldwin ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); 67*c209e3e2SJohn Baldwin 68*c209e3e2SJohn Baldwin /* Continue the child ignoring the SIGSTOP. */ 69*c209e3e2SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); 70*c209e3e2SJohn Baldwin 71*c209e3e2SJohn Baldwin /* The second wait() should report the exit status. */ 72*c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 73*c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == child); 74*c209e3e2SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 75*c209e3e2SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 76*c209e3e2SJohn Baldwin 77*c209e3e2SJohn Baldwin /* The child should no longer exist. */ 78*c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 79*c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == -1); 80*c209e3e2SJohn Baldwin ATF_REQUIRE(errno == ECHILD); 81*c209e3e2SJohn Baldwin } 82*c209e3e2SJohn Baldwin 83*c209e3e2SJohn Baldwin /* 84*c209e3e2SJohn Baldwin * Verify that a parent debugger process "sees" the exit of a debugged 85*c209e3e2SJohn Baldwin * process exactly once when attached via PT_ATTACH. 86*c209e3e2SJohn Baldwin */ 87*c209e3e2SJohn Baldwin ATF_TC_WITHOUT_HEAD(ptrace__parent_wait_after_attach); 88*c209e3e2SJohn Baldwin ATF_TC_BODY(ptrace__parent_wait_after_attach, tc) 89*c209e3e2SJohn Baldwin { 90*c209e3e2SJohn Baldwin pid_t child, wpid; 91*c209e3e2SJohn Baldwin int cpipe[2], status; 92*c209e3e2SJohn Baldwin char c; 93*c209e3e2SJohn Baldwin 94*c209e3e2SJohn Baldwin ATF_REQUIRE(pipe(cpipe) == 0); 95*c209e3e2SJohn Baldwin ATF_REQUIRE((child = fork()) != -1); 96*c209e3e2SJohn Baldwin if (child == 0) { 97*c209e3e2SJohn Baldwin /* Child process. */ 98*c209e3e2SJohn Baldwin close(cpipe[0]); 99*c209e3e2SJohn Baldwin 100*c209e3e2SJohn Baldwin /* Wait for the parent to attach. */ 101*c209e3e2SJohn Baldwin ATF_REQUIRE(read(cpipe[1], &c, sizeof(c)) == 0); 102*c209e3e2SJohn Baldwin 103*c209e3e2SJohn Baldwin exit(1); 104*c209e3e2SJohn Baldwin } 105*c209e3e2SJohn Baldwin close(cpipe[1]); 106*c209e3e2SJohn Baldwin 107*c209e3e2SJohn Baldwin /* Parent process. */ 108*c209e3e2SJohn Baldwin 109*c209e3e2SJohn Baldwin /* Attach to the child process. */ 110*c209e3e2SJohn Baldwin ATF_REQUIRE(ptrace(PT_ATTACH, child, NULL, 0) == 0); 111*c209e3e2SJohn Baldwin 112*c209e3e2SJohn Baldwin /* The first wait() should report the SIGSTOP from PT_ATTACH. */ 113*c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 114*c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == child); 115*c209e3e2SJohn Baldwin ATF_REQUIRE(WIFSTOPPED(status)); 116*c209e3e2SJohn Baldwin ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); 117*c209e3e2SJohn Baldwin 118*c209e3e2SJohn Baldwin /* Continue the child ignoring the SIGSTOP. */ 119*c209e3e2SJohn Baldwin ATF_REQUIRE(ptrace(PT_CONTINUE, child, (caddr_t)1, 0) != -1); 120*c209e3e2SJohn Baldwin 121*c209e3e2SJohn Baldwin /* Signal the child to exit. */ 122*c209e3e2SJohn Baldwin close(cpipe[0]); 123*c209e3e2SJohn Baldwin 124*c209e3e2SJohn Baldwin /* The second wait() should report the exit status. */ 125*c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 126*c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == child); 127*c209e3e2SJohn Baldwin ATF_REQUIRE(WIFEXITED(status)); 128*c209e3e2SJohn Baldwin ATF_REQUIRE(WEXITSTATUS(status) == 1); 129*c209e3e2SJohn Baldwin 130*c209e3e2SJohn Baldwin /* The child should no longer exist. */ 131*c209e3e2SJohn Baldwin wpid = waitpid(child, &status, 0); 132*c209e3e2SJohn Baldwin ATF_REQUIRE(wpid == -1); 133*c209e3e2SJohn Baldwin ATF_REQUIRE(errno == ECHILD); 134*c209e3e2SJohn Baldwin } 135*c209e3e2SJohn Baldwin 136*c209e3e2SJohn Baldwin ATF_TP_ADD_TCS(tp) 137*c209e3e2SJohn Baldwin { 138*c209e3e2SJohn Baldwin 139*c209e3e2SJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_trace_me); 140*c209e3e2SJohn Baldwin ATF_TP_ADD_TC(tp, ptrace__parent_wait_after_attach); 141*c209e3e2SJohn Baldwin 142*c209e3e2SJohn Baldwin return (atf_no_error()); 143*c209e3e2SJohn Baldwin } 144