xref: /netbsd-src/tests/lib/libc/sys/t_ptrace_lwp_wait.h (revision fadd423b64a29bc50f13fad30ce9ef1ef7876700)
1 /*	$NetBSD: t_ptrace_lwp_wait.h,v 1.1 2020/05/05 00:15:45 kamil Exp $	*/
2 
3 /*-
4  * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 
30 static int lwpinfo_thread_sigmask[] = {SIGXCPU, SIGPIPE, SIGALRM, SIGURG};
31 
32 static pthread_mutex_t lwpinfo_thread_mtx = PTHREAD_MUTEX_INITIALIZER;
33 static pthread_cond_t lwpinfo_thread_cnd = PTHREAD_COND_INITIALIZER;
34 static volatile size_t lwpinfo_thread_done;
35 
36 static void *
lwpinfo_thread(void * arg)37 lwpinfo_thread(void *arg)
38 {
39 	sigset_t s;
40 	volatile void **tcb;
41 
42 	tcb = (volatile void **)arg;
43 
44 	*tcb = _lwp_getprivate();
45 	DPRINTF("Storing tcb[] = %p from thread %d\n", *tcb, _lwp_self());
46 
47 	pthread_setname_np(pthread_self(), "thread %d",
48 	    (void *)(intptr_t)_lwp_self());
49 
50 	sigemptyset(&s);
51 	pthread_mutex_lock(&lwpinfo_thread_mtx);
52 	sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
53 	lwpinfo_thread_done++;
54 	pthread_sigmask(SIG_BLOCK, &s, NULL);
55 	pthread_cond_signal(&lwpinfo_thread_cnd);
56 	pthread_mutex_unlock(&lwpinfo_thread_mtx);
57 
58 	return infinite_thread(NULL);
59 }
60 
61 static void
traceme_lwpinfo(const size_t threads,const char * iter)62 traceme_lwpinfo(const size_t threads, const char *iter)
63 {
64 	const int sigval = SIGSTOP;
65 	const int sigval2 = SIGINT;
66 	pid_t child, wpid;
67 #if defined(TWAIT_HAVE_STATUS)
68 	int status;
69 #endif
70 	struct ptrace_lwpinfo lwp = {0, 0};
71 	struct ptrace_lwpstatus lwpstatus = {0};
72 	struct ptrace_siginfo info;
73 	void *private;
74 	char *name;
75 	char namebuf[PL_LNAMELEN];
76 	volatile void *tcb[4];
77 	bool found;
78 	sigset_t s;
79 
80 	/* Maximum number of supported threads in this test */
81 	pthread_t t[__arraycount(tcb) - 1];
82 	size_t n, m;
83 	int rv;
84 	size_t bytes_read;
85 
86 	struct ptrace_io_desc io;
87 	sigset_t sigmask;
88 
89 	ATF_REQUIRE(__arraycount(t) >= threads);
90 	memset(tcb, 0, sizeof(tcb));
91 
92 	DPRINTF("Before forking process PID=%d\n", getpid());
93 	SYSCALL_REQUIRE((child = fork()) != -1);
94 	if (child == 0) {
95 		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
96 		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
97 
98 		tcb[0] = _lwp_getprivate();
99 		DPRINTF("Storing tcb[0] = %p\n", tcb[0]);
100 
101 		pthread_setname_np(pthread_self(), "thread %d",
102 		    (void *)(intptr_t)_lwp_self());
103 
104 		sigemptyset(&s);
105 		sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
106 		pthread_sigmask(SIG_BLOCK, &s, NULL);
107 
108 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
109 		FORKEE_ASSERT(raise(sigval) == 0);
110 
111 		for (n = 0; n < threads; n++) {
112 			rv = pthread_create(&t[n], NULL, lwpinfo_thread,
113 			    &tcb[n + 1]);
114 			FORKEE_ASSERT(rv == 0);
115 		}
116 
117 		pthread_mutex_lock(&lwpinfo_thread_mtx);
118 		while (lwpinfo_thread_done < threads) {
119 			pthread_cond_wait(&lwpinfo_thread_cnd,
120 			    &lwpinfo_thread_mtx);
121 		}
122 		pthread_mutex_unlock(&lwpinfo_thread_mtx);
123 
124 		DPRINTF("Before raising %s from child\n", strsignal(sigval2));
125 		FORKEE_ASSERT(raise(sigval2) == 0);
126 
127 		/* NOTREACHED */
128 		FORKEE_ASSERTX(0 && "Not reached");
129 	}
130 	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
131 
132 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
133 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
134 
135 	validate_status_stopped(status, sigval);
136 
137 	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
138 	SYSCALL_REQUIRE(
139 	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
140 
141 	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
142 	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
143 	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
144 	    info.psi_siginfo.si_errno);
145 
146 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
147 	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
148 
149 	if (strstr(iter, "LWPINFO") != NULL) {
150 		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
151 		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
152 		    != -1);
153 
154 		DPRINTF("Assert that there exists a single thread only\n");
155 		ATF_REQUIRE(lwp.pl_lwpid > 0);
156 
157 		DPRINTF("Assert that lwp thread %d received event "
158 		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
159 		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
160 
161 		if (strstr(iter, "LWPSTATUS") != NULL) {
162 			DPRINTF("Before calling ptrace(2) with PT_LWPSTATUS "
163 			    "for child\n");
164 			lwpstatus.pl_lwpid = lwp.pl_lwpid;
165 			SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child, &lwpstatus,
166 			    sizeof(lwpstatus)) != -1);
167 		}
168 
169 		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
170 		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
171 		    != -1);
172 
173 		DPRINTF("Assert that there exists a single thread only\n");
174 		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
175 	} else {
176 		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
177 		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
178 		    sizeof(lwpstatus)) != -1);
179 
180 		DPRINTF("Assert that there exists a single thread only %d\n", lwpstatus.pl_lwpid);
181 		ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
182 
183 		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
184 		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
185 		    sizeof(lwpstatus)) != -1);
186 
187 		DPRINTF("Assert that there exists a single thread only\n");
188 		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
189 	}
190 
191 	DPRINTF("Before resuming the child process where it left off and "
192 	    "without signal to be sent\n");
193 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
194 
195 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
196 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
197 
198 	validate_status_stopped(status, sigval2);
199 
200 	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
201 	SYSCALL_REQUIRE(
202 	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
203 
204 	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
205 	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
206 	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
207 	    info.psi_siginfo.si_errno);
208 
209 	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval2);
210 	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
211 
212 	memset(&lwp, 0, sizeof(lwp));
213 	memset(&lwpstatus, 0, sizeof(lwpstatus));
214 
215 	memset(&io, 0, sizeof(io));
216 
217 	bytes_read = 0;
218 	io.piod_op = PIOD_READ_D;
219 	io.piod_len = sizeof(tcb);
220 
221 	do {
222 		io.piod_addr = (char *)&tcb + bytes_read;
223 		io.piod_offs = io.piod_addr;
224 
225 		rv = ptrace(PT_IO, child, &io, sizeof(io));
226 		ATF_REQUIRE(rv != -1 && io.piod_len != 0);
227 
228 		bytes_read += io.piod_len;
229 		io.piod_len = sizeof(tcb) - bytes_read;
230 	} while (bytes_read < sizeof(tcb));
231 
232 	for (n = 0; n <= threads; n++) {
233 		if (strstr(iter, "LWPINFO") != NULL) {
234 			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
235 			    "child\n");
236 			SYSCALL_REQUIRE(
237 			    ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
238 			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
239 
240 			DPRINTF("Assert that the thread exists\n");
241 			ATF_REQUIRE(lwp.pl_lwpid > 0);
242 
243 			DPRINTF("Assert that lwp thread %d received expected "
244 			    "event\n", lwp.pl_lwpid);
245 			FORKEE_ASSERT_EQ(lwp.pl_event,
246 			    info.psi_lwpid == lwp.pl_lwpid ?
247 			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
248 
249 			if (strstr(iter, "LWPSTATUS") != NULL) {
250 				DPRINTF("Before calling ptrace(2) with "
251 				    "PT_LWPSTATUS for child\n");
252 				lwpstatus.pl_lwpid = lwp.pl_lwpid;
253 				SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child,
254 				    &lwpstatus, sizeof(lwpstatus)) != -1);
255 
256 				goto check_lwpstatus;
257 			}
258 		} else {
259 			DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for "
260 			    "child\n");
261 			SYSCALL_REQUIRE(
262 			    ptrace(PT_LWPNEXT, child, &lwpstatus,
263 			    sizeof(lwpstatus)) != -1);
264 			DPRINTF("LWP=%d\n", lwpstatus.pl_lwpid);
265 
266 			DPRINTF("Assert that the thread exists\n");
267 			ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
268 
269 		check_lwpstatus:
270 
271 			if (strstr(iter, "pl_sigmask") != NULL) {
272 				sigmask = lwpstatus.pl_sigmask;
273 
274 				DPRINTF("Retrieved sigmask: "
275 				    "%02x%02x%02x%02x\n",
276 				    sigmask.__bits[0], sigmask.__bits[1],
277 				    sigmask.__bits[2], sigmask.__bits[3]);
278 
279 				found = false;
280 				for (m = 0;
281 				     m < __arraycount(lwpinfo_thread_sigmask);
282 				     m++) {
283 					if (sigismember(&sigmask,
284 					    lwpinfo_thread_sigmask[m])) {
285 						found = true;
286 						lwpinfo_thread_sigmask[m] = 0;
287 						break;
288 					}
289 				}
290 				ATF_REQUIRE(found == true);
291 			} else if (strstr(iter, "pl_name") != NULL) {
292 				name = lwpstatus.pl_name;
293 
294 				DPRINTF("Retrieved thread name: "
295 				    "%s\n", name);
296 
297 				snprintf(namebuf, sizeof namebuf, "thread %d",
298 				    lwpstatus.pl_lwpid);
299 
300 				ATF_REQUIRE(strcmp(name, namebuf) == 0);
301 			} else if (strstr(iter, "pl_private") != NULL) {
302 				private = lwpstatus.pl_private;
303 
304 				DPRINTF("Retrieved thread private pointer: "
305 				    "%p\n", private);
306 
307 				found = false;
308 				for (m = 0; m < __arraycount(tcb); m++) {
309 					DPRINTF("Comparing %p and %p\n",
310 					    private, tcb[m]);
311 					if (private == tcb[m]) {
312 						found = true;
313 						break;
314 					}
315 				}
316 				ATF_REQUIRE(found == true);
317 			}
318 		}
319 	}
320 
321 	if (strstr(iter, "LWPINFO") != NULL) {
322 		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
323 		    "child\n");
324 		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
325 		    != -1);
326 		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
327 
328 		DPRINTF("Assert that there are no more threads\n");
329 		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
330 	} else {
331 		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
332 		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
333 		    sizeof(lwpstatus)) != -1);
334 
335 		DPRINTF("Assert that there exists a single thread only\n");
336 		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
337 	}
338 
339 	DPRINTF("Before resuming the child process where it left off and "
340 	    "without signal to be sent\n");
341 	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, SIGKILL) != -1);
342 
343 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
344 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
345 
346 	validate_status_signaled(status, SIGKILL, 0);
347 
348 	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
349 	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
350 }
351 
352 #define TRACEME_LWPINFO(test, threads, iter)				\
353 ATF_TC(test);								\
354 ATF_TC_HEAD(test, tc)							\
355 {									\
356 	atf_tc_set_md_var(tc, "descr",					\
357 	    "Verify " iter " with the child with " #threads		\
358 	    " spawned extra threads");					\
359 }									\
360 									\
361 ATF_TC_BODY(test, tc)							\
362 {									\
363 									\
364 	traceme_lwpinfo(threads, iter);					\
365 }
366 
367 TRACEME_LWPINFO(traceme_lwpinfo0, 0, "LWPINFO")
368 TRACEME_LWPINFO(traceme_lwpinfo1, 1, "LWPINFO")
369 TRACEME_LWPINFO(traceme_lwpinfo2, 2, "LWPINFO")
370 TRACEME_LWPINFO(traceme_lwpinfo3, 3, "LWPINFO")
371 
372 TRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus, 0, "LWPINFO+LWPSTATUS")
373 TRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus, 1, "LWPINFO+LWPSTATUS")
374 TRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus, 2, "LWPINFO+LWPSTATUS")
375 TRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus, 3, "LWPINFO+LWPSTATUS")
376 
377 TRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_sigmask, 0,
378     "LWPINFO+LWPSTATUS+pl_sigmask")
379 TRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_sigmask, 1,
380     "LWPINFO+LWPSTATUS+pl_sigmask")
381 TRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_sigmask, 2,
382     "LWPINFO+LWPSTATUS+pl_sigmask")
383 TRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_sigmask, 3,
384     "LWPINFO+LWPSTATUS+pl_sigmask")
385 
386 TRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_name, 0,
387     "LWPINFO+LWPSTATUS+pl_name")
388 TRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_name, 1,
389     "LWPINFO+LWPSTATUS+pl_name")
390 TRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_name, 2,
391     "LWPINFO+LWPSTATUS+pl_name")
392 TRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_name, 3,
393     "LWPINFO+LWPSTATUS+pl_name")
394 
395 TRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_private, 0,
396     "LWPINFO+LWPSTATUS+pl_private")
397 TRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_private, 1,
398     "LWPINFO+LWPSTATUS+pl_private")
399 TRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_private, 2,
400     "LWPINFO+LWPSTATUS+pl_private")
401 TRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_private, 3,
402     "LWPINFO+LWPSTATUS+pl_private")
403 
404 TRACEME_LWPINFO(traceme_lwpnext0, 0, "LWPNEXT")
405 TRACEME_LWPINFO(traceme_lwpnext1, 1, "LWPNEXT")
406 TRACEME_LWPINFO(traceme_lwpnext2, 2, "LWPNEXT")
407 TRACEME_LWPINFO(traceme_lwpnext3, 3, "LWPNEXT")
408 
409 TRACEME_LWPINFO(traceme_lwpnext0_pl_sigmask, 0, "LWPNEXT+pl_sigmask")
410 TRACEME_LWPINFO(traceme_lwpnext1_pl_sigmask, 1, "LWPNEXT+pl_sigmask")
411 TRACEME_LWPINFO(traceme_lwpnext2_pl_sigmask, 2, "LWPNEXT+pl_sigmask")
412 TRACEME_LWPINFO(traceme_lwpnext3_pl_sigmask, 3, "LWPNEXT+pl_sigmask")
413 
414 TRACEME_LWPINFO(traceme_lwpnext0_pl_name, 0, "LWPNEXT+pl_name")
415 TRACEME_LWPINFO(traceme_lwpnext1_pl_name, 1, "LWPNEXT+pl_name")
416 TRACEME_LWPINFO(traceme_lwpnext2_pl_name, 2, "LWPNEXT+pl_name")
417 TRACEME_LWPINFO(traceme_lwpnext3_pl_name, 3, "LWPNEXT+pl_name")
418 
419 TRACEME_LWPINFO(traceme_lwpnext0_pl_private, 0, "LWPNEXT+pl_private")
420 TRACEME_LWPINFO(traceme_lwpnext1_pl_private, 1, "LWPNEXT+pl_private")
421 TRACEME_LWPINFO(traceme_lwpnext2_pl_private, 2, "LWPNEXT+pl_private")
422 TRACEME_LWPINFO(traceme_lwpnext3_pl_private, 3, "LWPNEXT+pl_private")
423 
424 /// ----------------------------------------------------------------------------
425 
426 #if defined(TWAIT_HAVE_PID)
427 static void
attach_lwpinfo(const int threads)428 attach_lwpinfo(const int threads)
429 {
430 	const int sigval = SIGINT;
431 	struct msg_fds parent_tracee, parent_tracer;
432 	const int exitval_tracer = 10;
433 	pid_t tracee, tracer, wpid;
434 	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
435 #if defined(TWAIT_HAVE_STATUS)
436 	int status;
437 #endif
438 	struct ptrace_lwpinfo lwp = {0, 0};
439 	struct ptrace_siginfo info;
440 
441 	/* Maximum number of supported threads in this test */
442 	pthread_t t[3];
443 	int n, rv;
444 
445 	DPRINTF("Spawn tracee\n");
446 	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
447 	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
448 	tracee = atf_utils_fork();
449 	if (tracee == 0) {
450 		/* Wait for message from the parent */
451 		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
452 
453 		CHILD_FROM_PARENT("spawn threads", parent_tracee, msg);
454 
455 		for (n = 0; n < threads; n++) {
456 			rv = pthread_create(&t[n], NULL, infinite_thread, NULL);
457 			FORKEE_ASSERT(rv == 0);
458 		}
459 
460 		CHILD_TO_PARENT("tracee exit", parent_tracee, msg);
461 
462 		DPRINTF("Before raising %s from child\n", strsignal(sigval));
463 		FORKEE_ASSERT(raise(sigval) == 0);
464 
465 		/* NOTREACHED */
466 		FORKEE_ASSERTX(0 && "Not reached");
467 	}
468 	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
469 
470 	DPRINTF("Spawn debugger\n");
471 	tracer = atf_utils_fork();
472 	if (tracer == 0) {
473 		/* No IPC to communicate with the child */
474 		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
475 		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
476 
477 		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
478 		FORKEE_REQUIRE_SUCCESS(
479 		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
480 
481 		forkee_status_stopped(status, SIGSTOP);
482 
483 		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
484 		    "tracee");
485 		FORKEE_ASSERT(
486 		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
487 
488 		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
489 		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
490 		    "si_errno=%#x\n",
491 		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
492 		    info.psi_siginfo.si_errno);
493 
494 		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
495 		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
496 
497 		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
498 		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
499 		    != -1);
500 
501 		DPRINTF("Assert that there exists a thread\n");
502 		FORKEE_ASSERTX(lwp.pl_lwpid > 0);
503 
504 		DPRINTF("Assert that lwp thread %d received event "
505 		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
506 		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
507 
508 		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
509 		    "tracee\n");
510 		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
511 		    != -1);
512 
513 		DPRINTF("Assert that there are no more lwp threads in "
514 		    "tracee\n");
515 		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
516 
517 		/* Resume tracee with PT_CONTINUE */
518 		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
519 
520 		/* Inform parent that tracer has attached to tracee */
521 		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
522 
523 		/* Wait for parent */
524 		CHILD_FROM_PARENT("tracer wait", parent_tracer, msg);
525 
526 		/* Wait for tracee and assert that it raised a signal */
527 		FORKEE_REQUIRE_SUCCESS(
528 		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
529 
530 		forkee_status_stopped(status, SIGINT);
531 
532 		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
533 		    "child");
534 		FORKEE_ASSERT(
535 		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
536 
537 		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
538 		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
539 		    "si_errno=%#x\n",
540 		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
541 		    info.psi_siginfo.si_errno);
542 
543 		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
544 		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
545 
546 		memset(&lwp, 0, sizeof(lwp));
547 
548 		for (n = 0; n <= threads; n++) {
549 			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
550 			    "child\n");
551 			FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp,
552 			    sizeof(lwp)) != -1);
553 			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
554 
555 			DPRINTF("Assert that the thread exists\n");
556 			FORKEE_ASSERT(lwp.pl_lwpid > 0);
557 
558 			DPRINTF("Assert that lwp thread %d received expected "
559 			    "event\n", lwp.pl_lwpid);
560 			FORKEE_ASSERT_EQ(lwp.pl_event,
561 			    info.psi_lwpid == lwp.pl_lwpid ?
562 			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
563 		}
564 		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
565 		    "tracee\n");
566 		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
567 		    != -1);
568 		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
569 
570 		DPRINTF("Assert that there are no more threads\n");
571 		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
572 
573 		DPRINTF("Before resuming the child process where it left off "
574 		    "and without signal to be sent\n");
575 		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, SIGKILL)
576 		    != -1);
577 
578 		/* Wait for tracee and assert that it exited */
579 		FORKEE_REQUIRE_SUCCESS(
580 		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
581 
582 		forkee_status_signaled(status, SIGKILL, 0);
583 
584 		DPRINTF("Before exiting of the tracer process\n");
585 		_exit(exitval_tracer);
586 	}
587 
588 	DPRINTF("Wait for the tracer to attach to the tracee\n");
589 	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
590 
591 	DPRINTF("Resume the tracee and spawn threads\n");
592 	PARENT_TO_CHILD("spawn threads", parent_tracee, msg);
593 
594 	DPRINTF("Resume the tracee and let it exit\n");
595 	PARENT_FROM_CHILD("tracee exit", parent_tracee, msg);
596 
597 	DPRINTF("Resume the tracer and let it detect multiple threads\n");
598 	PARENT_TO_CHILD("tracer wait", parent_tracer, msg);
599 
600 	DPRINTF("Wait for tracer to finish its job and exit - calling %s()\n",
601 	    TWAIT_FNAME);
602 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
603 	    tracer);
604 
605 	validate_status_exited(status, exitval_tracer);
606 
607 	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
608 	    TWAIT_FNAME);
609 	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
610 	    tracee);
611 
612 	validate_status_signaled(status, SIGKILL, 0);
613 
614 	msg_close(&parent_tracer);
615 	msg_close(&parent_tracee);
616 }
617 
618 #define ATTACH_LWPINFO(test, threads)					\
619 ATF_TC(test);								\
620 ATF_TC_HEAD(test, tc)							\
621 {									\
622 	atf_tc_set_md_var(tc, "descr",					\
623 	    "Verify LWPINFO with the child with " #threads		\
624 	    " spawned extra threads (tracer is not the original "	\
625 	    "parent)");							\
626 }									\
627 									\
628 ATF_TC_BODY(test, tc)							\
629 {									\
630 									\
631 	attach_lwpinfo(threads);					\
632 }
633 
634 ATTACH_LWPINFO(attach_lwpinfo0, 0)
635 ATTACH_LWPINFO(attach_lwpinfo1, 1)
636 ATTACH_LWPINFO(attach_lwpinfo2, 2)
637 ATTACH_LWPINFO(attach_lwpinfo3, 3)
638 #endif
639 
640 #define ATF_TP_ADD_TCS_PTRACE_WAIT_LWP() \
641 	ATF_TP_ADD_TC(tp, traceme_lwpinfo0); \
642 	ATF_TP_ADD_TC(tp, traceme_lwpinfo1); \
643 	ATF_TP_ADD_TC(tp, traceme_lwpinfo2); \
644 	ATF_TP_ADD_TC(tp, traceme_lwpinfo3); \
645 	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus); \
646 	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus); \
647 	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus); \
648 	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus); \
649 	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_sigmask); \
650 	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_sigmask); \
651 	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_sigmask); \
652 	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_sigmask); \
653 	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_name); \
654 	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_name); \
655 	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_name); \
656 	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_name); \
657 	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_private); \
658 	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_private); \
659 	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_private); \
660 	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_private); \
661 	ATF_TP_ADD_TC(tp, traceme_lwpnext0); \
662 	ATF_TP_ADD_TC(tp, traceme_lwpnext1); \
663 	ATF_TP_ADD_TC(tp, traceme_lwpnext2); \
664 	ATF_TP_ADD_TC(tp, traceme_lwpnext3); \
665 	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_sigmask); \
666 	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_sigmask); \
667 	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_sigmask); \
668 	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_sigmask); \
669 	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_name); \
670 	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_name); \
671 	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_name); \
672 	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_name); \
673 	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_private); \
674 	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_private); \
675 	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_private); \
676 	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_private); \
677 	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo0); \
678 	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo1); \
679 	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo2); \
680 	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo3);
681