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