xref: /netbsd-src/tests/lib/libc/sys/t_ptrace_signal_wait.h (revision 7f74343bad119fe26eb9b38bcfb9ab4c67fa31b2)
1*7f74343bSsimonb /*	$NetBSD: t_ptrace_signal_wait.h,v 1.5 2021/03/19 00:44:09 simonb Exp $	*/
2a0f774c8Skamil 
3a0f774c8Skamil /*-
4a0f774c8Skamil  * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
5a0f774c8Skamil  * All rights reserved.
6a0f774c8Skamil  *
7a0f774c8Skamil  * Redistribution and use in source and binary forms, with or without
8a0f774c8Skamil  * modification, are permitted provided that the following conditions
9a0f774c8Skamil  * are met:
10a0f774c8Skamil  * 1. Redistributions of source code must retain the above copyright
11a0f774c8Skamil  *    notice, this list of conditions and the following disclaimer.
12a0f774c8Skamil  * 2. Redistributions in binary form must reproduce the above copyright
13a0f774c8Skamil  *    notice, this list of conditions and the following disclaimer in the
14a0f774c8Skamil  *    documentation and/or other materials provided with the distribution.
15a0f774c8Skamil  *
16a0f774c8Skamil  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17a0f774c8Skamil  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18a0f774c8Skamil  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19a0f774c8Skamil  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20a0f774c8Skamil  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21a0f774c8Skamil  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22a0f774c8Skamil  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23a0f774c8Skamil  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24a0f774c8Skamil  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25a0f774c8Skamil  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26a0f774c8Skamil  * POSSIBILITY OF SUCH DAMAGE.
27a0f774c8Skamil  */
28a0f774c8Skamil 
29a0f774c8Skamil 
30a0f774c8Skamil static void
traceme_raise(int sigval)31a0f774c8Skamil traceme_raise(int sigval)
32a0f774c8Skamil {
33a0f774c8Skamil 	const int exitval = 5;
34a0f774c8Skamil 	pid_t child, wpid;
35a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
36a0f774c8Skamil 	int status;
37a0f774c8Skamil #endif
38a0f774c8Skamil 
39a0f774c8Skamil 	ptrace_state_t state, zero_state;
40a0f774c8Skamil 	const int slen = sizeof(state);
41a0f774c8Skamil 	struct ptrace_siginfo info;
42a0f774c8Skamil 	memset(&zero_state, 0, sizeof(zero_state));
43a0f774c8Skamil 	memset(&info, 0, sizeof(info));
44a0f774c8Skamil 
45a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
46a0f774c8Skamil 	SYSCALL_REQUIRE((child = fork()) != -1);
47a0f774c8Skamil 	if (child == 0) {
48a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
49a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
50a0f774c8Skamil 
51a0f774c8Skamil 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
52a0f774c8Skamil 		FORKEE_ASSERT(raise(sigval) == 0);
53a0f774c8Skamil 
54a0f774c8Skamil 		switch (sigval) {
55a0f774c8Skamil 		case SIGKILL:
56a0f774c8Skamil 			/* NOTREACHED */
57a0f774c8Skamil 			FORKEE_ASSERTX(0 && "This shall not be reached");
58a0f774c8Skamil 			__unreachable();
59a0f774c8Skamil 		default:
60a0f774c8Skamil 			DPRINTF("Before exiting of the child process\n");
61a0f774c8Skamil 			_exit(exitval);
62a0f774c8Skamil 		}
63a0f774c8Skamil 	}
64a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
65a0f774c8Skamil 
66a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
67a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68a0f774c8Skamil 
69a0f774c8Skamil 	switch (sigval) {
70a0f774c8Skamil 	case SIGKILL:
71a0f774c8Skamil 		validate_status_signaled(status, sigval, 0);
72a0f774c8Skamil 		SYSCALL_REQUIRE(
73a0f774c8Skamil 		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) == -1);
74a0f774c8Skamil 
75a0f774c8Skamil 		break;
76a0f774c8Skamil 	default:
77a0f774c8Skamil 		validate_status_stopped(status, sigval);
78a0f774c8Skamil 
79a0f774c8Skamil 		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
80a0f774c8Skamil 			"child\n");
81a0f774c8Skamil 		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
82a0f774c8Skamil 			sizeof(info)) != -1);
83a0f774c8Skamil 
84a0f774c8Skamil 		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
85a0f774c8Skamil 		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
86a0f774c8Skamil 			"si_errno=%#x\n",
87a0f774c8Skamil 			info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
88a0f774c8Skamil 			info.psi_siginfo.si_errno);
89a0f774c8Skamil 
90a0f774c8Skamil 		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
91a0f774c8Skamil 		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
92a0f774c8Skamil 
93*7f74343bSsimonb 		DPRINTF("Assert that PT_GET_PROCESS_STATE returns non-error\n");
94a0f774c8Skamil 		SYSCALL_REQUIRE(
95a0f774c8Skamil 		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
96a0f774c8Skamil 		ATF_REQUIRE(memcmp(&state, &zero_state, slen) == 0);
97a0f774c8Skamil 
98a0f774c8Skamil 		DPRINTF("Before resuming the child process where it left off "
99a0f774c8Skamil 		    "and without signal to be sent\n");
100a0f774c8Skamil 		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
101a0f774c8Skamil 
102a0f774c8Skamil 		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
103a0f774c8Skamil 		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
104a0f774c8Skamil 		    child);
105a0f774c8Skamil 		break;
106a0f774c8Skamil 	}
107a0f774c8Skamil 
108a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
109a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
110a0f774c8Skamil }
111a0f774c8Skamil 
112a0f774c8Skamil #define TRACEME_RAISE(test, sig)					\
113a0f774c8Skamil ATF_TC(test);								\
114a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
115a0f774c8Skamil {									\
116a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
117a0f774c8Skamil 	    "Verify " #sig " followed by _exit(2) in a child");		\
118a0f774c8Skamil }									\
119a0f774c8Skamil 									\
120a0f774c8Skamil ATF_TC_BODY(test, tc)							\
121a0f774c8Skamil {									\
122a0f774c8Skamil 									\
123a0f774c8Skamil 	traceme_raise(sig);						\
124a0f774c8Skamil }
125a0f774c8Skamil 
TRACEME_RAISE(traceme_raise1,SIGKILL)126a0f774c8Skamil TRACEME_RAISE(traceme_raise1, SIGKILL) /* non-maskable */
127a0f774c8Skamil TRACEME_RAISE(traceme_raise2, SIGSTOP) /* non-maskable */
128a0f774c8Skamil TRACEME_RAISE(traceme_raise3, SIGABRT) /* regular abort trap */
129a0f774c8Skamil TRACEME_RAISE(traceme_raise4, SIGHUP)  /* hangup */
130a0f774c8Skamil TRACEME_RAISE(traceme_raise5, SIGCONT) /* continued? */
131a0f774c8Skamil TRACEME_RAISE(traceme_raise6, SIGTRAP) /* crash signal */
132a0f774c8Skamil TRACEME_RAISE(traceme_raise7, SIGBUS) /* crash signal */
133a0f774c8Skamil TRACEME_RAISE(traceme_raise8, SIGILL) /* crash signal */
134a0f774c8Skamil TRACEME_RAISE(traceme_raise9, SIGFPE) /* crash signal */
135a0f774c8Skamil TRACEME_RAISE(traceme_raise10, SIGSEGV) /* crash signal */
136a0f774c8Skamil 
137a0f774c8Skamil /// ----------------------------------------------------------------------------
138a0f774c8Skamil 
139a0f774c8Skamil static void
140a0f774c8Skamil traceme_raisesignal_ignored(int sigignored)
141a0f774c8Skamil {
142a0f774c8Skamil 	const int exitval = 5;
143a0f774c8Skamil 	const int sigval = SIGSTOP;
144a0f774c8Skamil 	pid_t child, wpid;
145a0f774c8Skamil 	struct sigaction sa;
146a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
147a0f774c8Skamil 	int status;
148a0f774c8Skamil #endif
149a0f774c8Skamil 	struct ptrace_siginfo info;
150a0f774c8Skamil 
151a0f774c8Skamil 	memset(&info, 0, sizeof(info));
152a0f774c8Skamil 
153a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
154a0f774c8Skamil 	SYSCALL_REQUIRE((child = fork()) != -1);
155a0f774c8Skamil 	if (child == 0) {
156a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
157a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
158a0f774c8Skamil 
159a0f774c8Skamil 		memset(&sa, 0, sizeof(sa));
160a0f774c8Skamil 		sa.sa_handler = SIG_IGN;
161a0f774c8Skamil 		sigemptyset(&sa.sa_mask);
162a0f774c8Skamil 		FORKEE_ASSERT(sigaction(sigignored, &sa, NULL) != -1);
163a0f774c8Skamil 
164a0f774c8Skamil 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
165a0f774c8Skamil 		FORKEE_ASSERT(raise(sigval) == 0);
166a0f774c8Skamil 
167a0f774c8Skamil 		DPRINTF("Before raising %s from child\n",
168a0f774c8Skamil 		    strsignal(sigignored));
169a0f774c8Skamil 		FORKEE_ASSERT(raise(sigignored) == 0);
170a0f774c8Skamil 
171a0f774c8Skamil 		DPRINTF("Before exiting of the child process\n");
172a0f774c8Skamil 		_exit(exitval);
173a0f774c8Skamil 	}
174a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
175a0f774c8Skamil 
176a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
177a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
178a0f774c8Skamil 
179a0f774c8Skamil 	validate_status_stopped(status, sigval);
180a0f774c8Skamil 
181a0f774c8Skamil 	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
182a0f774c8Skamil 	SYSCALL_REQUIRE(
183a0f774c8Skamil 	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
184a0f774c8Skamil 
185a0f774c8Skamil 	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
186a0f774c8Skamil 	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
187a0f774c8Skamil 	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
188a0f774c8Skamil 	    info.psi_siginfo.si_errno);
189a0f774c8Skamil 
190a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
191a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
192a0f774c8Skamil 
193a0f774c8Skamil 	DPRINTF("Before resuming the child process where it left off and "
194a0f774c8Skamil 	    "without signal to be sent\n");
195a0f774c8Skamil 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
196a0f774c8Skamil 
197a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
198a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
199a0f774c8Skamil 
200a0f774c8Skamil 	validate_status_stopped(status, sigignored);
201a0f774c8Skamil 
202a0f774c8Skamil 	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
203a0f774c8Skamil 	SYSCALL_REQUIRE(
204a0f774c8Skamil 	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
205a0f774c8Skamil 
206a0f774c8Skamil 	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
207a0f774c8Skamil 	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
208a0f774c8Skamil 	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
209a0f774c8Skamil 	    info.psi_siginfo.si_errno);
210a0f774c8Skamil 
211a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigignored);
212a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
213a0f774c8Skamil 
214a0f774c8Skamil 	DPRINTF("Before resuming the child process where it left off and "
215a0f774c8Skamil 	    "without signal to be sent\n");
216a0f774c8Skamil 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
217a0f774c8Skamil 
218a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
219a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
220a0f774c8Skamil 
221a0f774c8Skamil 	validate_status_exited(status, exitval);
222a0f774c8Skamil 
223a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
224a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
225a0f774c8Skamil }
226a0f774c8Skamil 
227a0f774c8Skamil #define TRACEME_RAISESIGNAL_IGNORED(test, sig)				\
228a0f774c8Skamil ATF_TC(test);								\
229a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
230a0f774c8Skamil {									\
231a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
232a0f774c8Skamil 	    "Verify that ignoring (with SIG_IGN) " #sig " in tracee "	\
233a0f774c8Skamil 	    "does not stop tracer from catching this raised signal");	\
234a0f774c8Skamil }									\
235a0f774c8Skamil 									\
236a0f774c8Skamil ATF_TC_BODY(test, tc)							\
237a0f774c8Skamil {									\
238a0f774c8Skamil 									\
239a0f774c8Skamil 	traceme_raisesignal_ignored(sig);				\
240a0f774c8Skamil }
241a0f774c8Skamil 
242a0f774c8Skamil // A signal handler for SIGKILL and SIGSTOP cannot be ignored.
TRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored1,SIGABRT)243a0f774c8Skamil TRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored1, SIGABRT) /* abort */
244a0f774c8Skamil TRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored2, SIGHUP)  /* hangup */
245a0f774c8Skamil TRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored3, SIGCONT) /* cont. */
246a0f774c8Skamil TRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored4, SIGTRAP) /* crash */
247a0f774c8Skamil TRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored5, SIGBUS) /* crash */
248a0f774c8Skamil TRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored6, SIGILL) /* crash */
249a0f774c8Skamil TRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored7, SIGFPE) /* crash */
250a0f774c8Skamil TRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored8, SIGSEGV) /* crash */
251a0f774c8Skamil 
252a0f774c8Skamil /// ----------------------------------------------------------------------------
253a0f774c8Skamil 
254a0f774c8Skamil static void
255a0f774c8Skamil traceme_raisesignal_masked(int sigmasked)
256a0f774c8Skamil {
257a0f774c8Skamil 	const int exitval = 5;
258a0f774c8Skamil 	const int sigval = SIGSTOP;
259a0f774c8Skamil 	pid_t child, wpid;
260a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
261a0f774c8Skamil 	int status;
262a0f774c8Skamil #endif
263a0f774c8Skamil 	sigset_t intmask;
264a0f774c8Skamil 	struct ptrace_siginfo info;
265a0f774c8Skamil 
266a0f774c8Skamil 	memset(&info, 0, sizeof(info));
267a0f774c8Skamil 
268a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
269a0f774c8Skamil 	SYSCALL_REQUIRE((child = fork()) != -1);
270a0f774c8Skamil 	if (child == 0) {
271a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
272a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
273a0f774c8Skamil 
274a0f774c8Skamil 		sigemptyset(&intmask);
275a0f774c8Skamil 		sigaddset(&intmask, sigmasked);
276a0f774c8Skamil 		sigprocmask(SIG_BLOCK, &intmask, NULL);
277a0f774c8Skamil 
278a0f774c8Skamil 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
279a0f774c8Skamil 		FORKEE_ASSERT(raise(sigval) == 0);
280a0f774c8Skamil 
281a0f774c8Skamil 		DPRINTF("Before raising %s breakpoint from child\n",
282a0f774c8Skamil 		    strsignal(sigmasked));
283a0f774c8Skamil 		FORKEE_ASSERT(raise(sigmasked) == 0);
284a0f774c8Skamil 
285a0f774c8Skamil 		DPRINTF("Before exiting of the child process\n");
286a0f774c8Skamil 		_exit(exitval);
287a0f774c8Skamil 	}
288a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
289a0f774c8Skamil 
290a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
291a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
292a0f774c8Skamil 
293a0f774c8Skamil 	validate_status_stopped(status, sigval);
294a0f774c8Skamil 
295a0f774c8Skamil 	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
296a0f774c8Skamil 	SYSCALL_REQUIRE(
297a0f774c8Skamil 	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
298a0f774c8Skamil 
299a0f774c8Skamil 	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
300a0f774c8Skamil 	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
301a0f774c8Skamil 	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
302a0f774c8Skamil 	    info.psi_siginfo.si_errno);
303a0f774c8Skamil 
304a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
305a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
306a0f774c8Skamil 
307a0f774c8Skamil 	DPRINTF("Before resuming the child process where it left off and "
308a0f774c8Skamil 	    "without signal to be sent\n");
309a0f774c8Skamil 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
310a0f774c8Skamil 
311a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
312a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
313a0f774c8Skamil 
314a0f774c8Skamil 	validate_status_exited(status, exitval);
315a0f774c8Skamil 
316a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
317a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
318a0f774c8Skamil }
319a0f774c8Skamil 
320a0f774c8Skamil #define TRACEME_RAISESIGNAL_MASKED(test, sig)				\
321a0f774c8Skamil ATF_TC(test);								\
322a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
323a0f774c8Skamil {									\
324a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
325a0f774c8Skamil 	    "Verify that masking (with SIG_BLOCK) " #sig " in tracee "	\
326a0f774c8Skamil 	    "stops tracer from catching this raised signal");		\
327a0f774c8Skamil }									\
328a0f774c8Skamil 									\
329a0f774c8Skamil ATF_TC_BODY(test, tc)							\
330a0f774c8Skamil {									\
331a0f774c8Skamil 									\
332a0f774c8Skamil 	traceme_raisesignal_masked(sig);				\
333a0f774c8Skamil }
334a0f774c8Skamil 
335a0f774c8Skamil // A signal handler for SIGKILL and SIGSTOP cannot be masked.
TRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked1,SIGABRT)336a0f774c8Skamil TRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked1, SIGABRT) /* abort trap */
337a0f774c8Skamil TRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked2, SIGHUP)  /* hangup */
338a0f774c8Skamil TRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked3, SIGCONT) /* continued? */
339a0f774c8Skamil TRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked4, SIGTRAP) /* crash sig. */
340a0f774c8Skamil TRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked5, SIGBUS) /* crash sig. */
341a0f774c8Skamil TRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked6, SIGILL) /* crash sig. */
342a0f774c8Skamil TRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked7, SIGFPE) /* crash sig. */
343a0f774c8Skamil TRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked8, SIGSEGV) /* crash sig. */
344a0f774c8Skamil 
345a0f774c8Skamil /// ----------------------------------------------------------------------------
346a0f774c8Skamil 
347a0f774c8Skamil static void
348a0f774c8Skamil traceme_crash(int sig)
349a0f774c8Skamil {
350a0f774c8Skamil 	pid_t child, wpid;
351a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
352a0f774c8Skamil 	int status;
353a0f774c8Skamil #endif
354a0f774c8Skamil 	struct ptrace_siginfo info;
355a0f774c8Skamil 
356a0f774c8Skamil #ifndef PTRACE_ILLEGAL_ASM
357a0f774c8Skamil 	if (sig == SIGILL)
358a0f774c8Skamil 		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
359a0f774c8Skamil #endif
360a0f774c8Skamil 
361a0f774c8Skamil 	if (sig == SIGFPE && !are_fpu_exceptions_supported())
362a0f774c8Skamil 		atf_tc_skip("FP exceptions are not supported");
363a0f774c8Skamil 
364a0f774c8Skamil 	memset(&info, 0, sizeof(info));
365a0f774c8Skamil 
366a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
367a0f774c8Skamil 	SYSCALL_REQUIRE((child = fork()) != -1);
368a0f774c8Skamil 	if (child == 0) {
369a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
370a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
371a0f774c8Skamil 
372a0f774c8Skamil 		DPRINTF("Before executing a trap\n");
373a0f774c8Skamil 		switch (sig) {
374a0f774c8Skamil 		case SIGTRAP:
375a0f774c8Skamil 			trigger_trap();
376a0f774c8Skamil 			break;
377a0f774c8Skamil 		case SIGSEGV:
378a0f774c8Skamil 			trigger_segv();
379a0f774c8Skamil 			break;
380a0f774c8Skamil 		case SIGILL:
381a0f774c8Skamil 			trigger_ill();
382a0f774c8Skamil 			break;
383a0f774c8Skamil 		case SIGFPE:
384a0f774c8Skamil 			trigger_fpe();
385a0f774c8Skamil 			break;
386a0f774c8Skamil 		case SIGBUS:
387a0f774c8Skamil 			trigger_bus();
388a0f774c8Skamil 			break;
389a0f774c8Skamil 		default:
390a0f774c8Skamil 			/* NOTREACHED */
391a0f774c8Skamil 			FORKEE_ASSERTX(0 && "This shall not be reached");
392a0f774c8Skamil 		}
393a0f774c8Skamil 
394a0f774c8Skamil 		/* NOTREACHED */
395a0f774c8Skamil 		FORKEE_ASSERTX(0 && "This shall not be reached");
396a0f774c8Skamil 	}
397a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
398a0f774c8Skamil 
399a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
400a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
401a0f774c8Skamil 
402a0f774c8Skamil 	validate_status_stopped(status, sig);
403a0f774c8Skamil 
404*7f74343bSsimonb 	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
405a0f774c8Skamil 	SYSCALL_REQUIRE(
406a0f774c8Skamil 	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
407a0f774c8Skamil 
408a0f774c8Skamil 	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
409a0f774c8Skamil 	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
410a0f774c8Skamil 	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
411a0f774c8Skamil 	    info.psi_siginfo.si_errno);
412a0f774c8Skamil 
413a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
414a0f774c8Skamil 	switch (sig) {
415a0f774c8Skamil 	case SIGTRAP:
416a0f774c8Skamil 		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
417a0f774c8Skamil 		break;
418a0f774c8Skamil 	case SIGSEGV:
419a0f774c8Skamil 		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
420a0f774c8Skamil 		break;
421a0f774c8Skamil 	case SIGILL:
422a0f774c8Skamil 		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
423a0f774c8Skamil 		            info.psi_siginfo.si_code <= ILL_BADSTK);
424a0f774c8Skamil 		break;
425a0f774c8Skamil 	case SIGFPE:
426c3c8ab88Srin // XXXQEMU	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_FLTDIV);
427a0f774c8Skamil 		break;
428a0f774c8Skamil 	case SIGBUS:
429a0f774c8Skamil 		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
430a0f774c8Skamil 		break;
431a0f774c8Skamil 	}
432a0f774c8Skamil 
433a0f774c8Skamil 	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
434a0f774c8Skamil 
435a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
436a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
437a0f774c8Skamil 
438a0f774c8Skamil 	validate_status_signaled(status, SIGKILL, 0);
439a0f774c8Skamil 
440a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
441a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
442a0f774c8Skamil }
443a0f774c8Skamil 
444a0f774c8Skamil #define TRACEME_CRASH(test, sig)					\
445a0f774c8Skamil ATF_TC(test);								\
446a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
447a0f774c8Skamil {									\
448a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
449a0f774c8Skamil 	    "Verify crash signal " #sig " in a child after PT_TRACE_ME"); \
450a0f774c8Skamil }									\
451a0f774c8Skamil 									\
452a0f774c8Skamil ATF_TC_BODY(test, tc)							\
453a0f774c8Skamil {									\
454a0f774c8Skamil 									\
455a0f774c8Skamil 	traceme_crash(sig);						\
456a0f774c8Skamil }
457a0f774c8Skamil 
TRACEME_CRASH(traceme_crash_trap,SIGTRAP)458a0f774c8Skamil TRACEME_CRASH(traceme_crash_trap, SIGTRAP)
459a0f774c8Skamil TRACEME_CRASH(traceme_crash_segv, SIGSEGV)
460a0f774c8Skamil TRACEME_CRASH(traceme_crash_ill, SIGILL)
461a0f774c8Skamil TRACEME_CRASH(traceme_crash_fpe, SIGFPE)
462a0f774c8Skamil TRACEME_CRASH(traceme_crash_bus, SIGBUS)
463a0f774c8Skamil 
464a0f774c8Skamil /// ----------------------------------------------------------------------------
465a0f774c8Skamil 
466a0f774c8Skamil static void
467a0f774c8Skamil traceme_signalmasked_crash(int sig)
468a0f774c8Skamil {
469a0f774c8Skamil 	const int sigval = SIGSTOP;
470a0f774c8Skamil 	pid_t child, wpid;
471a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
472a0f774c8Skamil 	int status;
473a0f774c8Skamil #endif
474a0f774c8Skamil 	struct ptrace_siginfo info;
475a0f774c8Skamil 	sigset_t intmask;
476a0f774c8Skamil 	struct kinfo_proc2 kp;
477a0f774c8Skamil 	size_t len = sizeof(kp);
478a0f774c8Skamil 
479a0f774c8Skamil 	int name[6];
480a0f774c8Skamil 	const size_t namelen = __arraycount(name);
481a0f774c8Skamil 	ki_sigset_t kp_sigmask;
482a0f774c8Skamil 
483a0f774c8Skamil #ifndef PTRACE_ILLEGAL_ASM
484a0f774c8Skamil 	if (sig == SIGILL)
485a0f774c8Skamil 		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
486a0f774c8Skamil #endif
487a0f774c8Skamil 
488a0f774c8Skamil 	if (sig == SIGFPE && !are_fpu_exceptions_supported())
489a0f774c8Skamil 		atf_tc_skip("FP exceptions are not supported");
490a0f774c8Skamil 
491a0f774c8Skamil 	memset(&info, 0, sizeof(info));
492a0f774c8Skamil 
493a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
494a0f774c8Skamil 	SYSCALL_REQUIRE((child = fork()) != -1);
495a0f774c8Skamil 	if (child == 0) {
496a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
497a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
498a0f774c8Skamil 
499a0f774c8Skamil 		sigemptyset(&intmask);
500a0f774c8Skamil 		sigaddset(&intmask, sig);
501a0f774c8Skamil 		sigprocmask(SIG_BLOCK, &intmask, NULL);
502a0f774c8Skamil 
503a0f774c8Skamil 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
504a0f774c8Skamil 		FORKEE_ASSERT(raise(sigval) == 0);
505a0f774c8Skamil 
506a0f774c8Skamil 		DPRINTF("Before executing a trap\n");
507a0f774c8Skamil 		switch (sig) {
508a0f774c8Skamil 		case SIGTRAP:
509a0f774c8Skamil 			trigger_trap();
510a0f774c8Skamil 			break;
511a0f774c8Skamil 		case SIGSEGV:
512a0f774c8Skamil 			trigger_segv();
513a0f774c8Skamil 			break;
514a0f774c8Skamil 		case SIGILL:
515a0f774c8Skamil 			trigger_ill();
516a0f774c8Skamil 			break;
517a0f774c8Skamil 		case SIGFPE:
518a0f774c8Skamil 			trigger_fpe();
519a0f774c8Skamil 			break;
520a0f774c8Skamil 		case SIGBUS:
521a0f774c8Skamil 			trigger_bus();
522a0f774c8Skamil 			break;
523a0f774c8Skamil 		default:
524a0f774c8Skamil 			/* NOTREACHED */
525a0f774c8Skamil 			FORKEE_ASSERTX(0 && "This shall not be reached");
526a0f774c8Skamil 		}
527a0f774c8Skamil 
528a0f774c8Skamil 		/* NOTREACHED */
529a0f774c8Skamil 		FORKEE_ASSERTX(0 && "This shall not be reached");
530a0f774c8Skamil 	}
531a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
532a0f774c8Skamil 
533a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
534a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
535a0f774c8Skamil 
536a0f774c8Skamil 	validate_status_stopped(status, sigval);
537a0f774c8Skamil 
538a0f774c8Skamil 	name[0] = CTL_KERN,
539a0f774c8Skamil 	name[1] = KERN_PROC2,
540a0f774c8Skamil 	name[2] = KERN_PROC_PID;
541a0f774c8Skamil 	name[3] = child;
542a0f774c8Skamil 	name[4] = sizeof(kp);
543a0f774c8Skamil 	name[5] = 1;
544a0f774c8Skamil 
545a0f774c8Skamil 	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
546a0f774c8Skamil 
547a0f774c8Skamil 	kp_sigmask = kp.p_sigmask;
548a0f774c8Skamil 
549a0f774c8Skamil 	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
550a0f774c8Skamil 	SYSCALL_REQUIRE(
551a0f774c8Skamil 	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
552a0f774c8Skamil 
553a0f774c8Skamil 	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
554a0f774c8Skamil 	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
555a0f774c8Skamil 	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
556a0f774c8Skamil 	    info.psi_siginfo.si_errno);
557a0f774c8Skamil 
558a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
559a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
560a0f774c8Skamil 
561a0f774c8Skamil 	DPRINTF("Before resuming the child process where it left off and "
562a0f774c8Skamil 	    "without signal to be sent\n");
563a0f774c8Skamil 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
564a0f774c8Skamil 
565a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
566a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
567a0f774c8Skamil 
568a0f774c8Skamil 	validate_status_stopped(status, sig);
569a0f774c8Skamil 
570*7f74343bSsimonb 	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
571a0f774c8Skamil 	SYSCALL_REQUIRE(
572a0f774c8Skamil 	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
573a0f774c8Skamil 
574a0f774c8Skamil 	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
575a0f774c8Skamil 	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
576a0f774c8Skamil 	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
577a0f774c8Skamil 	    info.psi_siginfo.si_errno);
578a0f774c8Skamil 
579a0f774c8Skamil 	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
580a0f774c8Skamil 
581a0f774c8Skamil 	DPRINTF("kp_sigmask="
582a0f774c8Skamil 	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
583a0f774c8Skamil 	    kp_sigmask.__bits[0], kp_sigmask.__bits[1], kp_sigmask.__bits[2],
584a0f774c8Skamil 	    kp_sigmask.__bits[3]);
585a0f774c8Skamil 
586a0f774c8Skamil 	DPRINTF("kp.p_sigmask="
587a0f774c8Skamil 	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
588a0f774c8Skamil 	    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
589a0f774c8Skamil 	    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
590a0f774c8Skamil 
591a0f774c8Skamil 	ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask, sizeof(kp_sigmask)));
592a0f774c8Skamil 
593a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
594a0f774c8Skamil 	switch (sig) {
595a0f774c8Skamil 	case SIGTRAP:
596a0f774c8Skamil 		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
597a0f774c8Skamil 		break;
598a0f774c8Skamil 	case SIGSEGV:
599a0f774c8Skamil 		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
600a0f774c8Skamil 		break;
601a0f774c8Skamil 	case SIGILL:
602a0f774c8Skamil 		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
603a0f774c8Skamil 		            info.psi_siginfo.si_code <= ILL_BADSTK);
604a0f774c8Skamil 		break;
605a0f774c8Skamil 	case SIGFPE:
606c3c8ab88Srin // XXXQEMU	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_FLTDIV);
607a0f774c8Skamil 		break;
608a0f774c8Skamil 	case SIGBUS:
609a0f774c8Skamil 		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
610a0f774c8Skamil 		break;
611a0f774c8Skamil 	}
612a0f774c8Skamil 
613a0f774c8Skamil 	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
614a0f774c8Skamil 
615a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
616a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
617a0f774c8Skamil 
618a0f774c8Skamil 	validate_status_signaled(status, SIGKILL, 0);
619a0f774c8Skamil 
620a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
621a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
622a0f774c8Skamil }
623a0f774c8Skamil 
624a0f774c8Skamil #define TRACEME_SIGNALMASKED_CRASH(test, sig)				\
625a0f774c8Skamil ATF_TC(test);								\
626a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
627a0f774c8Skamil {									\
628a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
629a0f774c8Skamil 	    "Verify masked crash signal " #sig " in a child after "	\
630a0f774c8Skamil 	    "PT_TRACE_ME is delivered to its tracer");			\
631a0f774c8Skamil }									\
632a0f774c8Skamil 									\
633a0f774c8Skamil ATF_TC_BODY(test, tc)							\
634a0f774c8Skamil {									\
635a0f774c8Skamil 									\
636a0f774c8Skamil 	traceme_signalmasked_crash(sig);				\
637a0f774c8Skamil }
638a0f774c8Skamil 
TRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_trap,SIGTRAP)639a0f774c8Skamil TRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_trap, SIGTRAP)
640a0f774c8Skamil TRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_segv, SIGSEGV)
641a0f774c8Skamil TRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_ill, SIGILL)
642a0f774c8Skamil TRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_fpe, SIGFPE)
643a0f774c8Skamil TRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_bus, SIGBUS)
644a0f774c8Skamil 
645a0f774c8Skamil /// ----------------------------------------------------------------------------
646a0f774c8Skamil 
647a0f774c8Skamil static void
648a0f774c8Skamil traceme_signalignored_crash(int sig)
649a0f774c8Skamil {
650a0f774c8Skamil 	const int sigval = SIGSTOP;
651a0f774c8Skamil 	pid_t child, wpid;
652a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
653a0f774c8Skamil 	int status;
654a0f774c8Skamil #endif
655a0f774c8Skamil 	struct sigaction sa;
656a0f774c8Skamil 	struct ptrace_siginfo info;
657a0f774c8Skamil 	struct kinfo_proc2 kp;
658a0f774c8Skamil 	size_t len = sizeof(kp);
659a0f774c8Skamil 
660a0f774c8Skamil 	int name[6];
661a0f774c8Skamil 	const size_t namelen = __arraycount(name);
662a0f774c8Skamil 	ki_sigset_t kp_sigignore;
663a0f774c8Skamil 
664a0f774c8Skamil #ifndef PTRACE_ILLEGAL_ASM
665a0f774c8Skamil 	if (sig == SIGILL)
666a0f774c8Skamil 		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
667a0f774c8Skamil #endif
668a0f774c8Skamil 
669a0f774c8Skamil 	if (sig == SIGFPE && !are_fpu_exceptions_supported())
670a0f774c8Skamil 		atf_tc_skip("FP exceptions are not supported");
671a0f774c8Skamil 
672a0f774c8Skamil 	memset(&info, 0, sizeof(info));
673a0f774c8Skamil 
674a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
675a0f774c8Skamil 	SYSCALL_REQUIRE((child = fork()) != -1);
676a0f774c8Skamil 	if (child == 0) {
677a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
678a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
679a0f774c8Skamil 
680a0f774c8Skamil 		memset(&sa, 0, sizeof(sa));
681a0f774c8Skamil 		sa.sa_handler = SIG_IGN;
682a0f774c8Skamil 		sigemptyset(&sa.sa_mask);
683a0f774c8Skamil 
684a0f774c8Skamil 		FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
685a0f774c8Skamil 
686a0f774c8Skamil 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
687a0f774c8Skamil 		FORKEE_ASSERT(raise(sigval) == 0);
688a0f774c8Skamil 
689a0f774c8Skamil 		DPRINTF("Before executing a trap\n");
690a0f774c8Skamil 		switch (sig) {
691a0f774c8Skamil 		case SIGTRAP:
692a0f774c8Skamil 			trigger_trap();
693a0f774c8Skamil 			break;
694a0f774c8Skamil 		case SIGSEGV:
695a0f774c8Skamil 			trigger_segv();
696a0f774c8Skamil 			break;
697a0f774c8Skamil 		case SIGILL:
698a0f774c8Skamil 			trigger_ill();
699a0f774c8Skamil 			break;
700a0f774c8Skamil 		case SIGFPE:
701a0f774c8Skamil 			trigger_fpe();
702a0f774c8Skamil 			break;
703a0f774c8Skamil 		case SIGBUS:
704a0f774c8Skamil 			trigger_bus();
705a0f774c8Skamil 			break;
706a0f774c8Skamil 		default:
707a0f774c8Skamil 			/* NOTREACHED */
708a0f774c8Skamil 			FORKEE_ASSERTX(0 && "This shall not be reached");
709a0f774c8Skamil 		}
710a0f774c8Skamil 
711a0f774c8Skamil 		/* NOTREACHED */
712a0f774c8Skamil 		FORKEE_ASSERTX(0 && "This shall not be reached");
713a0f774c8Skamil 	}
714a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
715a0f774c8Skamil 
716a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
717a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
718a0f774c8Skamil 
719a0f774c8Skamil 	validate_status_stopped(status, sigval);
720a0f774c8Skamil 
721a0f774c8Skamil 	name[0] = CTL_KERN,
722a0f774c8Skamil 	name[1] = KERN_PROC2,
723a0f774c8Skamil 	name[2] = KERN_PROC_PID;
724a0f774c8Skamil 	name[3] = child;
725a0f774c8Skamil 	name[4] = sizeof(kp);
726a0f774c8Skamil 	name[5] = 1;
727a0f774c8Skamil 
728a0f774c8Skamil 	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
729a0f774c8Skamil 
730a0f774c8Skamil 	kp_sigignore = kp.p_sigignore;
731a0f774c8Skamil 
732a0f774c8Skamil 	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
733a0f774c8Skamil 	SYSCALL_REQUIRE(
734a0f774c8Skamil 	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
735a0f774c8Skamil 
736a0f774c8Skamil 	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
737a0f774c8Skamil 	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
738a0f774c8Skamil 	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
739a0f774c8Skamil 	    info.psi_siginfo.si_errno);
740a0f774c8Skamil 
741a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
742a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
743a0f774c8Skamil 
744a0f774c8Skamil 	DPRINTF("Before resuming the child process where it left off and "
745a0f774c8Skamil 	    "without signal to be sent\n");
746a0f774c8Skamil 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
747a0f774c8Skamil 
748a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
749a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
750a0f774c8Skamil 
751a0f774c8Skamil 	validate_status_stopped(status, sig);
752a0f774c8Skamil 
753*7f74343bSsimonb 	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
754a0f774c8Skamil 	SYSCALL_REQUIRE(
755a0f774c8Skamil 	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
756a0f774c8Skamil 
757a0f774c8Skamil 	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
758a0f774c8Skamil 	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
759a0f774c8Skamil 	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
760a0f774c8Skamil 	    info.psi_siginfo.si_errno);
761a0f774c8Skamil 
762a0f774c8Skamil 	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
763a0f774c8Skamil 
764a0f774c8Skamil 	DPRINTF("kp_sigignore="
765a0f774c8Skamil 	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
766a0f774c8Skamil 	    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
767a0f774c8Skamil 	    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
768a0f774c8Skamil 
769a0f774c8Skamil 	DPRINTF("kp.p_sigignore="
770a0f774c8Skamil 	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
771a0f774c8Skamil 	    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
772a0f774c8Skamil 	    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
773a0f774c8Skamil 
774a0f774c8Skamil 	ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore, sizeof(kp_sigignore)));
775a0f774c8Skamil 
776a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
777a0f774c8Skamil 	switch (sig) {
778a0f774c8Skamil 	case SIGTRAP:
779a0f774c8Skamil 		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
780a0f774c8Skamil 		break;
781a0f774c8Skamil 	case SIGSEGV:
782a0f774c8Skamil 		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
783a0f774c8Skamil 		break;
784a0f774c8Skamil 	case SIGILL:
785a0f774c8Skamil 		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
786a0f774c8Skamil 		            info.psi_siginfo.si_code <= ILL_BADSTK);
787a0f774c8Skamil 		break;
788a0f774c8Skamil 	case SIGFPE:
789c3c8ab88Srin // XXXQEMU	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_FLTDIV);
790a0f774c8Skamil 		break;
791a0f774c8Skamil 	case SIGBUS:
792a0f774c8Skamil 		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
793a0f774c8Skamil 		break;
794a0f774c8Skamil 	}
795a0f774c8Skamil 
796a0f774c8Skamil 	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
797a0f774c8Skamil 
798a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
799a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
800a0f774c8Skamil 
801a0f774c8Skamil 	validate_status_signaled(status, SIGKILL, 0);
802a0f774c8Skamil 
803a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
804a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
805a0f774c8Skamil }
806a0f774c8Skamil 
807a0f774c8Skamil #define TRACEME_SIGNALIGNORED_CRASH(test, sig)				\
808a0f774c8Skamil ATF_TC(test);								\
809a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
810a0f774c8Skamil {									\
811a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
812a0f774c8Skamil 	    "Verify ignored crash signal " #sig " in a child after "	\
813a0f774c8Skamil 	    "PT_TRACE_ME is delivered to its tracer"); 			\
814a0f774c8Skamil }									\
815a0f774c8Skamil 									\
816a0f774c8Skamil ATF_TC_BODY(test, tc)							\
817a0f774c8Skamil {									\
818a0f774c8Skamil 									\
819a0f774c8Skamil 	traceme_signalignored_crash(sig);				\
820a0f774c8Skamil }
821a0f774c8Skamil 
TRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_trap,SIGTRAP)822a0f774c8Skamil TRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_trap, SIGTRAP)
823a0f774c8Skamil TRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_segv, SIGSEGV)
824a0f774c8Skamil TRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_ill, SIGILL)
825a0f774c8Skamil TRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_fpe, SIGFPE)
826a0f774c8Skamil TRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_bus, SIGBUS)
827a0f774c8Skamil 
828a0f774c8Skamil /// ----------------------------------------------------------------------------
829a0f774c8Skamil 
830a0f774c8Skamil static void
831a0f774c8Skamil traceme_sendsignal_handle(int sigsent, void (*sah)(int a), int *traceme_caught)
832a0f774c8Skamil {
833a0f774c8Skamil 	const int exitval = 5;
834a0f774c8Skamil 	const int sigval = SIGSTOP;
835a0f774c8Skamil 	pid_t child, wpid;
836a0f774c8Skamil 	struct sigaction sa;
837a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
838a0f774c8Skamil 	int status;
839a0f774c8Skamil #endif
840a0f774c8Skamil 	struct ptrace_siginfo info;
841a0f774c8Skamil 
842a0f774c8Skamil 	memset(&info, 0, sizeof(info));
843a0f774c8Skamil 
844a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
845a0f774c8Skamil 	SYSCALL_REQUIRE((child = fork()) != -1);
846a0f774c8Skamil 	if (child == 0) {
847a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
848a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
849a0f774c8Skamil 
850a0f774c8Skamil 		sa.sa_handler = sah;
851a0f774c8Skamil 		sa.sa_flags = SA_SIGINFO;
852a0f774c8Skamil 		sigemptyset(&sa.sa_mask);
853a0f774c8Skamil 
854a0f774c8Skamil 		FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
855a0f774c8Skamil 
856a0f774c8Skamil 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
857a0f774c8Skamil 		FORKEE_ASSERT(raise(sigval) == 0);
858a0f774c8Skamil 
859a0f774c8Skamil 		FORKEE_ASSERT_EQ(*traceme_caught, 1);
860a0f774c8Skamil 
861a0f774c8Skamil 		DPRINTF("Before exiting of the child process\n");
862a0f774c8Skamil 		_exit(exitval);
863a0f774c8Skamil 	}
864a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
865a0f774c8Skamil 
866a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
867a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
868a0f774c8Skamil 
869a0f774c8Skamil 	validate_status_stopped(status, sigval);
870a0f774c8Skamil 
871a0f774c8Skamil 	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
872a0f774c8Skamil 	SYSCALL_REQUIRE(
873a0f774c8Skamil 	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
874a0f774c8Skamil 
875a0f774c8Skamil 	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
876a0f774c8Skamil 	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
877a0f774c8Skamil 	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
878a0f774c8Skamil 	    info.psi_siginfo.si_errno);
879a0f774c8Skamil 
880a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
881a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
882a0f774c8Skamil 
883a0f774c8Skamil 	DPRINTF("Before resuming the child process where it left off and with "
884a0f774c8Skamil 	    "signal %s to be sent\n", strsignal(sigsent));
885a0f774c8Skamil 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
886a0f774c8Skamil 
887a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
888a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
889a0f774c8Skamil 
890a0f774c8Skamil 	validate_status_exited(status, exitval);
891a0f774c8Skamil 
892a0f774c8Skamil 	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
893a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
894a0f774c8Skamil }
895a0f774c8Skamil 
896a0f774c8Skamil #define TRACEME_SENDSIGNAL_HANDLE(test, sig)				\
897a0f774c8Skamil ATF_TC(test);								\
898a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
899a0f774c8Skamil {									\
900a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
901a0f774c8Skamil 	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
902a0f774c8Skamil 	    "handled correctly and caught by a signal handler");	\
903a0f774c8Skamil }									\
904a0f774c8Skamil 									\
905a0f774c8Skamil static int test##_caught = 0;						\
906a0f774c8Skamil 									\
907a0f774c8Skamil static void								\
908a0f774c8Skamil test##_sighandler(int arg)						\
909a0f774c8Skamil {									\
910a0f774c8Skamil 	FORKEE_ASSERT_EQ(arg, sig);					\
911a0f774c8Skamil 									\
912a0f774c8Skamil 	++ test##_caught;						\
913a0f774c8Skamil }									\
914a0f774c8Skamil 									\
915a0f774c8Skamil ATF_TC_BODY(test, tc)							\
916a0f774c8Skamil {									\
917a0f774c8Skamil 									\
918a0f774c8Skamil 	traceme_sendsignal_handle(sig, test##_sighandler, & test##_caught); \
919a0f774c8Skamil }
920a0f774c8Skamil 
921a0f774c8Skamil // A signal handler for SIGKILL and SIGSTOP cannot be registered.
TRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle1,SIGABRT)922a0f774c8Skamil TRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle1, SIGABRT) /* abort trap */
923a0f774c8Skamil TRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle2, SIGHUP)  /* hangup */
924a0f774c8Skamil TRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle3, SIGCONT) /* continued? */
925a0f774c8Skamil TRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle4, SIGTRAP) /* crash sig. */
926a0f774c8Skamil TRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle5, SIGBUS) /* crash sig. */
927a0f774c8Skamil TRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle6, SIGILL) /* crash sig. */
928a0f774c8Skamil TRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle7, SIGFPE) /* crash sig. */
929a0f774c8Skamil TRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle8, SIGSEGV) /* crash sig. */
930a0f774c8Skamil 
931a0f774c8Skamil /// ----------------------------------------------------------------------------
932a0f774c8Skamil 
933a0f774c8Skamil static void
934a0f774c8Skamil traceme_sendsignal_masked(int sigsent)
935a0f774c8Skamil {
936a0f774c8Skamil 	const int exitval = 5;
937a0f774c8Skamil 	const int sigval = SIGSTOP;
938a0f774c8Skamil 	pid_t child, wpid;
939a0f774c8Skamil 	sigset_t set;
940a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
941a0f774c8Skamil 	int status;
942a0f774c8Skamil #endif
943a0f774c8Skamil 	struct ptrace_siginfo info;
944a0f774c8Skamil 
945a0f774c8Skamil 	memset(&info, 0, sizeof(info));
946a0f774c8Skamil 
947a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
948a0f774c8Skamil 	SYSCALL_REQUIRE((child = fork()) != -1);
949a0f774c8Skamil 	if (child == 0) {
950a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
951a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
952a0f774c8Skamil 
953a0f774c8Skamil 		sigemptyset(&set);
954a0f774c8Skamil 		sigaddset(&set, sigsent);
955a0f774c8Skamil 		FORKEE_ASSERT(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
956a0f774c8Skamil 
957a0f774c8Skamil 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
958a0f774c8Skamil 		FORKEE_ASSERT(raise(sigval) == 0);
959a0f774c8Skamil 
960a0f774c8Skamil 		_exit(exitval);
961a0f774c8Skamil 	}
962a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
963a0f774c8Skamil 
964a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
965a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
966a0f774c8Skamil 
967a0f774c8Skamil 	validate_status_stopped(status, sigval);
968a0f774c8Skamil 
969a0f774c8Skamil 	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
970a0f774c8Skamil 	SYSCALL_REQUIRE(
971a0f774c8Skamil 	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
972a0f774c8Skamil 
973a0f774c8Skamil 	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
974a0f774c8Skamil 	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
975a0f774c8Skamil 	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
976a0f774c8Skamil 	    info.psi_siginfo.si_errno);
977a0f774c8Skamil 
978a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
979a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
980a0f774c8Skamil 
981a0f774c8Skamil 	DPRINTF("Before resuming the child process where it left off and with "
982a0f774c8Skamil 	    "signal %s to be sent\n", strsignal(sigsent));
983a0f774c8Skamil 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
984a0f774c8Skamil 
985a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
986a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
987a0f774c8Skamil 
988a0f774c8Skamil 	validate_status_exited(status, exitval);
989a0f774c8Skamil 
990a0f774c8Skamil 	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
991a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
992a0f774c8Skamil }
993a0f774c8Skamil 
994a0f774c8Skamil #define TRACEME_SENDSIGNAL_MASKED(test, sig)				\
995a0f774c8Skamil ATF_TC(test);								\
996a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
997a0f774c8Skamil {									\
998a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
999a0f774c8Skamil 	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
1000a0f774c8Skamil 	    "handled correctly and the signal is masked by SIG_BLOCK");	\
1001a0f774c8Skamil }									\
1002a0f774c8Skamil 									\
1003a0f774c8Skamil ATF_TC_BODY(test, tc)							\
1004a0f774c8Skamil {									\
1005a0f774c8Skamil 									\
1006a0f774c8Skamil 	traceme_sendsignal_masked(sig);					\
1007a0f774c8Skamil }
1008a0f774c8Skamil 
1009a0f774c8Skamil // A signal handler for SIGKILL and SIGSTOP cannot be masked.
TRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked1,SIGABRT)1010a0f774c8Skamil TRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked1, SIGABRT) /* abort trap */
1011a0f774c8Skamil TRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked2, SIGHUP)  /* hangup */
1012a0f774c8Skamil TRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked3, SIGCONT) /* continued? */
1013a0f774c8Skamil TRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked4, SIGTRAP) /* crash sig. */
1014a0f774c8Skamil TRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked5, SIGBUS) /* crash sig. */
1015a0f774c8Skamil TRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked6, SIGILL) /* crash sig. */
1016a0f774c8Skamil TRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked7, SIGFPE) /* crash sig. */
1017a0f774c8Skamil TRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked8, SIGSEGV) /* crash sig. */
1018a0f774c8Skamil 
1019a0f774c8Skamil /// ----------------------------------------------------------------------------
1020a0f774c8Skamil 
1021a0f774c8Skamil static void
1022a0f774c8Skamil traceme_sendsignal_ignored(int sigsent)
1023a0f774c8Skamil {
1024a0f774c8Skamil 	const int exitval = 5;
1025a0f774c8Skamil 	const int sigval = SIGSTOP;
1026a0f774c8Skamil 	pid_t child, wpid;
1027a0f774c8Skamil 	struct sigaction sa;
1028a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
1029a0f774c8Skamil 	int status;
1030a0f774c8Skamil #endif
1031a0f774c8Skamil 	struct ptrace_siginfo info;
1032a0f774c8Skamil 
1033a0f774c8Skamil 	memset(&info, 0, sizeof(info));
1034a0f774c8Skamil 
1035a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
1036a0f774c8Skamil 	SYSCALL_REQUIRE((child = fork()) != -1);
1037a0f774c8Skamil 	if (child == 0) {
1038a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1039a0f774c8Skamil 
1040a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
1041a0f774c8Skamil 
1042a0f774c8Skamil 		memset(&sa, 0, sizeof(sa));
1043a0f774c8Skamil 		sa.sa_handler = SIG_IGN;
1044a0f774c8Skamil 		sigemptyset(&sa.sa_mask);
1045a0f774c8Skamil 		FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
1046a0f774c8Skamil 
1047a0f774c8Skamil 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
1048a0f774c8Skamil 		FORKEE_ASSERT(raise(sigval) == 0);
1049a0f774c8Skamil 
1050a0f774c8Skamil 		_exit(exitval);
1051a0f774c8Skamil 	}
1052a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
1053a0f774c8Skamil 
1054a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1055a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
1056a0f774c8Skamil 
1057a0f774c8Skamil 	validate_status_stopped(status, sigval);
1058a0f774c8Skamil 
1059a0f774c8Skamil 	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
1060a0f774c8Skamil 	SYSCALL_REQUIRE(
1061a0f774c8Skamil 	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
1062a0f774c8Skamil 
1063a0f774c8Skamil 	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
1064a0f774c8Skamil 	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
1065a0f774c8Skamil 	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
1066a0f774c8Skamil 	    info.psi_siginfo.si_errno);
1067a0f774c8Skamil 
1068a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
1069a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
1070a0f774c8Skamil 
1071a0f774c8Skamil 	DPRINTF("Before resuming the child process where it left off and with "
1072a0f774c8Skamil 	    "signal %s to be sent\n", strsignal(sigsent));
1073a0f774c8Skamil 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
1074a0f774c8Skamil 
1075a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1076a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
1077a0f774c8Skamil 
1078a0f774c8Skamil 	validate_status_exited(status, exitval);
1079a0f774c8Skamil 
1080a0f774c8Skamil 	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
1081a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
1082a0f774c8Skamil }
1083a0f774c8Skamil 
1084a0f774c8Skamil #define TRACEME_SENDSIGNAL_IGNORED(test, sig)				\
1085a0f774c8Skamil ATF_TC(test);								\
1086a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
1087a0f774c8Skamil {									\
1088a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
1089a0f774c8Skamil 	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
1090a0f774c8Skamil 	    "handled correctly and the signal is masked by SIG_IGN");	\
1091a0f774c8Skamil }									\
1092a0f774c8Skamil 									\
1093a0f774c8Skamil ATF_TC_BODY(test, tc)							\
1094a0f774c8Skamil {									\
1095a0f774c8Skamil 									\
1096a0f774c8Skamil 	traceme_sendsignal_ignored(sig);				\
1097a0f774c8Skamil }
1098a0f774c8Skamil 
1099a0f774c8Skamil // A signal handler for SIGKILL and SIGSTOP cannot be ignored.
TRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored1,SIGABRT)1100a0f774c8Skamil TRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored1, SIGABRT) /* abort */
1101a0f774c8Skamil TRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored2, SIGHUP)  /* hangup */
1102a0f774c8Skamil TRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored3, SIGCONT) /* continued */
1103a0f774c8Skamil TRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored4, SIGTRAP) /* crash s. */
1104a0f774c8Skamil TRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored5, SIGBUS) /* crash s. */
1105a0f774c8Skamil TRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored6, SIGILL) /* crash s. */
1106a0f774c8Skamil TRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored7, SIGFPE) /* crash s. */
1107a0f774c8Skamil TRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored8, SIGSEGV) /* crash s. */
1108a0f774c8Skamil 
1109a0f774c8Skamil /// ----------------------------------------------------------------------------
1110a0f774c8Skamil 
1111a0f774c8Skamil static void
1112a0f774c8Skamil traceme_sendsignal_simple(int sigsent)
1113a0f774c8Skamil {
1114a0f774c8Skamil 	const int sigval = SIGSTOP;
1115a0f774c8Skamil 	int exitval = 0;
1116a0f774c8Skamil 	pid_t child, wpid;
1117a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
1118a0f774c8Skamil 	int status;
1119a0f774c8Skamil 	int expect_core;
1120a0f774c8Skamil 
1121a0f774c8Skamil 	switch (sigsent) {
1122a0f774c8Skamil 	case SIGABRT:
1123a0f774c8Skamil 	case SIGTRAP:
1124a0f774c8Skamil 	case SIGBUS:
1125a0f774c8Skamil 	case SIGILL:
1126a0f774c8Skamil 	case SIGFPE:
1127a0f774c8Skamil 	case SIGSEGV:
1128a0f774c8Skamil 		expect_core = 1;
1129a0f774c8Skamil 		break;
1130a0f774c8Skamil 	default:
1131a0f774c8Skamil 		expect_core = 0;
1132a0f774c8Skamil 		break;
1133a0f774c8Skamil 	}
1134a0f774c8Skamil #endif
1135a0f774c8Skamil 	struct ptrace_siginfo info;
1136a0f774c8Skamil 
1137a0f774c8Skamil 	memset(&info, 0, sizeof(info));
1138a0f774c8Skamil 
1139a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
1140a0f774c8Skamil 	SYSCALL_REQUIRE((child = fork()) != -1);
1141a0f774c8Skamil 	if (child == 0) {
1142a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1143a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
1144a0f774c8Skamil 
1145a0f774c8Skamil 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
1146a0f774c8Skamil 		FORKEE_ASSERT(raise(sigval) == 0);
1147a0f774c8Skamil 
1148a0f774c8Skamil 		switch (sigsent) {
1149a0f774c8Skamil 		case SIGCONT:
1150a0f774c8Skamil 		case SIGSTOP:
1151a0f774c8Skamil 			_exit(exitval);
1152a0f774c8Skamil 		default:
1153a0f774c8Skamil 			/* NOTREACHED */
1154a0f774c8Skamil 			FORKEE_ASSERTX(0 && "This shall not be reached");
1155a0f774c8Skamil 		}
1156a0f774c8Skamil 	}
1157a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
1158a0f774c8Skamil 
1159a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1160a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
1161a0f774c8Skamil 
1162a0f774c8Skamil 	validate_status_stopped(status, sigval);
1163a0f774c8Skamil 
1164a0f774c8Skamil 	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
1165a0f774c8Skamil 	SYSCALL_REQUIRE(
1166a0f774c8Skamil 	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
1167a0f774c8Skamil 
1168a0f774c8Skamil 	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
1169a0f774c8Skamil 	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
1170a0f774c8Skamil 	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
1171a0f774c8Skamil 	    info.psi_siginfo.si_errno);
1172a0f774c8Skamil 
1173a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
1174a0f774c8Skamil 	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
1175a0f774c8Skamil 
1176a0f774c8Skamil 	DPRINTF("Before resuming the child process where it left off and with "
1177a0f774c8Skamil 	    "signal %s to be sent\n", strsignal(sigsent));
1178a0f774c8Skamil 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
1179a0f774c8Skamil 
1180a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1181a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
1182a0f774c8Skamil 
1183a0f774c8Skamil 	switch (sigsent) {
1184a0f774c8Skamil 	case SIGSTOP:
1185a0f774c8Skamil 		validate_status_stopped(status, sigsent);
1186a0f774c8Skamil 		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
1187a0f774c8Skamil 		    "child\n");
1188a0f774c8Skamil 		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
1189a0f774c8Skamil 		    sizeof(info)) != -1);
1190a0f774c8Skamil 
1191a0f774c8Skamil 		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
1192a0f774c8Skamil 		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
1193a0f774c8Skamil 		    "si_errno=%#x\n",
1194a0f774c8Skamil 		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
1195a0f774c8Skamil 		    info.psi_siginfo.si_errno);
1196a0f774c8Skamil 
1197a0f774c8Skamil 		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
1198a0f774c8Skamil 		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
1199a0f774c8Skamil 
1200a0f774c8Skamil 		DPRINTF("Before resuming the child process where it left off "
1201a0f774c8Skamil 		    "and with signal %s to be sent\n", strsignal(sigsent));
1202a0f774c8Skamil 		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
1203a0f774c8Skamil 
1204a0f774c8Skamil 		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1205a0f774c8Skamil 		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
1206a0f774c8Skamil 		    child);
1207a0f774c8Skamil 		/* FALLTHROUGH */
1208a0f774c8Skamil 	case SIGCONT:
1209a0f774c8Skamil 		validate_status_exited(status, exitval);
1210a0f774c8Skamil 		break;
1211a0f774c8Skamil 	default:
1212a0f774c8Skamil 		validate_status_signaled(status, sigsent, expect_core);
1213a0f774c8Skamil 		break;
1214a0f774c8Skamil 	}
1215a0f774c8Skamil 
1216a0f774c8Skamil 	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
1217a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
1218a0f774c8Skamil }
1219a0f774c8Skamil 
1220a0f774c8Skamil #define TRACEME_SENDSIGNAL_SIMPLE(test, sig)				\
1221a0f774c8Skamil ATF_TC(test);								\
1222a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
1223a0f774c8Skamil {									\
1224a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
1225a0f774c8Skamil 	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
1226a0f774c8Skamil 	    "handled correctly in a child without a signal handler");	\
1227a0f774c8Skamil }									\
1228a0f774c8Skamil 									\
1229a0f774c8Skamil ATF_TC_BODY(test, tc)							\
1230a0f774c8Skamil {									\
1231a0f774c8Skamil 									\
1232a0f774c8Skamil 	traceme_sendsignal_simple(sig);					\
1233a0f774c8Skamil }
1234a0f774c8Skamil 
TRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple1,SIGKILL)1235a0f774c8Skamil TRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple1, SIGKILL) /* non-maskable*/
1236a0f774c8Skamil TRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple2, SIGSTOP) /* non-maskable*/
1237a0f774c8Skamil TRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple3, SIGABRT) /* abort trap */
1238a0f774c8Skamil TRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple4, SIGHUP)  /* hangup */
1239a0f774c8Skamil TRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple5, SIGCONT) /* continued? */
1240a0f774c8Skamil TRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple6, SIGTRAP) /* crash sig. */
1241a0f774c8Skamil TRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple7, SIGBUS) /* crash sig. */
1242a0f774c8Skamil TRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple8, SIGILL) /* crash sig. */
1243a0f774c8Skamil TRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple9, SIGFPE) /* crash sig. */
1244a0f774c8Skamil TRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple10, SIGSEGV) /* crash sig. */
1245a0f774c8Skamil 
1246a0f774c8Skamil /// ----------------------------------------------------------------------------
1247a0f774c8Skamil 
1248a0f774c8Skamil static void
1249a0f774c8Skamil traceme_vfork_raise(int sigval)
1250a0f774c8Skamil {
1251a0f774c8Skamil 	const int exitval = 5, exitval_watcher = 10;
1252a0f774c8Skamil 	pid_t child, parent, watcher, wpid;
1253a0f774c8Skamil 	int rv;
1254a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
1255a0f774c8Skamil 	int status;
1256a0f774c8Skamil 
1257a0f774c8Skamil 	/* volatile workarounds GCC -Werror=clobbered */
1258a0f774c8Skamil 	volatile int expect_core;
1259a0f774c8Skamil 
1260a0f774c8Skamil 	switch (sigval) {
1261a0f774c8Skamil 	case SIGABRT:
1262a0f774c8Skamil 	case SIGTRAP:
1263a0f774c8Skamil 	case SIGBUS:
1264a0f774c8Skamil 	case SIGILL:
1265a0f774c8Skamil 	case SIGFPE:
1266a0f774c8Skamil 	case SIGSEGV:
1267a0f774c8Skamil 		expect_core = 1;
1268a0f774c8Skamil 		break;
1269a0f774c8Skamil 	default:
1270a0f774c8Skamil 		expect_core = 0;
1271a0f774c8Skamil 		break;
1272a0f774c8Skamil 	}
1273a0f774c8Skamil #endif
1274a0f774c8Skamil 
1275a0f774c8Skamil 	/*
1276a0f774c8Skamil 	 * Spawn a dedicated thread to watch for a stopped child and emit
1277a0f774c8Skamil 	 * the SIGKILL signal to it.
1278a0f774c8Skamil 	 *
1279a0f774c8Skamil 	 * vfork(2) might clobber watcher, this means that it's safer and
1280a0f774c8Skamil 	 * simpler to reparent this process to initproc and forget about it.
1281a0f774c8Skamil 	 */
1282a0f774c8Skamil 	if (sigval == SIGSTOP) {
1283a0f774c8Skamil 		parent = getpid();
1284a0f774c8Skamil 
1285a0f774c8Skamil 		watcher = fork();
1286a0f774c8Skamil 		ATF_REQUIRE(watcher != 1);
1287a0f774c8Skamil 		if (watcher == 0) {
1288a0f774c8Skamil 			/* Double fork(2) trick to reparent to initproc */
1289a0f774c8Skamil 			watcher = fork();
1290a0f774c8Skamil 			FORKEE_ASSERT_NEQ(watcher, -1);
1291a0f774c8Skamil 			if (watcher != 0)
1292a0f774c8Skamil 				_exit(exitval_watcher);
1293a0f774c8Skamil 
1294a0f774c8Skamil 			child = await_stopped_child(parent);
1295a0f774c8Skamil 
1296a0f774c8Skamil 			errno = 0;
1297a0f774c8Skamil 			rv = kill(child, SIGKILL);
1298a0f774c8Skamil 			FORKEE_ASSERT_EQ(rv, 0);
1299a0f774c8Skamil 			FORKEE_ASSERT_EQ(errno, 0);
1300a0f774c8Skamil 
1301a0f774c8Skamil 			/* This exit value will be collected by initproc */
1302a0f774c8Skamil 			_exit(0);
1303a0f774c8Skamil 		}
1304a0f774c8Skamil 		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1305a0f774c8Skamil 		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(watcher, &status, 0),
1306a0f774c8Skamil 		    watcher);
1307a0f774c8Skamil 
1308a0f774c8Skamil 		validate_status_exited(status, exitval_watcher);
1309a0f774c8Skamil 
1310a0f774c8Skamil 		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1311a0f774c8Skamil 		TWAIT_REQUIRE_FAILURE(ECHILD,
1312a0f774c8Skamil 		    wpid = TWAIT_GENERIC(watcher, &status, 0));
1313a0f774c8Skamil 	}
1314a0f774c8Skamil 
1315a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
1316a0f774c8Skamil 	SYSCALL_REQUIRE((child = vfork()) != -1);
1317a0f774c8Skamil 	if (child == 0) {
1318a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1319a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
1320a0f774c8Skamil 
1321a0f774c8Skamil 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
1322a0f774c8Skamil 		FORKEE_ASSERT(raise(sigval) == 0);
1323a0f774c8Skamil 
1324a0f774c8Skamil 		switch (sigval) {
1325a0f774c8Skamil 		case SIGSTOP:
1326a0f774c8Skamil 		case SIGKILL:
1327a0f774c8Skamil 		case SIGABRT:
1328a0f774c8Skamil 		case SIGHUP:
1329a0f774c8Skamil 		case SIGTRAP:
1330a0f774c8Skamil 		case SIGBUS:
1331a0f774c8Skamil 		case SIGILL:
1332a0f774c8Skamil 		case SIGFPE:
1333a0f774c8Skamil 		case SIGSEGV:
1334a0f774c8Skamil 			/* NOTREACHED */
1335a0f774c8Skamil 			FORKEE_ASSERTX(0 && "This shall not be reached");
1336a0f774c8Skamil 			__unreachable();
1337a0f774c8Skamil 		default:
1338a0f774c8Skamil 			DPRINTF("Before exiting of the child process\n");
1339a0f774c8Skamil 			_exit(exitval);
1340a0f774c8Skamil 		}
1341a0f774c8Skamil 	}
1342a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
1343a0f774c8Skamil 
1344a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1345a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
1346a0f774c8Skamil 
1347a0f774c8Skamil 	switch (sigval) {
1348a0f774c8Skamil 	case SIGKILL:
1349a0f774c8Skamil 	case SIGABRT:
1350a0f774c8Skamil 	case SIGHUP:
1351a0f774c8Skamil 	case SIGTRAP:
1352a0f774c8Skamil 	case SIGBUS:
1353a0f774c8Skamil 	case SIGILL:
1354a0f774c8Skamil 	case SIGFPE:
1355a0f774c8Skamil 	case SIGSEGV:
1356a0f774c8Skamil 		validate_status_signaled(status, sigval, expect_core);
1357a0f774c8Skamil 		break;
1358a0f774c8Skamil 	case SIGSTOP:
1359a0f774c8Skamil 		validate_status_signaled(status, SIGKILL, 0);
1360a0f774c8Skamil 		break;
1361a0f774c8Skamil 	case SIGCONT:
1362a0f774c8Skamil 	case SIGTSTP:
1363a0f774c8Skamil 	case SIGTTIN:
1364a0f774c8Skamil 	case SIGTTOU:
1365a0f774c8Skamil 		validate_status_exited(status, exitval);
1366a0f774c8Skamil 		break;
1367a0f774c8Skamil 	default:
1368a0f774c8Skamil 		/* NOTREACHED */
1369a0f774c8Skamil 		ATF_REQUIRE(0 && "NOT IMPLEMENTED");
1370a0f774c8Skamil 		break;
1371a0f774c8Skamil 	}
1372a0f774c8Skamil 
1373a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1374a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
1375a0f774c8Skamil }
1376a0f774c8Skamil 
1377a0f774c8Skamil #define TRACEME_VFORK_RAISE(test, sig)					\
1378a0f774c8Skamil ATF_TC(test);								\
1379a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
1380a0f774c8Skamil {									\
1381a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
1382a0f774c8Skamil 	    "Verify PT_TRACE_ME followed by raise of " #sig " in a "	\
1383a0f774c8Skamil 	    "vfork(2)ed child");					\
1384a0f774c8Skamil }									\
1385a0f774c8Skamil 									\
1386a0f774c8Skamil ATF_TC_BODY(test, tc)							\
1387a0f774c8Skamil {									\
1388a0f774c8Skamil 									\
1389a0f774c8Skamil 	traceme_vfork_raise(sig);					\
1390a0f774c8Skamil }
1391a0f774c8Skamil 
TRACEME_VFORK_RAISE(traceme_vfork_raise1,SIGKILL)1392a0f774c8Skamil TRACEME_VFORK_RAISE(traceme_vfork_raise1, SIGKILL) /* non-maskable */
1393a0f774c8Skamil TRACEME_VFORK_RAISE(traceme_vfork_raise2, SIGSTOP) /* non-maskable */
1394a0f774c8Skamil TRACEME_VFORK_RAISE(traceme_vfork_raise3, SIGTSTP) /* ignored in vfork(2) */
1395a0f774c8Skamil TRACEME_VFORK_RAISE(traceme_vfork_raise4, SIGTTIN) /* ignored in vfork(2) */
1396a0f774c8Skamil TRACEME_VFORK_RAISE(traceme_vfork_raise5, SIGTTOU) /* ignored in vfork(2) */
1397a0f774c8Skamil TRACEME_VFORK_RAISE(traceme_vfork_raise6, SIGABRT) /* regular abort trap */
1398a0f774c8Skamil TRACEME_VFORK_RAISE(traceme_vfork_raise7, SIGHUP)  /* hangup */
1399a0f774c8Skamil TRACEME_VFORK_RAISE(traceme_vfork_raise8, SIGCONT) /* continued? */
1400a0f774c8Skamil TRACEME_VFORK_RAISE(traceme_vfork_raise9, SIGTRAP) /* crash signal */
1401a0f774c8Skamil TRACEME_VFORK_RAISE(traceme_vfork_raise10, SIGBUS) /* crash signal */
1402a0f774c8Skamil TRACEME_VFORK_RAISE(traceme_vfork_raise11, SIGILL) /* crash signal */
1403a0f774c8Skamil TRACEME_VFORK_RAISE(traceme_vfork_raise12, SIGFPE) /* crash signal */
1404a0f774c8Skamil TRACEME_VFORK_RAISE(traceme_vfork_raise13, SIGSEGV) /* crash signal */
1405a0f774c8Skamil 
1406a0f774c8Skamil /// ----------------------------------------------------------------------------
1407a0f774c8Skamil 
1408a0f774c8Skamil static void
1409a0f774c8Skamil traceme_vfork_crash(int sig)
1410a0f774c8Skamil {
1411a0f774c8Skamil 	pid_t child, wpid;
1412a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
1413a0f774c8Skamil 	int status;
1414a0f774c8Skamil #endif
1415a0f774c8Skamil 
1416a0f774c8Skamil #ifndef PTRACE_ILLEGAL_ASM
1417a0f774c8Skamil 	if (sig == SIGILL)
1418a0f774c8Skamil 		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
1419a0f774c8Skamil #endif
1420a0f774c8Skamil 
1421a0f774c8Skamil 	if (sig == SIGFPE && !are_fpu_exceptions_supported())
1422a0f774c8Skamil 		atf_tc_skip("FP exceptions are not supported");
1423a0f774c8Skamil 
1424a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
1425a0f774c8Skamil 	SYSCALL_REQUIRE((child = vfork()) != -1);
1426a0f774c8Skamil 	if (child == 0) {
1427a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1428a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
1429a0f774c8Skamil 
1430a0f774c8Skamil 		DPRINTF("Before executing a trap\n");
1431a0f774c8Skamil 		switch (sig) {
1432a0f774c8Skamil 		case SIGTRAP:
1433a0f774c8Skamil 			trigger_trap();
1434a0f774c8Skamil 			break;
1435a0f774c8Skamil 		case SIGSEGV:
1436a0f774c8Skamil 			trigger_segv();
1437a0f774c8Skamil 			break;
1438a0f774c8Skamil 		case SIGILL:
1439a0f774c8Skamil 			trigger_ill();
1440a0f774c8Skamil 			break;
1441a0f774c8Skamil 		case SIGFPE:
1442a0f774c8Skamil 			trigger_fpe();
1443a0f774c8Skamil 			break;
1444a0f774c8Skamil 		case SIGBUS:
1445a0f774c8Skamil 			trigger_bus();
1446a0f774c8Skamil 			break;
1447a0f774c8Skamil 		default:
1448a0f774c8Skamil 			/* NOTREACHED */
1449a0f774c8Skamil 			FORKEE_ASSERTX(0 && "This shall not be reached");
1450a0f774c8Skamil 		}
1451a0f774c8Skamil 
1452a0f774c8Skamil 		/* NOTREACHED */
1453a0f774c8Skamil 		FORKEE_ASSERTX(0 && "This shall not be reached");
1454a0f774c8Skamil 	}
1455a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
1456a0f774c8Skamil 
1457a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1458a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
1459a0f774c8Skamil 
1460a0f774c8Skamil 	validate_status_signaled(status, sig, 1);
1461a0f774c8Skamil 
1462a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1463a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
1464a0f774c8Skamil }
1465a0f774c8Skamil 
1466a0f774c8Skamil #define TRACEME_VFORK_CRASH(test, sig)					\
1467a0f774c8Skamil ATF_TC(test);								\
1468a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
1469a0f774c8Skamil {									\
1470a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
1471a0f774c8Skamil 	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
1472a0f774c8Skamil 	    "vfork(2)ed child");					\
1473a0f774c8Skamil }									\
1474a0f774c8Skamil 									\
1475a0f774c8Skamil ATF_TC_BODY(test, tc)							\
1476a0f774c8Skamil {									\
1477a0f774c8Skamil 									\
1478a0f774c8Skamil 	traceme_vfork_crash(sig);					\
1479a0f774c8Skamil }
1480a0f774c8Skamil 
TRACEME_VFORK_CRASH(traceme_vfork_crash_trap,SIGTRAP)1481a0f774c8Skamil TRACEME_VFORK_CRASH(traceme_vfork_crash_trap, SIGTRAP)
1482a0f774c8Skamil TRACEME_VFORK_CRASH(traceme_vfork_crash_segv, SIGSEGV)
1483a0f774c8Skamil TRACEME_VFORK_CRASH(traceme_vfork_crash_ill, SIGILL)
1484a0f774c8Skamil TRACEME_VFORK_CRASH(traceme_vfork_crash_fpe, SIGFPE)
1485a0f774c8Skamil TRACEME_VFORK_CRASH(traceme_vfork_crash_bus, SIGBUS)
1486a0f774c8Skamil 
1487a0f774c8Skamil /// ----------------------------------------------------------------------------
1488a0f774c8Skamil 
1489a0f774c8Skamil static void
1490a0f774c8Skamil traceme_vfork_signalmasked_crash(int sig)
1491a0f774c8Skamil {
1492a0f774c8Skamil 	pid_t child, wpid;
1493a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
1494a0f774c8Skamil 	int status;
1495a0f774c8Skamil #endif
1496a0f774c8Skamil 	sigset_t intmask;
1497a0f774c8Skamil 
1498a0f774c8Skamil #ifndef PTRACE_ILLEGAL_ASM
1499a0f774c8Skamil 	if (sig == SIGILL)
1500a0f774c8Skamil 		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
1501a0f774c8Skamil #endif
1502a0f774c8Skamil 
1503a0f774c8Skamil 	if (sig == SIGFPE && !are_fpu_exceptions_supported())
1504a0f774c8Skamil 		atf_tc_skip("FP exceptions are not supported");
1505a0f774c8Skamil 
1506a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
1507a0f774c8Skamil 	SYSCALL_REQUIRE((child = vfork()) != -1);
1508a0f774c8Skamil 	if (child == 0) {
1509a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1510a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
1511a0f774c8Skamil 
1512a0f774c8Skamil 		sigemptyset(&intmask);
1513a0f774c8Skamil 		sigaddset(&intmask, sig);
1514a0f774c8Skamil 		sigprocmask(SIG_BLOCK, &intmask, NULL);
1515a0f774c8Skamil 
1516a0f774c8Skamil 		DPRINTF("Before executing a trap\n");
1517a0f774c8Skamil 		switch (sig) {
1518a0f774c8Skamil 		case SIGTRAP:
1519a0f774c8Skamil 			trigger_trap();
1520a0f774c8Skamil 			break;
1521a0f774c8Skamil 		case SIGSEGV:
1522a0f774c8Skamil 			trigger_segv();
1523a0f774c8Skamil 			break;
1524a0f774c8Skamil 		case SIGILL:
1525a0f774c8Skamil 			trigger_ill();
1526a0f774c8Skamil 			break;
1527a0f774c8Skamil 		case SIGFPE:
1528a0f774c8Skamil 			trigger_fpe();
1529a0f774c8Skamil 			break;
1530a0f774c8Skamil 		case SIGBUS:
1531a0f774c8Skamil 			trigger_bus();
1532a0f774c8Skamil 			break;
1533a0f774c8Skamil 		default:
1534a0f774c8Skamil 			/* NOTREACHED */
1535a0f774c8Skamil 			FORKEE_ASSERTX(0 && "This shall not be reached");
1536a0f774c8Skamil 		}
1537a0f774c8Skamil 
1538a0f774c8Skamil 		/* NOTREACHED */
1539a0f774c8Skamil 		FORKEE_ASSERTX(0 && "This shall not be reached");
1540a0f774c8Skamil 	}
1541a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
1542a0f774c8Skamil 
1543a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1544a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
1545a0f774c8Skamil 
1546a0f774c8Skamil 	validate_status_signaled(status, sig, 1);
1547a0f774c8Skamil 
1548a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1549a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
1550a0f774c8Skamil }
1551a0f774c8Skamil 
1552a0f774c8Skamil #define TRACEME_VFORK_SIGNALMASKED_CRASH(test, sig)			\
1553a0f774c8Skamil ATF_TC(test);								\
1554a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
1555a0f774c8Skamil {									\
1556a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
1557a0f774c8Skamil 	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
1558a0f774c8Skamil 	    "vfork(2)ed child with a masked signal");			\
1559a0f774c8Skamil }									\
1560a0f774c8Skamil 									\
1561a0f774c8Skamil ATF_TC_BODY(test, tc)							\
1562a0f774c8Skamil {									\
1563a0f774c8Skamil 									\
1564a0f774c8Skamil 	traceme_vfork_signalmasked_crash(sig);				\
1565a0f774c8Skamil }
1566a0f774c8Skamil 
TRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_trap,SIGTRAP)1567a0f774c8Skamil TRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_trap, SIGTRAP)
1568a0f774c8Skamil TRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_segv, SIGSEGV)
1569a0f774c8Skamil TRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_ill, SIGILL)
1570a0f774c8Skamil TRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_fpe, SIGFPE)
1571a0f774c8Skamil TRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_bus, SIGBUS)
1572a0f774c8Skamil 
1573a0f774c8Skamil /// ----------------------------------------------------------------------------
1574a0f774c8Skamil 
1575a0f774c8Skamil static void
1576a0f774c8Skamil traceme_vfork_signalignored_crash(int sig)
1577a0f774c8Skamil {
1578a0f774c8Skamil 	pid_t child, wpid;
1579a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
1580a0f774c8Skamil 	int status;
1581a0f774c8Skamil #endif
1582a0f774c8Skamil 	struct sigaction sa;
1583a0f774c8Skamil 
1584a0f774c8Skamil #ifndef PTRACE_ILLEGAL_ASM
1585a0f774c8Skamil 	if (sig == SIGILL)
1586a0f774c8Skamil 		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
1587a0f774c8Skamil #endif
1588a0f774c8Skamil 
1589a0f774c8Skamil 	if (sig == SIGFPE && !are_fpu_exceptions_supported())
1590a0f774c8Skamil 		atf_tc_skip("FP exceptions are not supported");
1591a0f774c8Skamil 
1592a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
1593a0f774c8Skamil 	SYSCALL_REQUIRE((child = vfork()) != -1);
1594a0f774c8Skamil 	if (child == 0) {
1595a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1596a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
1597a0f774c8Skamil 
1598a0f774c8Skamil 		memset(&sa, 0, sizeof(sa));
1599a0f774c8Skamil 		sa.sa_handler = SIG_IGN;
1600a0f774c8Skamil 		sigemptyset(&sa.sa_mask);
1601a0f774c8Skamil 
1602a0f774c8Skamil 		FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
1603a0f774c8Skamil 
1604a0f774c8Skamil 		DPRINTF("Before executing a trap\n");
1605a0f774c8Skamil 		switch (sig) {
1606a0f774c8Skamil 		case SIGTRAP:
1607a0f774c8Skamil 			trigger_trap();
1608a0f774c8Skamil 			break;
1609a0f774c8Skamil 		case SIGSEGV:
1610a0f774c8Skamil 			trigger_segv();
1611a0f774c8Skamil 			break;
1612a0f774c8Skamil 		case SIGILL:
1613a0f774c8Skamil 			trigger_ill();
1614a0f774c8Skamil 			break;
1615a0f774c8Skamil 		case SIGFPE:
1616a0f774c8Skamil 			trigger_fpe();
1617a0f774c8Skamil 			break;
1618a0f774c8Skamil 		case SIGBUS:
1619a0f774c8Skamil 			trigger_bus();
1620a0f774c8Skamil 			break;
1621a0f774c8Skamil 		default:
1622a0f774c8Skamil 			/* NOTREACHED */
1623a0f774c8Skamil 			FORKEE_ASSERTX(0 && "This shall not be reached");
1624a0f774c8Skamil 		}
1625a0f774c8Skamil 
1626a0f774c8Skamil 		/* NOTREACHED */
1627a0f774c8Skamil 		FORKEE_ASSERTX(0 && "This shall not be reached");
1628a0f774c8Skamil 	}
1629a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
1630a0f774c8Skamil 
1631a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1632a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
1633a0f774c8Skamil 
1634a0f774c8Skamil 	validate_status_signaled(status, sig, 1);
1635a0f774c8Skamil 
1636a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1637a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
1638a0f774c8Skamil }
1639a0f774c8Skamil 
1640a0f774c8Skamil #define TRACEME_VFORK_SIGNALIGNORED_CRASH(test, sig)			\
1641a0f774c8Skamil ATF_TC(test);								\
1642a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
1643a0f774c8Skamil {									\
1644a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
1645a0f774c8Skamil 	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
1646a0f774c8Skamil 	    "vfork(2)ed child with ignored signal");			\
1647a0f774c8Skamil }									\
1648a0f774c8Skamil 									\
1649a0f774c8Skamil ATF_TC_BODY(test, tc)							\
1650a0f774c8Skamil {									\
1651a0f774c8Skamil 									\
1652a0f774c8Skamil 	traceme_vfork_signalignored_crash(sig);				\
1653a0f774c8Skamil }
1654a0f774c8Skamil 
TRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_trap,SIGTRAP)1655a0f774c8Skamil TRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_trap,
1656a0f774c8Skamil     SIGTRAP)
1657a0f774c8Skamil TRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_segv,
1658a0f774c8Skamil     SIGSEGV)
1659a0f774c8Skamil TRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_ill,
1660a0f774c8Skamil     SIGILL)
1661a0f774c8Skamil TRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_fpe,
1662a0f774c8Skamil     SIGFPE)
1663a0f774c8Skamil TRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_bus,
1664a0f774c8Skamil     SIGBUS)
1665a0f774c8Skamil 
1666a0f774c8Skamil /// ----------------------------------------------------------------------------
1667a0f774c8Skamil 
1668a0f774c8Skamil #if defined(TWAIT_HAVE_PID)
1669a0f774c8Skamil static void
1670a0f774c8Skamil unrelated_tracer_sees_crash(int sig, bool masked, bool ignored)
1671a0f774c8Skamil {
1672a0f774c8Skamil 	const int sigval = SIGSTOP;
1673a0f774c8Skamil 	struct msg_fds parent_tracee, parent_tracer;
1674a0f774c8Skamil 	const int exitval = 10;
1675a0f774c8Skamil 	pid_t tracee, tracer, wpid;
1676a0f774c8Skamil 	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
1677a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
1678a0f774c8Skamil 	int status;
1679a0f774c8Skamil #endif
1680a0f774c8Skamil 	struct sigaction sa;
1681a0f774c8Skamil 	struct ptrace_siginfo info;
1682a0f774c8Skamil 	sigset_t intmask;
1683a0f774c8Skamil 	struct kinfo_proc2 kp;
1684a0f774c8Skamil 	size_t len = sizeof(kp);
1685a0f774c8Skamil 
1686a0f774c8Skamil 	int name[6];
1687a0f774c8Skamil 	const size_t namelen = __arraycount(name);
1688a0f774c8Skamil 	ki_sigset_t kp_sigmask;
1689a0f774c8Skamil 	ki_sigset_t kp_sigignore;
1690a0f774c8Skamil 
1691a0f774c8Skamil #ifndef PTRACE_ILLEGAL_ASM
1692a0f774c8Skamil 	if (sig == SIGILL)
1693a0f774c8Skamil 		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
1694a0f774c8Skamil #endif
1695a0f774c8Skamil 
1696a0f774c8Skamil 	if (sig == SIGFPE && !are_fpu_exceptions_supported())
1697a0f774c8Skamil 		atf_tc_skip("FP exceptions are not supported");
1698a0f774c8Skamil 
1699a0f774c8Skamil 	memset(&info, 0, sizeof(info));
1700a0f774c8Skamil 
1701a0f774c8Skamil 	DPRINTF("Spawn tracee\n");
1702a0f774c8Skamil 	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
1703a0f774c8Skamil 	tracee = atf_utils_fork();
1704a0f774c8Skamil 	if (tracee == 0) {
1705a0f774c8Skamil 		// Wait for parent to let us crash
1706a0f774c8Skamil 		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
1707a0f774c8Skamil 
1708a0f774c8Skamil 		if (masked) {
1709a0f774c8Skamil 			sigemptyset(&intmask);
1710a0f774c8Skamil 			sigaddset(&intmask, sig);
1711a0f774c8Skamil 			sigprocmask(SIG_BLOCK, &intmask, NULL);
1712a0f774c8Skamil 		}
1713a0f774c8Skamil 
1714a0f774c8Skamil 		if (ignored) {
1715a0f774c8Skamil 			memset(&sa, 0, sizeof(sa));
1716a0f774c8Skamil 			sa.sa_handler = SIG_IGN;
1717a0f774c8Skamil 			sigemptyset(&sa.sa_mask);
1718a0f774c8Skamil 			FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
1719a0f774c8Skamil 		}
1720a0f774c8Skamil 
1721a0f774c8Skamil 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
1722a0f774c8Skamil 		FORKEE_ASSERT(raise(sigval) == 0);
1723a0f774c8Skamil 
1724a0f774c8Skamil 		DPRINTF("Before executing a trap\n");
1725a0f774c8Skamil 		switch (sig) {
1726a0f774c8Skamil 		case SIGTRAP:
1727a0f774c8Skamil 			trigger_trap();
1728a0f774c8Skamil 			break;
1729a0f774c8Skamil 		case SIGSEGV:
1730a0f774c8Skamil 			trigger_segv();
1731a0f774c8Skamil 			break;
1732a0f774c8Skamil 		case SIGILL:
1733a0f774c8Skamil 			trigger_ill();
1734a0f774c8Skamil 			break;
1735a0f774c8Skamil 		case SIGFPE:
1736a0f774c8Skamil 			trigger_fpe();
1737a0f774c8Skamil 			break;
1738a0f774c8Skamil 		case SIGBUS:
1739a0f774c8Skamil 			trigger_bus();
1740a0f774c8Skamil 			break;
1741a0f774c8Skamil 		default:
1742a0f774c8Skamil 			/* NOTREACHED */
1743a0f774c8Skamil 			FORKEE_ASSERTX(0 && "This shall not be reached");
1744a0f774c8Skamil 		}
1745a0f774c8Skamil 
1746a0f774c8Skamil 		/* NOTREACHED */
1747a0f774c8Skamil 		FORKEE_ASSERTX(0 && "This shall not be reached");
1748a0f774c8Skamil 	}
1749a0f774c8Skamil 
1750a0f774c8Skamil 	DPRINTF("Spawn debugger\n");
1751a0f774c8Skamil 	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
1752a0f774c8Skamil 	tracer = atf_utils_fork();
1753a0f774c8Skamil 	if (tracer == 0) {
1754a0f774c8Skamil 		/* Fork again and drop parent to reattach to PID 1 */
1755a0f774c8Skamil 		tracer = atf_utils_fork();
1756a0f774c8Skamil 		if (tracer != 0)
1757a0f774c8Skamil 			_exit(exitval);
1758a0f774c8Skamil 
1759a0f774c8Skamil 		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
1760a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
1761a0f774c8Skamil 
1762a0f774c8Skamil 		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
1763a0f774c8Skamil 		FORKEE_REQUIRE_SUCCESS(
1764a0f774c8Skamil 		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
1765a0f774c8Skamil 
1766a0f774c8Skamil 		forkee_status_stopped(status, SIGSTOP);
1767a0f774c8Skamil 
1768a0f774c8Skamil 		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
1769a0f774c8Skamil 		    "traced process\n");
1770a0f774c8Skamil 		SYSCALL_REQUIRE(
1771a0f774c8Skamil 		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
1772a0f774c8Skamil 
1773a0f774c8Skamil 		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
1774a0f774c8Skamil 		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
1775a0f774c8Skamil 		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
1776a0f774c8Skamil 		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
1777a0f774c8Skamil 
1778a0f774c8Skamil 		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
1779a0f774c8Skamil 		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
1780a0f774c8Skamil 
1781a0f774c8Skamil 		/* Resume tracee with PT_CONTINUE */
1782a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
1783a0f774c8Skamil 
1784a0f774c8Skamil 		/* Inform parent that tracer has attached to tracee */
1785a0f774c8Skamil 		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
1786a0f774c8Skamil 
1787a0f774c8Skamil 		/* Wait for parent to tell use that tracee should have exited */
1788a0f774c8Skamil 		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
1789a0f774c8Skamil 
1790a0f774c8Skamil 		/* Wait for tracee and assert that it exited */
1791a0f774c8Skamil 		FORKEE_REQUIRE_SUCCESS(
1792a0f774c8Skamil 		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
1793a0f774c8Skamil 
1794a0f774c8Skamil 		forkee_status_stopped(status, sigval);
1795a0f774c8Skamil 
1796a0f774c8Skamil 		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
1797a0f774c8Skamil 		    "traced process\n");
1798a0f774c8Skamil 		SYSCALL_REQUIRE(
1799a0f774c8Skamil 		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
1800a0f774c8Skamil 
1801a0f774c8Skamil 		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
1802a0f774c8Skamil 		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
1803a0f774c8Skamil 		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
1804a0f774c8Skamil 		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
1805a0f774c8Skamil 
1806a0f774c8Skamil 		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
1807a0f774c8Skamil 		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
1808a0f774c8Skamil 
1809a0f774c8Skamil 		name[0] = CTL_KERN,
1810a0f774c8Skamil 		name[1] = KERN_PROC2,
1811a0f774c8Skamil 		name[2] = KERN_PROC_PID;
1812a0f774c8Skamil 		name[3] = tracee;
1813a0f774c8Skamil 		name[4] = sizeof(kp);
1814a0f774c8Skamil 		name[5] = 1;
1815a0f774c8Skamil 
1816a0f774c8Skamil 		FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
1817a0f774c8Skamil 
1818a0f774c8Skamil 		if (masked)
1819a0f774c8Skamil 			kp_sigmask = kp.p_sigmask;
1820a0f774c8Skamil 
1821a0f774c8Skamil 		if (ignored)
1822a0f774c8Skamil 			kp_sigignore = kp.p_sigignore;
1823a0f774c8Skamil 
1824a0f774c8Skamil 		/* Resume tracee with PT_CONTINUE */
1825a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
1826a0f774c8Skamil 
1827a0f774c8Skamil 		/* Wait for tracee and assert that it exited */
1828a0f774c8Skamil 		FORKEE_REQUIRE_SUCCESS(
1829a0f774c8Skamil 		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
1830a0f774c8Skamil 
1831a0f774c8Skamil 		forkee_status_stopped(status, sig);
1832a0f774c8Skamil 
1833a0f774c8Skamil 		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
1834a0f774c8Skamil 		    "traced process\n");
1835a0f774c8Skamil 		SYSCALL_REQUIRE(
1836a0f774c8Skamil 		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
1837a0f774c8Skamil 
1838a0f774c8Skamil 		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
1839a0f774c8Skamil 		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
1840a0f774c8Skamil 		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
1841a0f774c8Skamil 		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
1842a0f774c8Skamil 
1843a0f774c8Skamil 		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sig);
1844a0f774c8Skamil 
1845a0f774c8Skamil 		FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
1846a0f774c8Skamil 
1847a0f774c8Skamil 		if (masked) {
1848a0f774c8Skamil 			DPRINTF("kp_sigmask="
1849a0f774c8Skamil 			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
1850a0f774c8Skamil 			    PRIx32 "\n",
1851a0f774c8Skamil 			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
1852a0f774c8Skamil 			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
1853a0f774c8Skamil 
1854a0f774c8Skamil 			DPRINTF("kp.p_sigmask="
1855a0f774c8Skamil 			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
1856a0f774c8Skamil 			    PRIx32 "\n",
1857a0f774c8Skamil 			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
1858a0f774c8Skamil 			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
1859a0f774c8Skamil 
1860a0f774c8Skamil 			FORKEE_ASSERTX(!memcmp(&kp_sigmask, &kp.p_sigmask,
1861a0f774c8Skamil 			    sizeof(kp_sigmask)));
1862a0f774c8Skamil 		}
1863a0f774c8Skamil 
1864a0f774c8Skamil 		if (ignored) {
1865a0f774c8Skamil 			DPRINTF("kp_sigignore="
1866a0f774c8Skamil 			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
1867a0f774c8Skamil 			    PRIx32 "\n",
1868a0f774c8Skamil 			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
1869a0f774c8Skamil 			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
1870a0f774c8Skamil 
1871a0f774c8Skamil 			DPRINTF("kp.p_sigignore="
1872a0f774c8Skamil 			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
1873a0f774c8Skamil 			    PRIx32 "\n",
1874a0f774c8Skamil 			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
1875a0f774c8Skamil 			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
1876a0f774c8Skamil 
1877a0f774c8Skamil 			FORKEE_ASSERTX(!memcmp(&kp_sigignore, &kp.p_sigignore,
1878a0f774c8Skamil 			    sizeof(kp_sigignore)));
1879a0f774c8Skamil 		}
1880a0f774c8Skamil 
1881a0f774c8Skamil 		switch (sig) {
1882a0f774c8Skamil 		case SIGTRAP:
1883a0f774c8Skamil 			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
1884a0f774c8Skamil 			break;
1885a0f774c8Skamil 		case SIGSEGV:
1886a0f774c8Skamil 			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
1887a0f774c8Skamil 			break;
1888a0f774c8Skamil 		case SIGILL:
1889a0f774c8Skamil 			FORKEE_ASSERT(info.psi_siginfo.si_code >= ILL_ILLOPC &&
1890a0f774c8Skamil 			            info.psi_siginfo.si_code <= ILL_BADSTK);
1891a0f774c8Skamil 			break;
1892a0f774c8Skamil 		case SIGFPE:
1893c3c8ab88Srin // XXXQEMU		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, FPE_FLTDIV);
1894a0f774c8Skamil 			break;
1895a0f774c8Skamil 		case SIGBUS:
1896a0f774c8Skamil 			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
1897a0f774c8Skamil 			break;
1898a0f774c8Skamil 		}
1899a0f774c8Skamil 
1900a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_KILL, tracee, NULL, 0) != -1);
1901a0f774c8Skamil 		DPRINTF("Before calling %s() for the tracee\n", TWAIT_FNAME);
1902a0f774c8Skamil 		FORKEE_REQUIRE_SUCCESS(
1903a0f774c8Skamil 		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
1904a0f774c8Skamil 
1905a0f774c8Skamil 		forkee_status_signaled(status, SIGKILL, 0);
1906a0f774c8Skamil 
1907a0f774c8Skamil 		/* Inform parent that tracer is exiting normally */
1908a0f774c8Skamil 		CHILD_TO_PARENT("tracer done", parent_tracer, msg);
1909a0f774c8Skamil 
1910a0f774c8Skamil 		DPRINTF("Before exiting of the tracer process\n");
1911a0f774c8Skamil 		_exit(0 /* collect by initproc */);
1912a0f774c8Skamil 	}
1913a0f774c8Skamil 
1914a0f774c8Skamil 	DPRINTF("Wait for the tracer process (direct child) to exit "
1915a0f774c8Skamil 	    "calling %s()\n", TWAIT_FNAME);
1916a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(
1917a0f774c8Skamil 	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
1918a0f774c8Skamil 
1919a0f774c8Skamil 	validate_status_exited(status, exitval);
1920a0f774c8Skamil 
1921a0f774c8Skamil 	DPRINTF("Wait for the non-exited tracee process with %s()\n",
1922a0f774c8Skamil 	    TWAIT_FNAME);
1923a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(
1924a0f774c8Skamil 	    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
1925a0f774c8Skamil 
1926a0f774c8Skamil 	DPRINTF("Wait for the tracer to attach to the tracee\n");
1927a0f774c8Skamil 	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
1928a0f774c8Skamil 
1929a0f774c8Skamil 	DPRINTF("Resume the tracee and let it crash\n");
1930a0f774c8Skamil 	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
1931a0f774c8Skamil 
1932a0f774c8Skamil 	DPRINTF("Resume the tracer and let it detect crashed tracee\n");
1933a0f774c8Skamil 	PARENT_TO_CHILD("Message 2", parent_tracer, msg);
1934a0f774c8Skamil 
1935a0f774c8Skamil 	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
1936a0f774c8Skamil 	    TWAIT_FNAME);
1937a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
1938a0f774c8Skamil 
1939a0f774c8Skamil 	validate_status_signaled(status, SIGKILL, 0);
1940a0f774c8Skamil 
1941a0f774c8Skamil 	DPRINTF("Await normal exit of tracer\n");
1942a0f774c8Skamil 	PARENT_FROM_CHILD("tracer done", parent_tracer, msg);
1943a0f774c8Skamil 
1944a0f774c8Skamil 	msg_close(&parent_tracer);
1945a0f774c8Skamil 	msg_close(&parent_tracee);
1946a0f774c8Skamil }
1947a0f774c8Skamil 
1948a0f774c8Skamil #define UNRELATED_TRACER_SEES_CRASH(test, sig)				\
1949a0f774c8Skamil ATF_TC(test);								\
1950a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
1951a0f774c8Skamil {									\
1952a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
1953a0f774c8Skamil 	    "Assert that an unrelated tracer sees crash signal from "	\
1954a0f774c8Skamil 	    "the debuggee");						\
1955a0f774c8Skamil }									\
1956a0f774c8Skamil 									\
1957a0f774c8Skamil ATF_TC_BODY(test, tc)							\
1958a0f774c8Skamil {									\
1959a0f774c8Skamil 									\
1960a0f774c8Skamil 	unrelated_tracer_sees_crash(sig, false, false);			\
1961a0f774c8Skamil }
1962a0f774c8Skamil 
1963a0f774c8Skamil UNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_trap, SIGTRAP)
1964a0f774c8Skamil UNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_segv, SIGSEGV)
1965a0f774c8Skamil UNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_ill, SIGILL)
1966a0f774c8Skamil UNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_fpe, SIGFPE)
1967a0f774c8Skamil UNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_bus, SIGBUS)
1968a0f774c8Skamil 
1969a0f774c8Skamil #define UNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(test, sig)		\
1970a0f774c8Skamil ATF_TC(test);								\
1971a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
1972a0f774c8Skamil {									\
1973a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
1974a0f774c8Skamil 	    "Assert that an unrelated tracer sees crash signal from "	\
1975a0f774c8Skamil 	    "the debuggee with masked signal");				\
1976a0f774c8Skamil }									\
1977a0f774c8Skamil 									\
1978a0f774c8Skamil ATF_TC_BODY(test, tc)							\
1979a0f774c8Skamil {									\
1980a0f774c8Skamil 									\
1981a0f774c8Skamil 	unrelated_tracer_sees_crash(sig, true, false);			\
1982a0f774c8Skamil }
1983a0f774c8Skamil 
1984a0f774c8Skamil UNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
1985a0f774c8Skamil     unrelated_tracer_sees_signalmasked_crash_trap, SIGTRAP)
1986a0f774c8Skamil UNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
1987a0f774c8Skamil     unrelated_tracer_sees_signalmasked_crash_segv, SIGSEGV)
1988a0f774c8Skamil UNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
1989a0f774c8Skamil     unrelated_tracer_sees_signalmasked_crash_ill, SIGILL)
1990a0f774c8Skamil UNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
1991a0f774c8Skamil     unrelated_tracer_sees_signalmasked_crash_fpe, SIGFPE)
1992a0f774c8Skamil UNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
1993a0f774c8Skamil     unrelated_tracer_sees_signalmasked_crash_bus, SIGBUS)
1994a0f774c8Skamil 
1995a0f774c8Skamil #define UNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(test, sig)		\
1996a0f774c8Skamil ATF_TC(test);								\
1997a0f774c8Skamil ATF_TC_HEAD(test, tc)							\
1998a0f774c8Skamil {									\
1999a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",					\
2000a0f774c8Skamil 	    "Assert that an unrelated tracer sees crash signal from "	\
2001a0f774c8Skamil 	    "the debuggee with signal ignored");			\
2002a0f774c8Skamil }									\
2003a0f774c8Skamil 									\
2004a0f774c8Skamil ATF_TC_BODY(test, tc)							\
2005a0f774c8Skamil {									\
2006a0f774c8Skamil 									\
2007a0f774c8Skamil 	unrelated_tracer_sees_crash(sig, false, true);			\
2008a0f774c8Skamil }
2009a0f774c8Skamil 
2010a0f774c8Skamil UNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
2011a0f774c8Skamil     unrelated_tracer_sees_signalignored_crash_trap, SIGTRAP)
2012a0f774c8Skamil UNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
2013a0f774c8Skamil     unrelated_tracer_sees_signalignored_crash_segv, SIGSEGV)
2014a0f774c8Skamil UNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
2015a0f774c8Skamil     unrelated_tracer_sees_signalignored_crash_ill, SIGILL)
2016a0f774c8Skamil UNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
2017a0f774c8Skamil     unrelated_tracer_sees_signalignored_crash_fpe, SIGFPE)
2018a0f774c8Skamil UNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
2019a0f774c8Skamil     unrelated_tracer_sees_signalignored_crash_bus, SIGBUS)
2020a0f774c8Skamil #endif
2021a0f774c8Skamil 
2022a0f774c8Skamil /// ----------------------------------------------------------------------------
2023a0f774c8Skamil 
2024a0f774c8Skamil ATF_TC(signal_mask_unrelated);
ATF_TC_HEAD(signal_mask_unrelated,tc)2025a0f774c8Skamil ATF_TC_HEAD(signal_mask_unrelated, tc)
2026a0f774c8Skamil {
2027a0f774c8Skamil 	atf_tc_set_md_var(tc, "descr",
2028a0f774c8Skamil 	    "Verify that masking single unrelated signal does not stop tracer "
2029a0f774c8Skamil 	    "from catching other signals");
2030a0f774c8Skamil }
2031a0f774c8Skamil 
ATF_TC_BODY(signal_mask_unrelated,tc)2032a0f774c8Skamil ATF_TC_BODY(signal_mask_unrelated, tc)
2033a0f774c8Skamil {
2034a0f774c8Skamil 	const int exitval = 5;
2035a0f774c8Skamil 	const int sigval = SIGSTOP;
2036a0f774c8Skamil 	const int sigmasked = SIGTRAP;
2037a0f774c8Skamil 	const int signotmasked = SIGINT;
2038a0f774c8Skamil 	pid_t child, wpid;
2039a0f774c8Skamil #if defined(TWAIT_HAVE_STATUS)
2040a0f774c8Skamil 	int status;
2041a0f774c8Skamil #endif
2042a0f774c8Skamil 	sigset_t intmask;
2043a0f774c8Skamil 
2044a0f774c8Skamil 	DPRINTF("Before forking process PID=%d\n", getpid());
2045a0f774c8Skamil 	SYSCALL_REQUIRE((child = fork()) != -1);
2046a0f774c8Skamil 	if (child == 0) {
2047a0f774c8Skamil 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
2048a0f774c8Skamil 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
2049a0f774c8Skamil 
2050a0f774c8Skamil 		sigemptyset(&intmask);
2051a0f774c8Skamil 		sigaddset(&intmask, sigmasked);
2052a0f774c8Skamil 		sigprocmask(SIG_BLOCK, &intmask, NULL);
2053a0f774c8Skamil 
2054a0f774c8Skamil 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
2055a0f774c8Skamil 		FORKEE_ASSERT(raise(sigval) == 0);
2056a0f774c8Skamil 
2057a0f774c8Skamil 		DPRINTF("Before raising %s from child\n",
2058a0f774c8Skamil 		    strsignal(signotmasked));
2059a0f774c8Skamil 		FORKEE_ASSERT(raise(signotmasked) == 0);
2060a0f774c8Skamil 
2061a0f774c8Skamil 		DPRINTF("Before exiting of the child process\n");
2062a0f774c8Skamil 		_exit(exitval);
2063a0f774c8Skamil 	}
2064a0f774c8Skamil 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
2065a0f774c8Skamil 
2066a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2067a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2068a0f774c8Skamil 
2069a0f774c8Skamil 	validate_status_stopped(status, sigval);
2070a0f774c8Skamil 
2071a0f774c8Skamil 	DPRINTF("Before resuming the child process where it left off and "
2072a0f774c8Skamil 	    "without signal to be sent\n");
2073a0f774c8Skamil 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
2074a0f774c8Skamil 
2075a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2076a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2077a0f774c8Skamil 
2078a0f774c8Skamil 	validate_status_stopped(status, signotmasked);
2079a0f774c8Skamil 
2080a0f774c8Skamil 	DPRINTF("Before resuming the child process where it left off and "
2081a0f774c8Skamil 	    "without signal to be sent\n");
2082a0f774c8Skamil 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
2083a0f774c8Skamil 
2084a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2085a0f774c8Skamil 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2086a0f774c8Skamil 
2087a0f774c8Skamil 	validate_status_exited(status, exitval);
2088a0f774c8Skamil 
2089a0f774c8Skamil 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2090a0f774c8Skamil 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
2091a0f774c8Skamil }
2092a0f774c8Skamil 
2093a0f774c8Skamil /// ----------------------------------------------------------------------------
2094a0f774c8Skamil 
2095a0f774c8Skamil #define ATF_TP_ADD_TCS_PTRACE_WAIT_SIGNAL() \
2096a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raise1); \
2097a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raise2); \
2098a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raise3); \
2099a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raise4); \
2100a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raise5); \
2101a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raise6); \
2102a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raise7); \
2103a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raise8); \
2104a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raise9); \
2105a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raise10); \
2106a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored1); \
2107a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored2); \
2108a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored3); \
2109a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored4); \
2110a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored5); \
2111a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored6); \
2112a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored7); \
2113a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored8); \
2114a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked1); \
2115a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked2); \
2116a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked3); \
2117a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked4); \
2118a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked5); \
2119a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked6); \
2120a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked7); \
2121a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked8); \
2122a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_crash_trap); \
2123a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_crash_segv); \
2124a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_crash_ill); \
2125a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_crash_fpe); \
2126a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_crash_bus); \
2127a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_trap); \
2128a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_segv); \
2129a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_ill); \
2130a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_fpe); \
2131a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_bus); \
2132a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_trap); \
2133a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_segv); \
2134a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_ill); \
2135a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_fpe); \
2136a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_bus); \
2137a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle1); \
2138a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle2); \
2139a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle3); \
2140a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle4); \
2141a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle5); \
2142a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle6); \
2143a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle7); \
2144a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle8); \
2145a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked1); \
2146a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked2); \
2147a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked3); \
2148a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked4); \
2149a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked5); \
2150a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked6); \
2151a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked7); \
2152a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked8); \
2153a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored1); \
2154a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored2); \
2155a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored3); \
2156a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored4); \
2157a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored5); \
2158a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored6); \
2159a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored7); \
2160a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored8); \
2161a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple1); \
2162a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple2); \
2163a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple3); \
2164a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple4); \
2165a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple5); \
2166a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple6); \
2167a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple7); \
2168a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple8); \
2169a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple9); \
2170a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple10); \
2171a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_raise1); \
2172a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_raise2); \
2173a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_raise3); \
2174a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_raise4); \
2175a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_raise5); \
2176a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_raise6); \
2177a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_raise7); \
2178a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_raise8); \
2179a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_raise9); \
2180a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_raise10); \
2181a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_raise11); \
2182a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_raise12); \
2183a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_raise13); \
2184a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_crash_trap); \
2185a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_crash_segv); \
2186a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_crash_ill); \
2187a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_crash_fpe); \
2188a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_crash_bus); \
2189a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_trap); \
2190a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_segv); \
2191a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_ill); \
2192a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_fpe); \
2193a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_bus); \
2194a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_trap); \
2195a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_segv); \
2196a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_ill); \
2197a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_fpe); \
2198a0f774c8Skamil 	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_bus); \
2199a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_trap); \
2200a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_segv); \
2201a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_ill); \
2202a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_fpe); \
2203a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_bus); \
2204a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, \
2205a0f774c8Skamil 	    unrelated_tracer_sees_signalmasked_crash_trap); \
2206a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, \
2207a0f774c8Skamil 	    unrelated_tracer_sees_signalmasked_crash_segv); \
2208a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, \
2209a0f774c8Skamil 	    unrelated_tracer_sees_signalmasked_crash_ill); \
2210a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, \
2211a0f774c8Skamil 	    unrelated_tracer_sees_signalmasked_crash_fpe); \
2212a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, \
2213a0f774c8Skamil 	    unrelated_tracer_sees_signalmasked_crash_bus); \
2214a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, \
2215a0f774c8Skamil 	    unrelated_tracer_sees_signalignored_crash_trap); \
2216a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, \
2217a0f774c8Skamil 	    unrelated_tracer_sees_signalignored_crash_segv); \
2218a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, \
2219a0f774c8Skamil 	    unrelated_tracer_sees_signalignored_crash_ill); \
2220a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, \
2221a0f774c8Skamil 	    unrelated_tracer_sees_signalignored_crash_fpe); \
2222a0f774c8Skamil 	ATF_TP_ADD_TC_HAVE_PID(tp, \
2223a0f774c8Skamil 	    unrelated_tracer_sees_signalignored_crash_bus); \
2224a0f774c8Skamil 	ATF_TP_ADD_TC(tp, signal_mask_unrelated);
2225