t_ptrace_wait.c revision 1.181
11.181Skamil/*	$NetBSD: t_ptrace_wait.c,v 1.181 2020/05/04 23:49:31 kamil Exp $	*/
21.1Skamil
31.1Skamil/*-
41.181Skamil * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
51.1Skamil * All rights reserved.
61.1Skamil *
71.1Skamil * Redistribution and use in source and binary forms, with or without
81.1Skamil * modification, are permitted provided that the following conditions
91.1Skamil * are met:
101.1Skamil * 1. Redistributions of source code must retain the above copyright
111.1Skamil *    notice, this list of conditions and the following disclaimer.
121.1Skamil * 2. Redistributions in binary form must reproduce the above copyright
131.1Skamil *    notice, this list of conditions and the following disclaimer in the
141.1Skamil *    documentation and/or other materials provided with the distribution.
151.1Skamil *
161.1Skamil * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
171.1Skamil * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
181.1Skamil * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
191.1Skamil * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
201.1Skamil * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
211.1Skamil * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
221.1Skamil * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
231.1Skamil * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
241.1Skamil * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
251.1Skamil * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
261.1Skamil * POSSIBILITY OF SUCH DAMAGE.
271.1Skamil */
281.1Skamil
291.1Skamil#include <sys/cdefs.h>
301.181Skamil__RCSID("$NetBSD: t_ptrace_wait.c,v 1.181 2020/05/04 23:49:31 kamil Exp $");
311.143Skamil
321.143Skamil#define __LEGACY_PT_LWPINFO
331.1Skamil
341.1Skamil#include <sys/param.h>
351.1Skamil#include <sys/types.h>
361.130Smgorny#include <sys/exec_elf.h>
371.39Skamil#include <sys/mman.h>
381.1Skamil#include <sys/ptrace.h>
391.1Skamil#include <sys/resource.h>
401.1Skamil#include <sys/stat.h>
411.1Skamil#include <sys/syscall.h>
421.1Skamil#include <sys/sysctl.h>
431.129Smgorny#include <sys/uio.h>
441.1Skamil#include <sys/wait.h>
451.1Skamil#include <machine/reg.h>
461.132Skamil#include <assert.h>
471.1Skamil#include <elf.h>
481.1Skamil#include <err.h>
491.1Skamil#include <errno.h>
501.130Smgorny#include <fcntl.h>
511.1Skamil#include <lwp.h>
521.77Skamil#include <pthread.h>
531.1Skamil#include <sched.h>
541.1Skamil#include <signal.h>
551.124Skamil#include <spawn.h>
561.1Skamil#include <stdint.h>
571.1Skamil#include <stdio.h>
581.1Skamil#include <stdlib.h>
591.1Skamil#include <strings.h>
601.26Skamil#include <time.h>
611.1Skamil#include <unistd.h>
621.1Skamil
631.121Smgorny#if defined(__i386__) || defined(__x86_64__)
641.121Smgorny#include <cpuid.h>
651.121Smgorny#include <x86/cpu_extended_state.h>
661.129Smgorny#include <x86/specialreg.h>
671.121Smgorny#endif
681.121Smgorny
691.130Smgorny#include <libelf.h>
701.130Smgorny#include <gelf.h>
711.130Smgorny
721.1Skamil#include <atf-c.h>
731.1Skamil
741.165Skamil#ifdef ENABLE_TESTS
751.165Skamil
761.132Skamil/* Assumptions in the kernel code that must be kept. */
771.171Skamil__CTASSERT(sizeof(((struct ptrace_state *)0)->pe_report_event) ==
781.171Skamil    sizeof(((siginfo_t *)0)->si_pe_report_event));
791.171Skamil__CTASSERT(sizeof(((struct ptrace_state *)0)->pe_other_pid) ==
801.171Skamil    sizeof(((siginfo_t *)0)->si_pe_other_pid));
811.171Skamil__CTASSERT(sizeof(((struct ptrace_state *)0)->pe_lwp) ==
821.171Skamil    sizeof(((siginfo_t *)0)->si_pe_lwp));
831.171Skamil__CTASSERT(sizeof(((struct ptrace_state *)0)->pe_other_pid) ==
841.171Skamil    sizeof(((struct ptrace_state *)0)->pe_lwp));
851.132Skamil
861.1Skamil#include "h_macros.h"
871.1Skamil
881.1Skamil#include "t_ptrace_wait.h"
891.1Skamil#include "msg.h"
901.1Skamil
911.13Schristos#define SYSCALL_REQUIRE(expr) ATF_REQUIRE_MSG(expr, "%s: %s", # expr, \
921.13Schristos    strerror(errno))
931.18Schristos#define SYSCALL_REQUIRE_ERRNO(res, exp) ATF_REQUIRE_MSG(res == exp, \
941.18Schristos    "%d(%s) != %d", res, strerror(res), exp)
951.13Schristos
961.152Skamilstatic int debug = 0;
971.13Schristos
981.13Schristos#define DPRINTF(a, ...)	do  \
991.123Skamil	if (debug) \
1001.142Skamil	printf("%s() %d.%d %s:%d " a, \
1011.142Skamil	__func__, getpid(), _lwp_self(), __FILE__, __LINE__,  ##__VA_ARGS__); \
1021.13Schristos    while (/*CONSTCOND*/0)
1031.1Skamil
1041.34Skamil/// ----------------------------------------------------------------------------
1051.34Skamil
1061.37SkamilATF_TC(traceme_pid1_parent);
1071.37SkamilATF_TC_HEAD(traceme_pid1_parent, tc)
1081.37Skamil{
1091.181Skamil	atf_tc_set_md_var(tc, "descr",
1101.181Skamil	    "Verify that PT_TRACE_ME is not allowed when our parent is PID1");
1111.43Skamil}
1121.43Skamil
1131.181SkamilATF_TC_BODY(traceme_pid1_parent, tc)
1141.59Skamil{
1151.181Skamil	struct msg_fds parent_child;
1161.181Skamil	int exitval_child1 = 1, exitval_child2 = 2;
1171.181Skamil	pid_t child1, child2, wpid;
1181.59Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
1191.59Skamil#if defined(TWAIT_HAVE_STATUS)
1201.59Skamil	int status;
1211.59Skamil#endif
1221.94Skamil
1231.181Skamil	SYSCALL_REQUIRE(msg_open(&parent_child) == 0);
1241.61Skre
1251.181Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
1261.181Skamil	SYSCALL_REQUIRE((child1 = fork()) != -1);
1271.181Skamil	if (child1 == 0) {
1281.181Skamil		DPRINTF("Before forking process PID=%d\n", getpid());
1291.181Skamil		SYSCALL_REQUIRE((child2 = fork()) != -1);
1301.181Skamil		if (child2 != 0) {
1311.181Skamil			DPRINTF("Parent process PID=%d, child2's PID=%d\n",
1321.181Skamil			    getpid(), child2);
1331.181Skamil			_exit(exitval_child1);
1341.94Skamil		}
1351.181Skamil		CHILD_FROM_PARENT("exit child1", parent_child, msg);
1361.94Skamil
1371.181Skamil		DPRINTF("Assert that our parent is PID1 (initproc)\n");
1381.181Skamil		FORKEE_ASSERT_EQ(getppid(), 1);
1391.94Skamil
1401.181Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1411.181Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) == -1);
1421.181Skamil		SYSCALL_REQUIRE_ERRNO(errno, EPERM);
1431.94Skamil
1441.181Skamil		CHILD_TO_PARENT("child2 exiting", parent_child, msg);
1451.94Skamil
1461.181Skamil		_exit(exitval_child2);
1471.181Skamil	}
1481.181Skamil	DPRINTF("Parent process PID=%d, child1's PID=%d\n", getpid(), child1);
1491.94Skamil
1501.181Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1511.181Skamil	TWAIT_REQUIRE_SUCCESS(
1521.181Skamil	    wpid = TWAIT_GENERIC(child1, &status, WEXITED), child1);
1531.94Skamil
1541.181Skamil	validate_status_exited(status, exitval_child1);
1551.94Skamil
1561.181Skamil	DPRINTF("Notify that child1 is dead\n");
1571.181Skamil	PARENT_TO_CHILD("exit child1", parent_child, msg);
1581.94Skamil
1591.181Skamil	DPRINTF("Wait for exiting of child2\n");
1601.181Skamil	PARENT_FROM_CHILD("child2 exiting", parent_child, msg);
1611.181Skamil}
1621.94Skamil
1631.181Skamil/// ----------------------------------------------------------------------------
1641.59Skamil
1651.181Skamilstatic void
1661.181Skamiltraceme_vfork_exec(bool masked, bool ignored)
1671.181Skamil{
1681.181Skamil	const int sigval = SIGTRAP;
1691.181Skamil	pid_t child, wpid;
1701.181Skamil#if defined(TWAIT_HAVE_STATUS)
1711.181Skamil	int status;
1721.181Skamil#endif
1731.181Skamil	struct sigaction sa;
1741.181Skamil	struct ptrace_siginfo info;
1751.181Skamil	sigset_t intmask;
1761.181Skamil	struct kinfo_proc2 kp;
1771.181Skamil	size_t len = sizeof(kp);
1781.59Skamil
1791.181Skamil	int name[6];
1801.181Skamil	const size_t namelen = __arraycount(name);
1811.181Skamil	ki_sigset_t kp_sigmask;
1821.181Skamil	ki_sigset_t kp_sigignore;
1831.59Skamil
1841.181Skamil	memset(&info, 0, sizeof(info));
1851.94Skamil
1861.181Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
1871.181Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
1881.181Skamil	if (child == 0) {
1891.181Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1901.181Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
1911.94Skamil
1921.94Skamil		if (masked) {
1931.181Skamil			sigemptyset(&intmask);
1941.181Skamil			sigaddset(&intmask, sigval);
1951.181Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
1961.181Skamil		}
1971.94Skamil
1981.181Skamil		if (ignored) {
1991.181Skamil			memset(&sa, 0, sizeof(sa));
2001.181Skamil			sa.sa_handler = SIG_IGN;
2011.181Skamil			sigemptyset(&sa.sa_mask);
2021.181Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
2031.94Skamil		}
2041.94Skamil
2051.181Skamil		DPRINTF("Before calling execve(2) from child\n");
2061.181Skamil		execlp("/bin/echo", "/bin/echo", NULL);
2071.181Skamil
2081.181Skamil		/* NOTREACHED */
2091.181Skamil		FORKEE_ASSERTX(0 && "Not reached");
2101.181Skamil	}
2111.181Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
2121.181Skamil
2131.181Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2141.181Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2151.94Skamil
2161.181Skamil	validate_status_stopped(status, sigval);
2171.94Skamil
2181.181Skamil	name[0] = CTL_KERN,
2191.181Skamil	name[1] = KERN_PROC2,
2201.181Skamil	name[2] = KERN_PROC_PID;
2211.181Skamil	name[3] = getpid();
2221.181Skamil	name[4] = sizeof(kp);
2231.181Skamil	name[5] = 1;
2241.59Skamil
2251.181Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
2261.59Skamil
2271.181Skamil	if (masked)
2281.181Skamil		kp_sigmask = kp.p_sigmask;
2291.59Skamil
2301.181Skamil	if (ignored)
2311.181Skamil		kp_sigignore = kp.p_sigignore;
2321.71Skamil
2331.181Skamil	name[3] = getpid();
2341.59Skamil
2351.181Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
2361.59Skamil
2371.181Skamil	if (masked) {
2381.181Skamil		DPRINTF("kp_sigmask="
2391.181Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
2401.181Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
2411.181Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
2421.59Skamil
2431.181Skamil	        DPRINTF("kp.p_sigmask="
2441.181Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
2451.181Skamil	            kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
2461.181Skamil	            kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
2471.59Skamil
2481.181Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
2491.181Skamil		    sizeof(kp_sigmask)));
2501.181Skamil	}
2511.59Skamil
2521.181Skamil	if (ignored) {
2531.181Skamil		DPRINTF("kp_sigignore="
2541.181Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
2551.181Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
2561.181Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
2571.59Skamil
2581.181Skamil	        DPRINTF("kp.p_sigignore="
2591.181Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
2601.181Skamil	            kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
2611.181Skamil	            kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
2621.59Skamil
2631.181Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
2641.181Skamil		    sizeof(kp_sigignore)));
2651.181Skamil	}
2661.59Skamil
2671.181Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
2681.181Skamil	SYSCALL_REQUIRE(
2691.181Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
2701.59Skamil
2711.181Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
2721.181Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
2731.181Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
2741.181Skamil	    info.psi_siginfo.si_errno);
2751.71Skamil
2761.181Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
2771.181Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
2781.59Skamil
2791.181Skamil	DPRINTF("Before resuming the child process where it left off and "
2801.181Skamil	    "without signal to be sent\n");
2811.181Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
2821.59Skamil
2831.181Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2841.181Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2851.94Skamil
2861.181Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2871.181Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
2881.94Skamil}
2891.94Skamil
2901.181Skamil#define TRACEME_VFORK_EXEC(test, masked, ignored)			\
2911.94SkamilATF_TC(test);								\
2921.94SkamilATF_TC_HEAD(test, tc)							\
2931.94Skamil{									\
2941.94Skamil	atf_tc_set_md_var(tc, "descr",					\
2951.181Skamil	    "Verify PT_TRACE_ME followed by exec(3) in a vfork(2)ed "	\
2961.181Skamil	    "child%s%s", masked ? " with masked signal" : "",		\
2971.181Skamil	    masked ? " with ignored signal" : "");			\
2981.94Skamil}									\
2991.94Skamil									\
3001.94SkamilATF_TC_BODY(test, tc)							\
3011.94Skamil{									\
3021.94Skamil									\
3031.181Skamil	traceme_vfork_exec(masked, ignored);				\
3041.94Skamil}
3051.94Skamil
3061.181SkamilTRACEME_VFORK_EXEC(traceme_vfork_exec, false, false)
3071.181SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalmasked_exec, true, false)
3081.181SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalignored_exec, false, true)
3091.59Skamil
3101.59Skamil/// ----------------------------------------------------------------------------
3111.59Skamil
3121.59Skamil#if defined(TWAIT_HAVE_PID)
3131.59Skamilstatic void
3141.67Skamiltracer_sees_terminaton_before_the_parent_raw(bool notimeout, bool unrelated,
3151.67Skamil                                             bool stopped)
3161.1Skamil{
3171.51Skamil	/*
3181.51Skamil	 * notimeout - disable timeout in await zombie function
3191.51Skamil	 * unrelated - attach from unrelated tracer reparented to initproc
3201.67Skamil	 * stopped - attach to a stopped process
3211.51Skamil	 */
3221.1Skamil
3231.1Skamil	struct msg_fds parent_tracee, parent_tracer;
3241.1Skamil	const int exitval_tracee = 5;
3251.1Skamil	const int exitval_tracer = 10;
3261.1Skamil	pid_t tracee, tracer, wpid;
3271.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
3281.1Skamil#if defined(TWAIT_HAVE_STATUS)
3291.1Skamil	int status;
3301.1Skamil#endif
3311.1Skamil
3321.67Skamil	/*
3331.67Skamil	 * Only a subset of options are supported.
3341.67Skamil	 */
3351.67Skamil	ATF_REQUIRE((!notimeout && !unrelated && !stopped) ||
3361.67Skamil	            (!notimeout && unrelated && !stopped) ||
3371.67Skamil	            (notimeout && !unrelated && !stopped) ||
3381.67Skamil	            (!notimeout && unrelated && stopped));
3391.67Skamil
3401.13Schristos	DPRINTF("Spawn tracee\n");
3411.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
3421.1Skamil	tracee = atf_utils_fork();
3431.1Skamil	if (tracee == 0) {
3441.67Skamil		if (stopped) {
3451.67Skamil			DPRINTF("Stop self PID %d\n", getpid());
3461.67Skamil			raise(SIGSTOP);
3471.67Skamil		}
3481.67Skamil
3491.1Skamil		// Wait for parent to let us exit
3501.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
3511.1Skamil		_exit(exitval_tracee);
3521.1Skamil	}
3531.1Skamil
3541.13Schristos	DPRINTF("Spawn debugger\n");
3551.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
3561.1Skamil	tracer = atf_utils_fork();
3571.1Skamil	if (tracer == 0) {
3581.51Skamil		if(unrelated) {
3591.51Skamil			/* Fork again and drop parent to reattach to PID 1 */
3601.51Skamil			tracer = atf_utils_fork();
3611.51Skamil			if (tracer != 0)
3621.51Skamil				_exit(exitval_tracer);
3631.51Skamil		}
3641.51Skamil
3651.67Skamil		if (stopped) {
3661.67Skamil			DPRINTF("Await for a stopped parent PID %d\n", tracee);
3671.67Skamil			await_stopped(tracee);
3681.67Skamil		}
3691.67Skamil
3701.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
3711.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
3721.1Skamil
3731.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
3741.1Skamil		FORKEE_REQUIRE_SUCCESS(
3751.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
3761.1Skamil
3771.1Skamil		forkee_status_stopped(status, SIGSTOP);
3781.1Skamil
3791.1Skamil		/* Resume tracee with PT_CONTINUE */
3801.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
3811.1Skamil
3821.1Skamil		/* Inform parent that tracer has attached to tracee */
3831.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
3841.1Skamil
3851.1Skamil		/* Wait for parent to tell use that tracee should have exited */
3861.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
3871.1Skamil
3881.1Skamil		/* Wait for tracee and assert that it exited */
3891.1Skamil		FORKEE_REQUIRE_SUCCESS(
3901.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
3911.1Skamil
3921.1Skamil		forkee_status_exited(status, exitval_tracee);
3931.13Schristos		DPRINTF("Tracee %d exited with %d\n", tracee, exitval_tracee);
3941.1Skamil
3951.13Schristos		DPRINTF("Before exiting of the tracer process\n");
3961.51Skamil		_exit(unrelated ? 0 /* collect by initproc */ : exitval_tracer);
3971.51Skamil	}
3981.51Skamil
3991.51Skamil	if (unrelated) {
4001.51Skamil		DPRINTF("Wait for the tracer process (direct child) to exit "
4011.51Skamil		    "calling %s()\n", TWAIT_FNAME);
4021.51Skamil		TWAIT_REQUIRE_SUCCESS(
4031.51Skamil		    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
4041.51Skamil
4051.51Skamil		validate_status_exited(status, exitval_tracer);
4061.51Skamil
4071.51Skamil		DPRINTF("Wait for the non-exited tracee process with %s()\n",
4081.51Skamil		    TWAIT_FNAME);
4091.51Skamil		TWAIT_REQUIRE_SUCCESS(
4101.51Skamil		    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
4111.1Skamil	}
4121.1Skamil
4131.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
4141.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
4151.1Skamil
4161.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
4171.1Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
4181.1Skamil
4191.13Schristos	DPRINTF("Detect that tracee is zombie\n");
4201.51Skamil	if (notimeout)
4211.26Skamil		await_zombie_raw(tracee, 0);
4221.26Skamil	else
4231.26Skamil		await_zombie(tracee);
4241.1Skamil
4251.13Schristos	DPRINTF("Assert that there is no status about tracee %d - "
4261.1Skamil	    "Tracer must detect zombie first - calling %s()\n", tracee,
4271.1Skamil	    TWAIT_FNAME);
4281.1Skamil	TWAIT_REQUIRE_SUCCESS(
4291.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
4301.1Skamil
4311.51Skamil	if (unrelated) {
4321.51Skamil		DPRINTF("Resume the tracer and let it detect exited tracee\n");
4331.51Skamil		PARENT_TO_CHILD("Message 2", parent_tracer, msg);
4341.51Skamil	} else {
4351.51Skamil		DPRINTF("Tell the tracer child should have exited\n");
4361.51Skamil		PARENT_TO_CHILD("wait for tracee exit", parent_tracer,  msg);
4371.51Skamil		DPRINTF("Wait for tracer to finish its job and exit - calling "
4381.59Skamil			"%s()\n", TWAIT_FNAME);
4391.51Skamil
4401.51Skamil		DPRINTF("Wait from tracer child to complete waiting for "
4411.59Skamil			"tracee\n");
4421.51Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
4431.51Skamil		    tracer);
4441.1Skamil
4451.51Skamil		validate_status_exited(status, exitval_tracer);
4461.51Skamil	}
4471.1Skamil
4481.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
4491.1Skamil	    TWAIT_FNAME);
4501.51Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
4511.1Skamil
4521.1Skamil	validate_status_exited(status, exitval_tracee);
4531.1Skamil
4541.1Skamil	msg_close(&parent_tracer);
4551.1Skamil	msg_close(&parent_tracee);
4561.1Skamil}
4571.26Skamil
4581.51SkamilATF_TC(tracer_sees_terminaton_before_the_parent);
4591.51SkamilATF_TC_HEAD(tracer_sees_terminaton_before_the_parent, tc)
4601.51Skamil{
4611.51Skamil	atf_tc_set_md_var(tc, "descr",
4621.51Skamil	    "Assert that tracer sees process termination before the parent");
4631.51Skamil}
4641.51Skamil
4651.51SkamilATF_TC_BODY(tracer_sees_terminaton_before_the_parent, tc)
4661.26Skamil{
4671.26Skamil
4681.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, false, false);
4691.26Skamil}
4701.26Skamil
4711.51SkamilATF_TC(tracer_sysctl_lookup_without_duplicates);
4721.51SkamilATF_TC_HEAD(tracer_sysctl_lookup_without_duplicates, tc)
4731.1Skamil{
4741.164Skamil	atf_tc_set_md_var(tc, "timeout", "15");
4751.1Skamil	atf_tc_set_md_var(tc, "descr",
4761.51Skamil	    "Assert that await_zombie() in attach1 always finds a single "
4771.51Skamil	    "process and no other error is reported");
4781.1Skamil}
4791.1Skamil
4801.51SkamilATF_TC_BODY(tracer_sysctl_lookup_without_duplicates, tc)
4811.1Skamil{
4821.51Skamil	time_t start, end;
4831.51Skamil	double diff;
4841.51Skamil	unsigned long N = 0;
4851.1Skamil
4861.51Skamil	/*
4871.51Skamil	 * Reuse this test with tracer_sees_terminaton_before_the_parent_raw().
4881.51Skamil	 * This test body isn't specific to this race, however it's just good
4891.51Skamil	 * enough for this purposes, no need to invent a dedicated code flow.
4901.51Skamil	 */
4911.1Skamil
4921.51Skamil	start = time(NULL);
4931.51Skamil	while (true) {
4941.51Skamil		DPRINTF("Step: %lu\n", N);
4951.67Skamil		tracer_sees_terminaton_before_the_parent_raw(true, false,
4961.67Skamil		                                             false);
4971.51Skamil		end = time(NULL);
4981.51Skamil		diff = difftime(end, start);
4991.51Skamil		if (diff >= 5.0)
5001.51Skamil			break;
5011.51Skamil		++N;
5021.1Skamil	}
5031.51Skamil	DPRINTF("Iterations: %lu\n", N);
5041.51Skamil}
5051.1Skamil
5061.51SkamilATF_TC(unrelated_tracer_sees_terminaton_before_the_parent);
5071.51SkamilATF_TC_HEAD(unrelated_tracer_sees_terminaton_before_the_parent, tc)
5081.51Skamil{
5091.51Skamil	atf_tc_set_md_var(tc, "descr",
5101.51Skamil	    "Assert that tracer sees process termination before the parent");
5111.51Skamil}
5121.1Skamil
5131.51SkamilATF_TC_BODY(unrelated_tracer_sees_terminaton_before_the_parent, tc)
5141.51Skamil{
5151.1Skamil
5161.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, false);
5171.67Skamil}
5181.67Skamil
5191.67SkamilATF_TC(tracer_attach_to_unrelated_stopped_process);
5201.67SkamilATF_TC_HEAD(tracer_attach_to_unrelated_stopped_process, tc)
5211.67Skamil{
5221.67Skamil	atf_tc_set_md_var(tc, "descr",
5231.67Skamil	    "Assert that tracer can attach to an unrelated stopped process");
5241.67Skamil}
5251.67Skamil
5261.67SkamilATF_TC_BODY(tracer_attach_to_unrelated_stopped_process, tc)
5271.67Skamil{
5281.67Skamil
5291.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, true);
5301.1Skamil}
5311.1Skamil#endif
5321.1Skamil
5331.51Skamil/// ----------------------------------------------------------------------------
5341.51Skamil
5351.66Skamilstatic void
5361.66Skamilparent_attach_to_its_child(bool stopped)
5371.1Skamil{
5381.1Skamil	struct msg_fds parent_tracee;
5391.1Skamil	const int exitval_tracee = 5;
5401.1Skamil	pid_t tracee, wpid;
5411.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
5421.1Skamil#if defined(TWAIT_HAVE_STATUS)
5431.1Skamil	int status;
5441.1Skamil#endif
5451.1Skamil
5461.13Schristos	DPRINTF("Spawn tracee\n");
5471.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
5481.1Skamil	tracee = atf_utils_fork();
5491.1Skamil	if (tracee == 0) {
5501.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
5511.13Schristos		DPRINTF("Parent should now attach to tracee\n");
5521.1Skamil
5531.66Skamil		if (stopped) {
5541.66Skamil			DPRINTF("Stop self PID %d\n", getpid());
5551.66Skamil			SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
5561.66Skamil		}
5571.66Skamil
5581.1Skamil		CHILD_FROM_PARENT("Message 2", parent_tracee, msg);
5591.1Skamil		/* Wait for message from the parent */
5601.1Skamil		_exit(exitval_tracee);
5611.1Skamil	}
5621.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
5631.57Skamil
5641.66Skamil	if (stopped) {
5651.66Skamil		DPRINTF("Await for a stopped tracee PID %d\n", tracee);
5661.66Skamil		await_stopped(tracee);
5671.66Skamil	}
5681.66Skamil
5691.13Schristos	DPRINTF("Before calling PT_ATTACH for tracee %d\n", tracee);
5701.13Schristos	SYSCALL_REQUIRE(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
5711.1Skamil
5721.13Schristos	DPRINTF("Wait for the stopped tracee process with %s()\n",
5731.1Skamil	    TWAIT_FNAME);
5741.1Skamil	TWAIT_REQUIRE_SUCCESS(
5751.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
5761.1Skamil
5771.1Skamil	validate_status_stopped(status, SIGSTOP);
5781.1Skamil
5791.13Schristos	DPRINTF("Resume tracee with PT_CONTINUE\n");
5801.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
5811.1Skamil
5821.13Schristos	DPRINTF("Let the tracee exit now\n");
5831.1Skamil	PARENT_TO_CHILD("Message 2", parent_tracee, msg);
5841.1Skamil
5851.13Schristos	DPRINTF("Wait for tracee to exit with %s()\n", TWAIT_FNAME);
5861.1Skamil	TWAIT_REQUIRE_SUCCESS(
5871.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
5881.1Skamil
5891.1Skamil	validate_status_exited(status, exitval_tracee);
5901.1Skamil
5911.13Schristos	DPRINTF("Before calling %s() for tracee\n", TWAIT_FNAME);
5921.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
5931.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0));
5941.1Skamil
5951.1Skamil	msg_close(&parent_tracee);
5961.1Skamil}
5971.1Skamil
5981.66SkamilATF_TC(parent_attach_to_its_child);
5991.66SkamilATF_TC_HEAD(parent_attach_to_its_child, tc)
6001.66Skamil{
6011.66Skamil	atf_tc_set_md_var(tc, "descr",
6021.66Skamil	    "Assert that tracer parent can PT_ATTACH to its child");
6031.66Skamil}
6041.66Skamil
6051.66SkamilATF_TC_BODY(parent_attach_to_its_child, tc)
6061.66Skamil{
6071.66Skamil
6081.66Skamil	parent_attach_to_its_child(false);
6091.66Skamil}
6101.66Skamil
6111.66SkamilATF_TC(parent_attach_to_its_stopped_child);
6121.66SkamilATF_TC_HEAD(parent_attach_to_its_stopped_child, tc)
6131.66Skamil{
6141.66Skamil	atf_tc_set_md_var(tc, "descr",
6151.66Skamil	    "Assert that tracer parent can PT_ATTACH to its stopped child");
6161.66Skamil}
6171.66Skamil
6181.66SkamilATF_TC_BODY(parent_attach_to_its_stopped_child, tc)
6191.66Skamil{
6201.66Skamil
6211.66Skamil	parent_attach_to_its_child(true);
6221.66Skamil}
6231.66Skamil
6241.51Skamil/// ----------------------------------------------------------------------------
6251.51Skamil
6261.65Skamilstatic void
6271.65Skamilchild_attach_to_its_parent(bool stopped)
6281.1Skamil{
6291.1Skamil	struct msg_fds parent_tracee;
6301.1Skamil	const int exitval_tracer = 5;
6311.1Skamil	pid_t tracer, wpid;
6321.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
6331.1Skamil#if defined(TWAIT_HAVE_STATUS)
6341.1Skamil	int status;
6351.1Skamil#endif
6361.1Skamil
6371.13Schristos	DPRINTF("Spawn tracer\n");
6381.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
6391.1Skamil	tracer = atf_utils_fork();
6401.1Skamil	if (tracer == 0) {
6411.1Skamil		/* Wait for message from the parent */
6421.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
6431.1Skamil
6441.65Skamil		if (stopped) {
6451.65Skamil			DPRINTF("Await for a stopped parent PID %d\n",
6461.65Skamil			        getppid());
6471.65Skamil			await_stopped(getppid());
6481.65Skamil		}
6491.65Skamil
6501.13Schristos		DPRINTF("Attach to parent PID %d with PT_ATTACH from child\n",
6511.1Skamil		    getppid());
6521.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, getppid(), NULL, 0) != -1);
6531.1Skamil
6541.13Schristos		DPRINTF("Wait for the stopped parent process with %s()\n",
6551.1Skamil		    TWAIT_FNAME);
6561.1Skamil		FORKEE_REQUIRE_SUCCESS(
6571.1Skamil		    wpid = TWAIT_GENERIC(getppid(), &status, 0), getppid());
6581.1Skamil
6591.1Skamil		forkee_status_stopped(status, SIGSTOP);
6601.1Skamil
6611.13Schristos		DPRINTF("Resume parent with PT_DETACH\n");
6621.1Skamil		FORKEE_ASSERT(ptrace(PT_DETACH, getppid(), (void *)1, 0)
6631.1Skamil		    != -1);
6641.1Skamil
6651.1Skamil		/* Tell parent we are ready */
6661.1Skamil		CHILD_TO_PARENT("Message 1", parent_tracee, msg);
6671.1Skamil
6681.1Skamil		_exit(exitval_tracer);
6691.1Skamil	}
6701.1Skamil
6711.13Schristos	DPRINTF("Wait for the tracer to become ready\n");
6721.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
6731.65Skamil
6741.65Skamil	if (stopped) {
6751.65Skamil		DPRINTF("Stop self PID %d\n", getpid());
6761.65Skamil		SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
6771.65Skamil	}
6781.65Skamil
6791.13Schristos	DPRINTF("Allow the tracer to exit now\n");
6801.1Skamil	PARENT_FROM_CHILD("Message 1", parent_tracee, msg);
6811.1Skamil
6821.13Schristos	DPRINTF("Wait for tracer to exit with %s()\n", TWAIT_FNAME);
6831.1Skamil	TWAIT_REQUIRE_SUCCESS(
6841.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
6851.1Skamil
6861.1Skamil	validate_status_exited(status, exitval_tracer);
6871.1Skamil
6881.13Schristos	DPRINTF("Before calling %s() for tracer\n", TWAIT_FNAME);
6891.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
6901.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0));
6911.1Skamil
6921.1Skamil	msg_close(&parent_tracee);
6931.1Skamil}
6941.1Skamil
6951.65SkamilATF_TC(child_attach_to_its_parent);
6961.65SkamilATF_TC_HEAD(child_attach_to_its_parent, tc)
6971.65Skamil{
6981.65Skamil	atf_tc_set_md_var(tc, "descr",
6991.65Skamil	    "Assert that tracer child can PT_ATTACH to its parent");
7001.65Skamil}
7011.65Skamil
7021.65SkamilATF_TC_BODY(child_attach_to_its_parent, tc)
7031.65Skamil{
7041.65Skamil
7051.65Skamil	child_attach_to_its_parent(false);
7061.65Skamil}
7071.65Skamil
7081.65SkamilATF_TC(child_attach_to_its_stopped_parent);
7091.65SkamilATF_TC_HEAD(child_attach_to_its_stopped_parent, tc)
7101.65Skamil{
7111.65Skamil	atf_tc_set_md_var(tc, "descr",
7121.65Skamil	    "Assert that tracer child can PT_ATTACH to its stopped parent");
7131.65Skamil}
7141.65Skamil
7151.65SkamilATF_TC_BODY(child_attach_to_its_stopped_parent, tc)
7161.65Skamil{
7171.65Skamil	/*
7181.65Skamil	 * The ATF framework (atf-run) does not tolerate raise(SIGSTOP), as
7191.65Skamil	 * this causes a pipe (established from atf-run) to be broken.
7201.65Skamil	 * atf-run uses this mechanism to monitor whether a test is alive.
7211.65Skamil	 *
7221.65Skamil	 * As a workaround spawn this test as a subprocess.
7231.65Skamil	 */
7241.65Skamil
7251.65Skamil	const int exitval = 15;
7261.65Skamil	pid_t child, wpid;
7271.65Skamil#if defined(TWAIT_HAVE_STATUS)
7281.65Skamil	int status;
7291.65Skamil#endif
7301.65Skamil
7311.65Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
7321.65Skamil	if (child == 0) {
7331.65Skamil		child_attach_to_its_parent(true);
7341.65Skamil		_exit(exitval);
7351.65Skamil	} else {
7361.65Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
7371.65Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
7381.65Skamil
7391.65Skamil		validate_status_exited(status, exitval);
7401.65Skamil
7411.65Skamil		DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
7421.65Skamil		TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
7431.65Skamil	}
7441.65Skamil}
7451.65Skamil
7461.51Skamil/// ----------------------------------------------------------------------------
7471.51Skamil
7481.1Skamil#if defined(TWAIT_HAVE_PID)
7491.1Skamil
7501.51Skamilenum tracee_sees_its_original_parent_type {
7511.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
7521.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
7531.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS
7541.51Skamil};
7551.51Skamil
7561.51Skamilstatic void
7571.51Skamiltracee_sees_its_original_parent(enum tracee_sees_its_original_parent_type type)
7581.1Skamil{
7591.1Skamil	struct msg_fds parent_tracer, parent_tracee;
7601.1Skamil	const int exitval_tracee = 5;
7611.1Skamil	const int exitval_tracer = 10;
7621.1Skamil	pid_t parent, tracee, tracer, wpid;
7631.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
7641.1Skamil#if defined(TWAIT_HAVE_STATUS)
7651.1Skamil	int status;
7661.1Skamil#endif
7671.51Skamil	/* sysctl(3) - kinfo_proc2 */
7681.51Skamil	int name[CTL_MAXNAME];
7691.51Skamil	struct kinfo_proc2 kp;
7701.51Skamil	size_t len = sizeof(kp);
7711.51Skamil	unsigned int namelen;
7721.51Skamil
7731.51Skamil	/* procfs - status  */
7741.51Skamil	FILE *fp;
7751.51Skamil	struct stat st;
7761.51Skamil	const char *fname = "/proc/curproc/status";
7771.51Skamil	char s_executable[MAXPATHLEN];
7781.51Skamil	int s_pid, s_ppid;
7791.51Skamil	int rv;
7801.51Skamil
7811.51Skamil	if (type == TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS) {
7821.61Skre		SYSCALL_REQUIRE(
7831.61Skre		    (rv = stat(fname, &st)) == 0 || (errno == ENOENT));
7841.61Skre		if (rv != 0)
7851.51Skamil			atf_tc_skip("/proc/curproc/status not found");
7861.51Skamil	}
7871.1Skamil
7881.13Schristos	DPRINTF("Spawn tracee\n");
7891.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
7901.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
7911.1Skamil	tracee = atf_utils_fork();
7921.1Skamil	if (tracee == 0) {
7931.1Skamil		parent = getppid();
7941.1Skamil
7951.1Skamil		/* Emit message to the parent */
7961.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
7971.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
7981.1Skamil
7991.51Skamil		switch (type) {
8001.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID:
8011.51Skamil			FORKEE_ASSERT_EQ(parent, getppid());
8021.51Skamil			break;
8031.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2:
8041.51Skamil			namelen = 0;
8051.51Skamil			name[namelen++] = CTL_KERN;
8061.51Skamil			name[namelen++] = KERN_PROC2;
8071.51Skamil			name[namelen++] = KERN_PROC_PID;
8081.51Skamil			name[namelen++] = getpid();
8091.51Skamil			name[namelen++] = len;
8101.51Skamil			name[namelen++] = 1;
8111.51Skamil
8121.61Skre			FORKEE_ASSERT_EQ(
8131.61Skre			    sysctl(name, namelen, &kp, &len, NULL, 0), 0);
8141.51Skamil			FORKEE_ASSERT_EQ(parent, kp.p_ppid);
8151.51Skamil			break;
8161.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS:
8171.51Skamil			/*
8181.51Skamil			 * Format:
8191.51Skamil			 *  EXECUTABLE PID PPID ...
8201.51Skamil			 */
8211.51Skamil			FORKEE_ASSERT((fp = fopen(fname, "r")) != NULL);
8221.51Skamil			fscanf(fp, "%s %d %d", s_executable, &s_pid, &s_ppid);
8231.51Skamil			FORKEE_ASSERT_EQ(fclose(fp), 0);
8241.51Skamil			FORKEE_ASSERT_EQ(parent, s_ppid);
8251.51Skamil			break;
8261.51Skamil		}
8271.1Skamil
8281.1Skamil		_exit(exitval_tracee);
8291.1Skamil	}
8301.13Schristos	DPRINTF("Wait for child to record its parent identifier (pid)\n");
8311.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
8321.1Skamil
8331.13Schristos	DPRINTF("Spawn debugger\n");
8341.1Skamil	tracer = atf_utils_fork();
8351.1Skamil	if (tracer == 0) {
8361.1Skamil		/* No IPC to communicate with the child */
8371.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
8381.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
8391.1Skamil
8401.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
8411.1Skamil		FORKEE_REQUIRE_SUCCESS(
8421.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
8431.1Skamil
8441.1Skamil		forkee_status_stopped(status, SIGSTOP);
8451.1Skamil
8461.1Skamil		/* Resume tracee with PT_CONTINUE */
8471.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
8481.1Skamil
8491.1Skamil		/* Inform parent that tracer has attached to tracee */
8501.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
8511.1Skamil
8521.1Skamil		/* Wait for parent to tell use that tracee should have exited */
8531.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
8541.1Skamil
8551.1Skamil		/* Wait for tracee and assert that it exited */
8561.1Skamil		FORKEE_REQUIRE_SUCCESS(
8571.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
8581.1Skamil
8591.1Skamil		forkee_status_exited(status, exitval_tracee);
8601.1Skamil
8611.13Schristos		DPRINTF("Before exiting of the tracer process\n");
8621.1Skamil		_exit(exitval_tracer);
8631.1Skamil	}
8641.1Skamil
8651.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
8661.1Skamil	PARENT_FROM_CHILD("tracer ready",  parent_tracer, msg);
8671.1Skamil
8681.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
8691.1Skamil	PARENT_TO_CHILD("exit tracee",  parent_tracee, msg);
8701.1Skamil
8711.13Schristos	DPRINTF("Detect that tracee is zombie\n");
8721.1Skamil	await_zombie(tracee);
8731.1Skamil
8741.13Schristos	DPRINTF("Assert that there is no status about tracee - "
8751.1Skamil	    "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
8761.1Skamil	TWAIT_REQUIRE_SUCCESS(
8771.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
8781.1Skamil
8791.13Schristos	DPRINTF("Tell the tracer child should have exited\n");
8801.1Skamil	PARENT_TO_CHILD("wait for tracee exit",  parent_tracer, msg);
8811.1Skamil
8821.13Schristos	DPRINTF("Wait from tracer child to complete waiting for tracee\n");
8831.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
8841.1Skamil	    tracer);
8851.1Skamil
8861.1Skamil	validate_status_exited(status, exitval_tracer);
8871.1Skamil
8881.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
8891.1Skamil	    TWAIT_FNAME);
8901.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
8911.1Skamil	    tracee);
8921.1Skamil
8931.1Skamil	validate_status_exited(status, exitval_tracee);
8941.1Skamil
8951.1Skamil	msg_close(&parent_tracer);
8961.1Skamil	msg_close(&parent_tracee);
8971.1Skamil}
8981.1Skamil
8991.61Skre#define TRACEE_SEES_ITS_ORIGINAL_PARENT(test, type, descr)		\
9001.61SkreATF_TC(test);								\
9011.61SkreATF_TC_HEAD(test, tc)							\
9021.61Skre{									\
9031.61Skre	atf_tc_set_md_var(tc, "descr",					\
9041.61Skre	    "Assert that tracee sees its original parent when being traced " \
9051.61Skre	    "(check " descr ")");					\
9061.61Skre}									\
9071.61Skre									\
9081.61SkreATF_TC_BODY(test, tc)							\
9091.61Skre{									\
9101.61Skre									\
9111.61Skre	tracee_sees_its_original_parent(type);				\
9121.1Skamil}
9131.1Skamil
9141.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
9151.51Skamil	tracee_sees_its_original_parent_getppid,
9161.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
9171.51Skamil	"getppid(2)");
9181.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
9191.51Skamil	tracee_sees_its_original_parent_sysctl_kinfo_proc2,
9201.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
9211.51Skamil	"sysctl(3) and kinfo_proc2");
9221.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
9231.51Skamil	tracee_sees_its_original_parent_procfs_status,
9241.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS,
9251.51Skamil	"the status file in procfs");
9261.1Skamil#endif
9271.1Skamil
9281.51Skamil/// ----------------------------------------------------------------------------
9291.1Skamil
9301.53Skamilstatic void
9311.53Skamileventmask_preserved(int event)
9321.1Skamil{
9331.1Skamil	const int exitval = 5;
9341.1Skamil	const int sigval = SIGSTOP;
9351.1Skamil	pid_t child, wpid;
9361.1Skamil#if defined(TWAIT_HAVE_STATUS)
9371.1Skamil	int status;
9381.1Skamil#endif
9391.1Skamil	ptrace_event_t set_event, get_event;
9401.1Skamil	const int len = sizeof(ptrace_event_t);
9411.1Skamil
9421.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
9431.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
9441.1Skamil	if (child == 0) {
9451.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
9461.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
9471.1Skamil
9481.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
9491.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
9501.1Skamil
9511.13Schristos		DPRINTF("Before exiting of the child process\n");
9521.1Skamil		_exit(exitval);
9531.1Skamil	}
9541.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
9551.1Skamil
9561.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9571.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9581.1Skamil
9591.1Skamil	validate_status_stopped(status, sigval);
9601.1Skamil
9611.53Skamil	set_event.pe_set_event = event;
9621.61Skre	SYSCALL_REQUIRE(
9631.61Skre	    ptrace(PT_SET_EVENT_MASK, child, &set_event, len) != -1);
9641.61Skre	SYSCALL_REQUIRE(
9651.61Skre	    ptrace(PT_GET_EVENT_MASK, child, &get_event, len) != -1);
9661.125Skamil	DPRINTF("set_event=%#x get_event=%#x\n", set_event.pe_set_event,
9671.125Skamil	    get_event.pe_set_event);
9681.1Skamil	ATF_REQUIRE(memcmp(&set_event, &get_event, len) == 0);
9691.1Skamil
9701.13Schristos	DPRINTF("Before resuming the child process where it left off and "
9711.1Skamil	    "without signal to be sent\n");
9721.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
9731.1Skamil
9741.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9751.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9761.1Skamil
9771.1Skamil	validate_status_exited(status, exitval);
9781.1Skamil
9791.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9801.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
9811.1Skamil}
9821.1Skamil
9831.61Skre#define EVENTMASK_PRESERVED(test, event)				\
9841.61SkreATF_TC(test);								\
9851.61SkreATF_TC_HEAD(test, tc)							\
9861.61Skre{									\
9871.61Skre	atf_tc_set_md_var(tc, "descr",					\
9881.61Skre	    "Verify that eventmask " #event " is preserved");		\
9891.61Skre}									\
9901.61Skre									\
9911.61SkreATF_TC_BODY(test, tc)							\
9921.61Skre{									\
9931.61Skre									\
9941.61Skre	eventmask_preserved(event);					\
9951.1Skamil}
9961.1Skamil
9971.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_empty, 0)
9981.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_fork, PTRACE_FORK)
9991.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_vfork, PTRACE_VFORK)
10001.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_vfork_done, PTRACE_VFORK_DONE)
10011.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_lwp_create, PTRACE_LWP_CREATE)
10021.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_lwp_exit, PTRACE_LWP_EXIT)
10031.125SkamilEVENTMASK_PRESERVED(eventmask_preserved_posix_spawn, PTRACE_POSIX_SPAWN)
10041.1Skamil
10051.53Skamil/// ----------------------------------------------------------------------------
10061.1Skamil
10071.180Skamilstatic int lwpinfo_thread_sigmask[] = {SIGXCPU, SIGPIPE, SIGALRM, SIGURG};
10081.180Skamil
10091.180Skamilstatic pthread_mutex_t lwpinfo_thread_mtx = PTHREAD_MUTEX_INITIALIZER;
10101.180Skamilstatic pthread_cond_t lwpinfo_thread_cnd = PTHREAD_COND_INITIALIZER;
10111.180Skamilstatic volatile size_t lwpinfo_thread_done;
10121.180Skamil
10131.180Skamilstatic void *
10141.180Skamillwpinfo_thread(void *arg)
10151.180Skamil{
10161.180Skamil	sigset_t s;
10171.180Skamil	volatile void **tcb;
10181.180Skamil
10191.180Skamil	tcb = (volatile void **)arg;
10201.180Skamil
10211.180Skamil	*tcb = _lwp_getprivate();
10221.180Skamil	DPRINTF("Storing tcb[] = %p from thread %d\n", *tcb, _lwp_self());
10231.180Skamil
10241.180Skamil	pthread_setname_np(pthread_self(), "thread %d",
10251.180Skamil	    (void *)(intptr_t)_lwp_self());
10261.180Skamil
10271.180Skamil	sigemptyset(&s);
10281.180Skamil	pthread_mutex_lock(&lwpinfo_thread_mtx);
10291.180Skamil	sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
10301.180Skamil	lwpinfo_thread_done++;
10311.180Skamil	pthread_sigmask(SIG_BLOCK, &s, NULL);
10321.180Skamil	pthread_cond_signal(&lwpinfo_thread_cnd);
10331.180Skamil	pthread_mutex_unlock(&lwpinfo_thread_mtx);
10341.180Skamil
10351.180Skamil	return infinite_thread(NULL);
10361.180Skamil}
10371.180Skamil
10381.28Skamilstatic void
10391.180Skamiltraceme_lwpinfo(const size_t threads, const char *iter)
10401.1Skamil{
10411.1Skamil	const int sigval = SIGSTOP;
10421.180Skamil	const int sigval2 = SIGINT;
10431.180Skamil	pid_t child, wpid;
10441.1Skamil#if defined(TWAIT_HAVE_STATUS)
10451.1Skamil	int status;
10461.1Skamil#endif
10471.180Skamil	struct ptrace_lwpinfo lwp = {0, 0};
10481.180Skamil	struct ptrace_lwpstatus lwpstatus = {0};
10491.180Skamil	struct ptrace_siginfo info;
10501.180Skamil	void *private;
10511.180Skamil	char *name;
10521.180Skamil	char namebuf[PL_LNAMELEN];
10531.180Skamil	volatile void *tcb[4];
10541.180Skamil	bool found;
10551.180Skamil	sigset_t s;
10561.180Skamil
10571.180Skamil	/* Maximum number of supported threads in this test */
10581.180Skamil	pthread_t t[__arraycount(tcb) - 1];
10591.180Skamil	size_t n, m;
10601.180Skamil	int rv;
10611.180Skamil	size_t bytes_read;
10621.180Skamil
10631.180Skamil	struct ptrace_io_desc io;
10641.180Skamil	sigset_t sigmask;
10651.1Skamil
10661.180Skamil	ATF_REQUIRE(__arraycount(t) >= threads);
10671.180Skamil	memset(tcb, 0, sizeof(tcb));
10681.124Skamil
10691.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
10701.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
10711.1Skamil	if (child == 0) {
10721.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
10731.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
10741.1Skamil
10751.180Skamil		tcb[0] = _lwp_getprivate();
10761.180Skamil		DPRINTF("Storing tcb[0] = %p\n", tcb[0]);
10771.180Skamil
10781.180Skamil		pthread_setname_np(pthread_self(), "thread %d",
10791.180Skamil		    (void *)(intptr_t)_lwp_self());
10801.180Skamil
10811.180Skamil		sigemptyset(&s);
10821.180Skamil		sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
10831.180Skamil		pthread_sigmask(SIG_BLOCK, &s, NULL);
10841.180Skamil
10851.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
10861.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
10871.1Skamil
10881.180Skamil		for (n = 0; n < threads; n++) {
10891.180Skamil			rv = pthread_create(&t[n], NULL, lwpinfo_thread,
10901.180Skamil			    &tcb[n + 1]);
10911.180Skamil			FORKEE_ASSERT(rv == 0);
10921.180Skamil		}
10931.1Skamil
10941.180Skamil		pthread_mutex_lock(&lwpinfo_thread_mtx);
10951.180Skamil		while (lwpinfo_thread_done < threads) {
10961.180Skamil			pthread_cond_wait(&lwpinfo_thread_cnd,
10971.180Skamil			    &lwpinfo_thread_mtx);
10981.124Skamil		}
10991.180Skamil		pthread_mutex_unlock(&lwpinfo_thread_mtx);
11001.1Skamil
11011.180Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval2));
11021.180Skamil		FORKEE_ASSERT(raise(sigval2) == 0);
11031.1Skamil
11041.180Skamil		/* NOTREACHED */
11051.180Skamil		FORKEE_ASSERTX(0 && "Not reached");
11061.1Skamil	}
11071.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
11081.1Skamil
11091.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11101.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11111.1Skamil
11121.1Skamil	validate_status_stopped(status, sigval);
11131.1Skamil
11141.180Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
11151.180Skamil	SYSCALL_REQUIRE(
11161.180Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
11171.1Skamil
11181.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
11191.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
11201.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
11211.180Skamil	    info.psi_siginfo.si_errno);
11221.1Skamil
11231.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
11241.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
11251.1Skamil
11261.180Skamil	if (strstr(iter, "LWPINFO") != NULL) {
11271.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
11281.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
11291.180Skamil		    != -1);
11301.1Skamil
11311.180Skamil		DPRINTF("Assert that there exists a single thread only\n");
11321.180Skamil		ATF_REQUIRE(lwp.pl_lwpid > 0);
11331.1Skamil
11341.180Skamil		DPRINTF("Assert that lwp thread %d received event "
11351.180Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
11361.180Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
11371.1Skamil
11381.180Skamil		if (strstr(iter, "LWPSTATUS") != NULL) {
11391.180Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPSTATUS "
11401.180Skamil			    "for child\n");
11411.180Skamil			lwpstatus.pl_lwpid = lwp.pl_lwpid;
11421.180Skamil			SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child, &lwpstatus,
11431.180Skamil			    sizeof(lwpstatus)) != -1);
11441.30Skamil		}
11451.30Skamil
11461.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
11471.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
11481.180Skamil		    != -1);
11491.29Skamil
11501.180Skamil		DPRINTF("Assert that there exists a single thread only\n");
11511.180Skamil		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
11521.180Skamil	} else {
11531.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
11541.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
11551.180Skamil		    sizeof(lwpstatus)) != -1);
11561.29Skamil
11571.180Skamil		DPRINTF("Assert that there exists a single thread only %d\n", lwpstatus.pl_lwpid);
11581.180Skamil		ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
11591.30Skamil
11601.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
11611.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
11621.180Skamil		    sizeof(lwpstatus)) != -1);
11631.30Skamil
11641.180Skamil		DPRINTF("Assert that there exists a single thread only\n");
11651.180Skamil		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
11661.30Skamil	}
11671.29Skamil
11681.13Schristos	DPRINTF("Before resuming the child process where it left off and "
11691.1Skamil	    "without signal to be sent\n");
11701.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
11711.1Skamil
11721.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11731.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11741.1Skamil
11751.180Skamil	validate_status_stopped(status, sigval2);
11761.180Skamil
11771.180Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
11781.180Skamil	SYSCALL_REQUIRE(
11791.180Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
11801.180Skamil
11811.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
11821.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
11831.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
11841.180Skamil	    info.psi_siginfo.si_errno);
11851.1Skamil
11861.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval2);
11871.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
11881.28Skamil
11891.180Skamil	memset(&lwp, 0, sizeof(lwp));
11901.180Skamil	memset(&lwpstatus, 0, sizeof(lwpstatus));
11911.32Skamil
11921.180Skamil	memset(&io, 0, sizeof(io));
11931.1Skamil
11941.180Skamil	bytes_read = 0;
11951.180Skamil	io.piod_op = PIOD_READ_D;
11961.180Skamil	io.piod_len = sizeof(tcb);
11971.125Skamil
11981.180Skamil	do {
11991.180Skamil		io.piod_addr = (char *)&tcb + bytes_read;
12001.180Skamil		io.piod_offs = io.piod_addr;
12011.124Skamil
12021.180Skamil		rv = ptrace(PT_IO, child, &io, sizeof(io));
12031.180Skamil		ATF_REQUIRE(rv != -1 && io.piod_len != 0);
12041.31Skamil
12051.180Skamil		bytes_read += io.piod_len;
12061.180Skamil		io.piod_len = sizeof(tcb) - bytes_read;
12071.180Skamil	} while (bytes_read < sizeof(tcb));
12081.149Skamil
12091.180Skamil	for (n = 0; n <= threads; n++) {
12101.180Skamil		if (strstr(iter, "LWPINFO") != NULL) {
12111.180Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
12121.180Skamil			    "child\n");
12131.180Skamil			SYSCALL_REQUIRE(
12141.180Skamil			    ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
12151.180Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
12161.149Skamil
12171.180Skamil			DPRINTF("Assert that the thread exists\n");
12181.180Skamil			ATF_REQUIRE(lwp.pl_lwpid > 0);
12191.149Skamil
12201.180Skamil			DPRINTF("Assert that lwp thread %d received expected "
12211.180Skamil			    "event\n", lwp.pl_lwpid);
12221.180Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
12231.180Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
12241.180Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
12251.149Skamil
12261.180Skamil			if (strstr(iter, "LWPSTATUS") != NULL) {
12271.180Skamil				DPRINTF("Before calling ptrace(2) with "
12281.180Skamil				    "PT_LWPSTATUS for child\n");
12291.180Skamil				lwpstatus.pl_lwpid = lwp.pl_lwpid;
12301.180Skamil				SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child,
12311.180Skamil				    &lwpstatus, sizeof(lwpstatus)) != -1);
12321.149Skamil
12331.180Skamil				goto check_lwpstatus;
12341.180Skamil			}
12351.149Skamil		} else {
12361.180Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for "
12371.180Skamil			    "child\n");
12381.180Skamil			SYSCALL_REQUIRE(
12391.180Skamil			    ptrace(PT_LWPNEXT, child, &lwpstatus,
12401.180Skamil			    sizeof(lwpstatus)) != -1);
12411.180Skamil			DPRINTF("LWP=%d\n", lwpstatus.pl_lwpid);
12421.149Skamil
12431.180Skamil			DPRINTF("Assert that the thread exists\n");
12441.180Skamil			ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
12451.149Skamil
12461.180Skamil		check_lwpstatus:
12471.149Skamil
12481.180Skamil			if (strstr(iter, "pl_sigmask") != NULL) {
12491.180Skamil				sigmask = lwpstatus.pl_sigmask;
12501.149Skamil
12511.180Skamil				DPRINTF("Retrieved sigmask: "
12521.180Skamil				    "%02x%02x%02x%02x\n",
12531.180Skamil				    sigmask.__bits[0], sigmask.__bits[1],
12541.180Skamil				    sigmask.__bits[2], sigmask.__bits[3]);
12551.149Skamil
12561.180Skamil				found = false;
12571.180Skamil				for (m = 0;
12581.180Skamil				     m < __arraycount(lwpinfo_thread_sigmask);
12591.180Skamil				     m++) {
12601.180Skamil					if (sigismember(&sigmask,
12611.180Skamil					    lwpinfo_thread_sigmask[m])) {
12621.180Skamil						found = true;
12631.180Skamil						lwpinfo_thread_sigmask[m] = 0;
12641.180Skamil						break;
12651.180Skamil					}
12661.180Skamil				}
12671.180Skamil				ATF_REQUIRE(found == true);
12681.180Skamil			} else if (strstr(iter, "pl_name") != NULL) {
12691.180Skamil				name = lwpstatus.pl_name;
12701.149Skamil
12711.180Skamil				DPRINTF("Retrieved thread name: "
12721.180Skamil				    "%s\n", name);
12731.149Skamil
12741.180Skamil				snprintf(namebuf, sizeof namebuf, "thread %d",
12751.180Skamil				    lwpstatus.pl_lwpid);
12761.149Skamil
12771.180Skamil				ATF_REQUIRE(strcmp(name, namebuf) == 0);
12781.180Skamil			} else if (strstr(iter, "pl_private") != NULL) {
12791.180Skamil				private = lwpstatus.pl_private;
12801.149Skamil
12811.180Skamil				DPRINTF("Retrieved thread private pointer: "
12821.180Skamil				    "%p\n", private);
12831.149Skamil
12841.180Skamil				found = false;
12851.180Skamil				for (m = 0; m < __arraycount(tcb); m++) {
12861.180Skamil					DPRINTF("Comparing %p and %p\n",
12871.180Skamil					    private, tcb[m]);
12881.180Skamil					if (private == tcb[m]) {
12891.180Skamil						found = true;
12901.180Skamil						break;
12911.180Skamil					}
12921.180Skamil				}
12931.180Skamil				ATF_REQUIRE(found == true);
12941.180Skamil			}
12951.180Skamil		}
12961.180Skamil	}
12971.149Skamil
12981.180Skamil	if (strstr(iter, "LWPINFO") != NULL) {
12991.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
13001.180Skamil		    "child\n");
13011.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
13021.180Skamil		    != -1);
13031.180Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
13041.149Skamil
13051.180Skamil		DPRINTF("Assert that there are no more threads\n");
13061.180Skamil		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
13071.180Skamil	} else {
13081.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
13091.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
13101.180Skamil		    sizeof(lwpstatus)) != -1);
13111.149Skamil
13121.180Skamil		DPRINTF("Assert that there exists a single thread only\n");
13131.180Skamil		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
13141.180Skamil	}
13151.149Skamil
13161.180Skamil	DPRINTF("Before resuming the child process where it left off and "
13171.180Skamil	    "without signal to be sent\n");
13181.180Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, SIGKILL) != -1);
13191.149Skamil
13201.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
13211.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
13221.149Skamil
13231.180Skamil	validate_status_signaled(status, SIGKILL, 0);
13241.149Skamil
13251.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
13261.180Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
13271.180Skamil}
13281.149Skamil
13291.180Skamil#define TRACEME_LWPINFO(test, threads, iter)				\
13301.180SkamilATF_TC(test);								\
13311.180SkamilATF_TC_HEAD(test, tc)							\
13321.180Skamil{									\
13331.180Skamil	atf_tc_set_md_var(tc, "descr",					\
13341.180Skamil	    "Verify " iter " with the child with " #threads		\
13351.180Skamil	    " spawned extra threads");					\
13361.180Skamil}									\
13371.180Skamil									\
13381.180SkamilATF_TC_BODY(test, tc)							\
13391.180Skamil{									\
13401.180Skamil									\
13411.180Skamil	traceme_lwpinfo(threads, iter);					\
13421.180Skamil}
13431.149Skamil
13441.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0, 0, "LWPINFO")
13451.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1, 1, "LWPINFO")
13461.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2, 2, "LWPINFO")
13471.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3, 3, "LWPINFO")
13481.149Skamil
13491.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus, 0, "LWPINFO+LWPSTATUS")
13501.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus, 1, "LWPINFO+LWPSTATUS")
13511.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus, 2, "LWPINFO+LWPSTATUS")
13521.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus, 3, "LWPINFO+LWPSTATUS")
13531.149Skamil
13541.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_sigmask, 0,
13551.180Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
13561.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_sigmask, 1,
13571.180Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
13581.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_sigmask, 2,
13591.180Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
13601.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_sigmask, 3,
13611.180Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
13621.149Skamil
13631.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_name, 0,
13641.180Skamil    "LWPINFO+LWPSTATUS+pl_name")
13651.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_name, 1,
13661.180Skamil    "LWPINFO+LWPSTATUS+pl_name")
13671.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_name, 2,
13681.180Skamil    "LWPINFO+LWPSTATUS+pl_name")
13691.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_name, 3,
13701.180Skamil    "LWPINFO+LWPSTATUS+pl_name")
13711.149Skamil
13721.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_private, 0,
13731.180Skamil    "LWPINFO+LWPSTATUS+pl_private")
13741.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_private, 1,
13751.180Skamil    "LWPINFO+LWPSTATUS+pl_private")
13761.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_private, 2,
13771.180Skamil    "LWPINFO+LWPSTATUS+pl_private")
13781.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_private, 3,
13791.180Skamil    "LWPINFO+LWPSTATUS+pl_private")
13801.149Skamil
13811.180SkamilTRACEME_LWPINFO(traceme_lwpnext0, 0, "LWPNEXT")
13821.180SkamilTRACEME_LWPINFO(traceme_lwpnext1, 1, "LWPNEXT")
13831.180SkamilTRACEME_LWPINFO(traceme_lwpnext2, 2, "LWPNEXT")
13841.180SkamilTRACEME_LWPINFO(traceme_lwpnext3, 3, "LWPNEXT")
13851.149Skamil
13861.180SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_sigmask, 0, "LWPNEXT+pl_sigmask")
13871.180SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_sigmask, 1, "LWPNEXT+pl_sigmask")
13881.180SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_sigmask, 2, "LWPNEXT+pl_sigmask")
13891.180SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_sigmask, 3, "LWPNEXT+pl_sigmask")
13901.149Skamil
13911.180SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_name, 0, "LWPNEXT+pl_name")
13921.180SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_name, 1, "LWPNEXT+pl_name")
13931.180SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_name, 2, "LWPNEXT+pl_name")
13941.180SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_name, 3, "LWPNEXT+pl_name")
13951.149Skamil
13961.180SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_private, 0, "LWPNEXT+pl_private")
13971.180SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_private, 1, "LWPNEXT+pl_private")
13981.180SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_private, 2, "LWPNEXT+pl_private")
13991.180SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_private, 3, "LWPNEXT+pl_private")
14001.149Skamil
14011.180Skamil/// ----------------------------------------------------------------------------
14021.149Skamil
14031.180Skamil#if defined(TWAIT_HAVE_PID)
14041.180Skamilstatic void
14051.180Skamilattach_lwpinfo(const int threads)
14061.180Skamil{
14071.180Skamil	const int sigval = SIGINT;
14081.180Skamil	struct msg_fds parent_tracee, parent_tracer;
14091.180Skamil	const int exitval_tracer = 10;
14101.180Skamil	pid_t tracee, tracer, wpid;
14111.180Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
14121.180Skamil#if defined(TWAIT_HAVE_STATUS)
14131.180Skamil	int status;
14141.180Skamil#endif
14151.180Skamil	struct ptrace_lwpinfo lwp = {0, 0};
14161.180Skamil	struct ptrace_siginfo info;
14171.149Skamil
14181.180Skamil	/* Maximum number of supported threads in this test */
14191.180Skamil	pthread_t t[3];
14201.180Skamil	int n, rv;
14211.149Skamil
14221.180Skamil	DPRINTF("Spawn tracee\n");
14231.180Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
14241.180Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
14251.180Skamil	tracee = atf_utils_fork();
14261.180Skamil	if (tracee == 0) {
14271.180Skamil		/* Wait for message from the parent */
14281.180Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
14291.149Skamil
14301.180Skamil		CHILD_FROM_PARENT("spawn threads", parent_tracee, msg);
14311.149Skamil
14321.180Skamil		for (n = 0; n < threads; n++) {
14331.180Skamil			rv = pthread_create(&t[n], NULL, infinite_thread, NULL);
14341.180Skamil			FORKEE_ASSERT(rv == 0);
14351.149Skamil		}
14361.149Skamil
14371.180Skamil		CHILD_TO_PARENT("tracee exit", parent_tracee, msg);
14381.149Skamil
14391.180Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
14401.180Skamil		FORKEE_ASSERT(raise(sigval) == 0);
14411.149Skamil
14421.180Skamil		/* NOTREACHED */
14431.180Skamil		FORKEE_ASSERTX(0 && "Not reached");
14441.150Skamil	}
14451.180Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
14461.150Skamil
14471.150Skamil	DPRINTF("Spawn debugger\n");
14481.150Skamil	tracer = atf_utils_fork();
14491.150Skamil	if (tracer == 0) {
14501.180Skamil		/* No IPC to communicate with the child */
14511.150Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
14521.150Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
14531.150Skamil
14541.150Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
14551.150Skamil		FORKEE_REQUIRE_SUCCESS(
14561.150Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
14571.150Skamil
14581.150Skamil		forkee_status_stopped(status, SIGSTOP);
14591.150Skamil
14601.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
14611.180Skamil		    "tracee");
14621.180Skamil		FORKEE_ASSERT(
14631.150Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
14641.150Skamil
14651.150Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
14661.150Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
14671.180Skamil		    "si_errno=%#x\n",
14681.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
14691.180Skamil		    info.psi_siginfo.si_errno);
14701.150Skamil
14711.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
14721.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
14731.150Skamil
14741.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
14751.180Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
14761.180Skamil		    != -1);
14771.180Skamil
14781.180Skamil		DPRINTF("Assert that there exists a thread\n");
14791.180Skamil		FORKEE_ASSERTX(lwp.pl_lwpid > 0);
14801.180Skamil
14811.180Skamil		DPRINTF("Assert that lwp thread %d received event "
14821.180Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
14831.180Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
14841.180Skamil
14851.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
14861.180Skamil		    "tracee\n");
14871.180Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
14881.180Skamil		    != -1);
14891.180Skamil
14901.180Skamil		DPRINTF("Assert that there are no more lwp threads in "
14911.180Skamil		    "tracee\n");
14921.180Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
14931.180Skamil
14941.150Skamil		/* Resume tracee with PT_CONTINUE */
14951.150Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
14961.150Skamil
14971.150Skamil		/* Inform parent that tracer has attached to tracee */
14981.150Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
14991.150Skamil
15001.180Skamil		/* Wait for parent */
15011.180Skamil		CHILD_FROM_PARENT("tracer wait", parent_tracer, msg);
15021.150Skamil
15031.180Skamil		/* Wait for tracee and assert that it raised a signal */
15041.150Skamil		FORKEE_REQUIRE_SUCCESS(
15051.150Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
15061.150Skamil
15071.180Skamil		forkee_status_stopped(status, SIGINT);
15081.150Skamil
15091.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
15101.180Skamil		    "child");
15111.180Skamil		FORKEE_ASSERT(
15121.150Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
15131.150Skamil
15141.150Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
15151.150Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
15161.180Skamil		    "si_errno=%#x\n",
15171.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
15181.180Skamil		    info.psi_siginfo.si_errno);
15191.150Skamil
15201.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
15211.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
15221.150Skamil
15231.180Skamil		memset(&lwp, 0, sizeof(lwp));
15241.150Skamil
15251.180Skamil		for (n = 0; n <= threads; n++) {
15261.180Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
15271.180Skamil			    "child\n");
15281.180Skamil			FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp,
15291.180Skamil			    sizeof(lwp)) != -1);
15301.180Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
15311.150Skamil
15321.180Skamil			DPRINTF("Assert that the thread exists\n");
15331.180Skamil			FORKEE_ASSERT(lwp.pl_lwpid > 0);
15341.150Skamil
15351.180Skamil			DPRINTF("Assert that lwp thread %d received expected "
15361.180Skamil			    "event\n", lwp.pl_lwpid);
15371.180Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
15381.180Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
15391.180Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
15401.180Skamil		}
15411.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
15421.180Skamil		    "tracee\n");
15431.180Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
15441.180Skamil		    != -1);
15451.180Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
15461.150Skamil
15471.180Skamil		DPRINTF("Assert that there are no more threads\n");
15481.180Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
15491.150Skamil
15501.180Skamil		DPRINTF("Before resuming the child process where it left off "
15511.150Skamil		    "and without signal to be sent\n");
15521.180Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, SIGKILL)
15531.180Skamil		    != -1);
15541.150Skamil
15551.180Skamil		/* Wait for tracee and assert that it exited */
15561.180Skamil		FORKEE_REQUIRE_SUCCESS(
15571.180Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
15581.150Skamil
15591.180Skamil		forkee_status_signaled(status, SIGKILL, 0);
15601.150Skamil
15611.150Skamil		DPRINTF("Before exiting of the tracer process\n");
15621.180Skamil		_exit(exitval_tracer);
15631.97Skamil	}
15641.97Skamil
15651.180Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
15661.180Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
15671.97Skamil
15681.180Skamil	DPRINTF("Resume the tracee and spawn threads\n");
15691.180Skamil	PARENT_TO_CHILD("spawn threads", parent_tracee, msg);
15701.97Skamil
15711.180Skamil	DPRINTF("Resume the tracee and let it exit\n");
15721.180Skamil	PARENT_FROM_CHILD("tracee exit", parent_tracee, msg);
15731.97Skamil
15741.180Skamil	DPRINTF("Resume the tracer and let it detect multiple threads\n");
15751.180Skamil	PARENT_TO_CHILD("tracer wait", parent_tracer, msg);
15761.1Skamil
15771.180Skamil	DPRINTF("Wait for tracer to finish its job and exit - calling %s()\n",
15781.180Skamil	    TWAIT_FNAME);
15791.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
15801.180Skamil	    tracer);
15811.1Skamil
15821.180Skamil	validate_status_exited(status, exitval_tracer);
15831.1Skamil
15841.180Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
15851.180Skamil	    TWAIT_FNAME);
15861.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
15871.180Skamil	    tracee);
15881.1Skamil
15891.180Skamil	validate_status_signaled(status, SIGKILL, 0);
15901.1Skamil
15911.180Skamil	msg_close(&parent_tracer);
15921.180Skamil	msg_close(&parent_tracee);
15931.1Skamil}
15941.1Skamil
15951.180Skamil#define ATTACH_LWPINFO(test, threads)					\
15961.97SkamilATF_TC(test);								\
15971.97SkamilATF_TC_HEAD(test, tc)							\
15981.97Skamil{									\
15991.180Skamil	atf_tc_set_md_var(tc, "descr",					\
16001.180Skamil	    "Verify LWPINFO with the child with " #threads		\
16011.180Skamil	    " spawned extra threads (tracer is not the original "	\
16021.180Skamil	    "parent)");							\
16031.97Skamil}									\
16041.97Skamil									\
16051.97SkamilATF_TC_BODY(test, tc)							\
16061.97Skamil{									\
16071.97Skamil									\
16081.180Skamil	attach_lwpinfo(threads);					\
16091.97Skamil}
16101.97Skamil
16111.180SkamilATTACH_LWPINFO(attach_lwpinfo0, 0)
16121.180SkamilATTACH_LWPINFO(attach_lwpinfo1, 1)
16131.180SkamilATTACH_LWPINFO(attach_lwpinfo2, 2)
16141.180SkamilATTACH_LWPINFO(attach_lwpinfo3, 3)
16151.180Skamil#endif
16161.97Skamil
16171.82Skamil/// ----------------------------------------------------------------------------
16181.82Skamil
16191.83Skamilstatic void
16201.180Skamilptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c), int *signal_caught)
16211.1Skamil{
16221.180Skamil	const int exitval = 5;
16231.180Skamil	const int sigval = SIGINT;
16241.180Skamil	const int sigfaked = SIGTRAP;
16251.180Skamil	const int sicodefaked = TRAP_BRKPT;
16261.1Skamil	pid_t child, wpid;
16271.180Skamil	struct sigaction sa;
16281.1Skamil#if defined(TWAIT_HAVE_STATUS)
16291.1Skamil	int status;
16301.1Skamil#endif
16311.83Skamil	struct ptrace_siginfo info;
16321.180Skamil	memset(&info, 0, sizeof(info));
16331.83Skamil
16341.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
16351.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
16361.1Skamil	if (child == 0) {
16371.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
16381.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
16391.1Skamil
16401.180Skamil		sa.sa_sigaction = sah;
16411.180Skamil		sa.sa_flags = SA_SIGINFO;
16421.180Skamil		sigemptyset(&sa.sa_mask);
16431.180Skamil
16441.180Skamil		FORKEE_ASSERT(sigaction(faked ? sigfaked : sigval, &sa, NULL)
16451.180Skamil		    != -1);
16461.153Skamil
16471.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
16481.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
16491.1Skamil
16501.180Skamil		FORKEE_ASSERT_EQ(*signal_caught, 1);
16511.1Skamil
16521.180Skamil		DPRINTF("Before exiting of the child process\n");
16531.180Skamil		_exit(exitval);
16541.1Skamil	}
16551.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
16561.1Skamil
16571.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16581.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
16591.1Skamil
16601.1Skamil	validate_status_stopped(status, sigval);
16611.1Skamil
16621.83Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
16631.83Skamil	SYSCALL_REQUIRE(
16641.83Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
16651.1Skamil
16661.83Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
16671.83Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
16681.83Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
16691.83Skamil	    info.psi_siginfo.si_errno);
16701.1Skamil
16711.180Skamil	if (faked) {
16721.180Skamil		DPRINTF("Before setting new faked signal to signo=%d "
16731.180Skamil		    "si_code=%d\n", sigfaked, sicodefaked);
16741.180Skamil		info.psi_siginfo.si_signo = sigfaked;
16751.180Skamil		info.psi_siginfo.si_code = sicodefaked;
16761.83Skamil	}
16771.1Skamil
16781.180Skamil	DPRINTF("Before calling ptrace(2) with PT_SET_SIGINFO for child\n");
16791.180Skamil	SYSCALL_REQUIRE(
16801.180Skamil	    ptrace(PT_SET_SIGINFO, child, &info, sizeof(info)) != -1);
16811.1Skamil
16821.180Skamil	if (faked) {
16831.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
16841.83Skamil		    "child\n");
16851.180Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
16861.180Skamil		    sizeof(info)) != -1);
16871.1Skamil
16881.180Skamil		DPRINTF("Before checking siginfo_t\n");
16891.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigfaked);
16901.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, sicodefaked);
16911.83Skamil	}
16921.1Skamil
16931.180Skamil	DPRINTF("Before resuming the child process where it left off and "
16941.180Skamil	    "without signal to be sent\n");
16951.180Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
16961.180Skamil	    faked ? sigfaked : sigval) != -1);
16971.1Skamil
16981.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16991.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17001.1Skamil
17011.180Skamil	validate_status_exited(status, exitval);
17021.1Skamil
17031.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17041.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
17051.1Skamil}
17061.1Skamil
17071.180Skamil#define PTRACE_SIGINFO(test, faked)					\
17081.83SkamilATF_TC(test);								\
17091.83SkamilATF_TC_HEAD(test, tc)							\
17101.83Skamil{									\
17111.180Skamil	atf_tc_set_md_var(tc, "descr",					\
17121.180Skamil	    "Verify basic PT_GET_SIGINFO and PT_SET_SIGINFO calls"	\
17131.180Skamil	    "with%s setting signal to new value", faked ? "" : "out");	\
17141.180Skamil}									\
17151.180Skamil									\
17161.180Skamilstatic int test##_caught = 0;						\
17171.180Skamil									\
17181.180Skamilstatic void								\
17191.180Skamiltest##_sighandler(int sig, siginfo_t *info, void *ctx)			\
17201.180Skamil{									\
17211.180Skamil	if (faked) {							\
17221.180Skamil		FORKEE_ASSERT_EQ(sig, SIGTRAP);				\
17231.180Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGTRAP);		\
17241.180Skamil		FORKEE_ASSERT_EQ(info->si_code, TRAP_BRKPT);		\
17251.180Skamil	} else {							\
17261.180Skamil		FORKEE_ASSERT_EQ(sig, SIGINT);				\
17271.180Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGINT);		\
17281.180Skamil		FORKEE_ASSERT_EQ(info->si_code, SI_LWP);		\
17291.180Skamil	}								\
17301.180Skamil									\
17311.180Skamil	++ test##_caught;						\
17321.83Skamil}									\
17331.83Skamil									\
17341.83SkamilATF_TC_BODY(test, tc)							\
17351.83Skamil{									\
17361.83Skamil									\
17371.180Skamil	ptrace_siginfo(faked, test##_sighandler, & test##_caught); 	\
17381.83Skamil}
17391.83Skamil
17401.180SkamilPTRACE_SIGINFO(siginfo_set_unmodified, false)
17411.180SkamilPTRACE_SIGINFO(siginfo_set_faked, true)
17421.83Skamil
17431.83Skamil/// ----------------------------------------------------------------------------
17441.83Skamil
17451.180Skamilstatic void
17461.180Skamiltraceme_exec(bool masked, bool ignored)
17471.1Skamil{
17481.180Skamil	const int sigval = SIGTRAP;
17491.1Skamil	pid_t child, wpid;
17501.1Skamil#if defined(TWAIT_HAVE_STATUS)
17511.1Skamil	int status;
17521.1Skamil#endif
17531.180Skamil	struct sigaction sa;
17541.180Skamil	struct ptrace_siginfo info;
17551.1Skamil	sigset_t intmask;
17561.180Skamil	struct kinfo_proc2 kp;
17571.180Skamil	size_t len = sizeof(kp);
17581.180Skamil
17591.180Skamil	int name[6];
17601.180Skamil	const size_t namelen = __arraycount(name);
17611.180Skamil	ki_sigset_t kp_sigmask;
17621.180Skamil	ki_sigset_t kp_sigignore;
17631.180Skamil
17641.180Skamil	memset(&info, 0, sizeof(info));
17651.1Skamil
17661.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
17671.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
17681.1Skamil	if (child == 0) {
17691.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
17701.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
17711.1Skamil
17721.180Skamil		if (masked) {
17731.180Skamil			sigemptyset(&intmask);
17741.180Skamil			sigaddset(&intmask, sigval);
17751.180Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
17761.180Skamil		}
17771.1Skamil
17781.180Skamil		if (ignored) {
17791.180Skamil			memset(&sa, 0, sizeof(sa));
17801.180Skamil			sa.sa_handler = SIG_IGN;
17811.180Skamil			sigemptyset(&sa.sa_mask);
17821.180Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
17831.180Skamil		}
17841.1Skamil
17851.180Skamil		DPRINTF("Before calling execve(2) from child\n");
17861.180Skamil		execlp("/bin/echo", "/bin/echo", NULL);
17871.1Skamil
17881.180Skamil		FORKEE_ASSERT(0 && "Not reached");
17891.1Skamil	}
17901.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
17911.1Skamil
17921.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17931.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17941.1Skamil
17951.1Skamil	validate_status_stopped(status, sigval);
17961.1Skamil
17971.180Skamil	name[0] = CTL_KERN,
17981.180Skamil	name[1] = KERN_PROC2,
17991.180Skamil	name[2] = KERN_PROC_PID;
18001.180Skamil	name[3] = getpid();
18011.180Skamil	name[4] = sizeof(kp);
18021.180Skamil	name[5] = 1;
18031.180Skamil
18041.180Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
18051.180Skamil
18061.180Skamil	if (masked)
18071.180Skamil		kp_sigmask = kp.p_sigmask;
18081.180Skamil
18091.180Skamil	if (ignored)
18101.180Skamil		kp_sigignore = kp.p_sigignore;
18111.180Skamil
18121.180Skamil	name[3] = getpid();
18131.180Skamil
18141.180Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
18151.180Skamil
18161.180Skamil	if (masked) {
18171.180Skamil		DPRINTF("kp_sigmask="
18181.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
18191.180Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
18201.180Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
18211.180Skamil
18221.180Skamil		DPRINTF("kp.p_sigmask="
18231.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
18241.180Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
18251.180Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
18261.180Skamil
18271.180Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
18281.180Skamil		    sizeof(kp_sigmask)));
18291.180Skamil	}
18301.180Skamil
18311.180Skamil	if (ignored) {
18321.180Skamil		DPRINTF("kp_sigignore="
18331.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
18341.180Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
18351.180Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
18361.180Skamil
18371.180Skamil		DPRINTF("kp.p_sigignore="
18381.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
18391.180Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
18401.180Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
18411.180Skamil
18421.180Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
18431.180Skamil		    sizeof(kp_sigignore)));
18441.180Skamil	}
18451.180Skamil
18461.180Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
18471.180Skamil	SYSCALL_REQUIRE(
18481.180Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
18491.1Skamil
18501.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
18511.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
18521.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
18531.180Skamil	    info.psi_siginfo.si_errno);
18541.1Skamil
18551.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
18561.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
18571.1Skamil
18581.13Schristos	DPRINTF("Before resuming the child process where it left off and "
18591.1Skamil	    "without signal to be sent\n");
18601.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
18611.1Skamil
18621.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18631.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
18641.1Skamil
18651.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18661.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
18671.1Skamil}
18681.1Skamil
18691.180Skamil#define TRACEME_EXEC(test, masked, ignored)				\
18701.180SkamilATF_TC(test);								\
18711.180SkamilATF_TC_HEAD(test, tc)							\
18721.180Skamil{									\
18731.180Skamil       atf_tc_set_md_var(tc, "descr",					\
18741.180Skamil           "Detect SIGTRAP TRAP_EXEC from "				\
18751.180Skamil           "child%s%s", masked ? " with masked signal" : "",		\
18761.180Skamil           masked ? " with ignored signal" : "");			\
18771.180Skamil}									\
18781.180Skamil									\
18791.180SkamilATF_TC_BODY(test, tc)							\
18801.180Skamil{									\
18811.180Skamil									\
18821.180Skamil       traceme_exec(masked, ignored);					\
18831.180Skamil}
18841.180Skamil
18851.180SkamilTRACEME_EXEC(traceme_exec, false, false)
18861.180SkamilTRACEME_EXEC(traceme_signalmasked_exec, true, false)
18871.180SkamilTRACEME_EXEC(traceme_signalignored_exec, false, true)
18881.180Skamil
18891.84Skamil/// ----------------------------------------------------------------------------
18901.84Skamil
18911.180Skamil#define TRACE_THREADS_NUM 100
18921.180Skamil
18931.180Skamilstatic volatile int done;
18941.180Skamilpthread_mutex_t trace_threads_mtx = PTHREAD_MUTEX_INITIALIZER;
18951.180Skamil
18961.180Skamilstatic void *
18971.180Skamiltrace_threads_cb(void *arg __unused)
18981.180Skamil{
18991.180Skamil
19001.180Skamil	pthread_mutex_lock(&trace_threads_mtx);
19011.180Skamil	done++;
19021.180Skamil	pthread_mutex_unlock(&trace_threads_mtx);
19031.180Skamil
19041.180Skamil	while (done < TRACE_THREADS_NUM)
19051.180Skamil		sched_yield();
19061.180Skamil
19071.180Skamil	return NULL;
19081.180Skamil}
19091.180Skamil
19101.99Skamilstatic void
19111.180Skamiltrace_threads(bool trace_create, bool trace_exit, bool masked)
19121.1Skamil{
19131.1Skamil	const int sigval = SIGSTOP;
19141.180Skamil	pid_t child, wpid;
19151.1Skamil#if defined(TWAIT_HAVE_STATUS)
19161.1Skamil	int status;
19171.1Skamil#endif
19181.1Skamil	ptrace_state_t state;
19191.1Skamil	const int slen = sizeof(state);
19201.1Skamil	ptrace_event_t event;
19211.1Skamil	const int elen = sizeof(event);
19221.99Skamil	struct ptrace_siginfo info;
19231.180Skamil
19241.99Skamil	sigset_t intmask;
19251.99Skamil
19261.180Skamil	pthread_t t[TRACE_THREADS_NUM];
19271.180Skamil	int rv;
19281.180Skamil	size_t n;
19291.180Skamil	lwpid_t lid;
19301.1Skamil
19311.180Skamil	/* Track created and exited threads */
19321.180Skamil	struct lwp_event_count traced_lwps[__arraycount(t)] = {{0, 0}};
19331.14Schristos
19341.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
19351.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
19361.1Skamil	if (child == 0) {
19371.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
19381.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
19391.1Skamil
19401.99Skamil		if (masked) {
19411.99Skamil			sigemptyset(&intmask);
19421.99Skamil			sigaddset(&intmask, SIGTRAP);
19431.99Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
19441.99Skamil		}
19451.99Skamil
19461.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
19471.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
19481.1Skamil
19491.180Skamil		for (n = 0; n < __arraycount(t); n++) {
19501.180Skamil			rv = pthread_create(&t[n], NULL, trace_threads_cb,
19511.180Skamil			    NULL);
19521.180Skamil			FORKEE_ASSERT(rv == 0);
19531.126Skamil		}
19541.1Skamil
19551.180Skamil		for (n = 0; n < __arraycount(t); n++) {
19561.180Skamil			rv = pthread_join(t[n], NULL);
19571.180Skamil			FORKEE_ASSERT(rv == 0);
19581.180Skamil		}
19591.1Skamil
19601.180Skamil		/*
19611.180Skamil		 * There is race between _exit() and pthread_join() detaching
19621.180Skamil		 * a thread. For simplicity kill the process after detecting
19631.180Skamil		 * LWP events.
19641.180Skamil		 */
19651.180Skamil		while (true)
19661.180Skamil			continue;
19671.1Skamil
19681.180Skamil		FORKEE_ASSERT(0 && "Not reached");
19691.1Skamil	}
19701.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
19711.1Skamil
19721.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
19731.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
19741.1Skamil
19751.1Skamil	validate_status_stopped(status, sigval);
19761.1Skamil
19771.99Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
19781.99Skamil	SYSCALL_REQUIRE(
19791.99Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
19801.99Skamil
19811.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
19821.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
19831.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
19841.180Skamil	    info.psi_siginfo.si_errno);
19851.180Skamil
19861.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
19871.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
19881.1Skamil
19891.180Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
19901.180Skamil	memset(&event, 0, sizeof(event));
19911.180Skamil	if (trace_create)
19921.180Skamil		event.pe_set_event |= PTRACE_LWP_CREATE;
19931.180Skamil	if (trace_exit)
19941.180Skamil		event.pe_set_event |= PTRACE_LWP_EXIT;
19951.99Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
19961.1Skamil
19971.99Skamil	DPRINTF("Before resuming the child process where it left off and "
19981.99Skamil	    "without signal to be sent\n");
19991.99Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
20001.1Skamil
20011.180Skamil	for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
20021.180Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
20031.180Skamil		    "SIGTRAP\n", TWAIT_FNAME);
20041.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
20051.99Skamil		    child);
20061.1Skamil
20071.99Skamil		validate_status_stopped(status, SIGTRAP);
20081.1Skamil
20091.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
20101.180Skamil		    "child\n");
20111.180Skamil		SYSCALL_REQUIRE(
20121.180Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
20131.180Skamil
20141.180Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
20151.180Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
20161.180Skamil		    "si_errno=%#x\n",
20171.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
20181.180Skamil		    info.psi_siginfo.si_errno);
20191.1Skamil
20201.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
20211.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
20221.1Skamil
20231.180Skamil		SYSCALL_REQUIRE(
20241.180Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
20251.1Skamil
20261.180Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
20271.180Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
20281.1Skamil
20291.180Skamil		lid = state.pe_lwp;
20301.180Skamil		DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
20311.1Skamil
20321.180Skamil		*FIND_EVENT_COUNT(traced_lwps, lid) += 1;
20331.1Skamil
20341.180Skamil		DPRINTF("Before resuming the child process where it left off "
20351.180Skamil		    "and without signal to be sent\n");
20361.180Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
20371.180Skamil	}
20381.1Skamil
20391.180Skamil	for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
20401.180Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
20411.180Skamil		    "SIGTRAP\n", TWAIT_FNAME);
20421.180Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
20431.180Skamil		    child);
20441.1Skamil
20451.99Skamil		validate_status_stopped(status, SIGTRAP);
20461.1Skamil
20471.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
20481.180Skamil		    "child\n");
20491.180Skamil		SYSCALL_REQUIRE(
20501.180Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
20511.1Skamil
20521.180Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
20531.180Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
20541.180Skamil		    "si_errno=%#x\n",
20551.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
20561.180Skamil		    info.psi_siginfo.si_errno);
20571.1Skamil
20581.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
20591.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
20601.14Schristos
20611.180Skamil		SYSCALL_REQUIRE(
20621.180Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
20631.1Skamil
20641.180Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
20651.180Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
20661.1Skamil
20671.180Skamil		lid = state.pe_lwp;
20681.180Skamil		DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
20691.1Skamil
20701.180Skamil		if (trace_create) {
20711.180Skamil			int *count = FIND_EVENT_COUNT(traced_lwps, lid);
20721.180Skamil			ATF_REQUIRE_EQ(*count, 1);
20731.180Skamil			*count = 0;
20741.99Skamil		}
20751.1Skamil
20761.99Skamil		DPRINTF("Before resuming the child process where it left off "
20771.99Skamil		    "and without signal to be sent\n");
20781.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
20791.1Skamil	}
20801.1Skamil
20811.180Skamil	kill(child, SIGKILL);
20821.180Skamil
20831.180Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
20841.180Skamil	    TWAIT_FNAME);
20851.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
20861.180Skamil
20871.180Skamil	validate_status_signaled(status, SIGKILL, 0);
20881.1Skamil
20891.180Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
20901.180Skamil	    TWAIT_FNAME);
20911.180Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
20921.180Skamil}
20931.1Skamil
20941.180Skamil#define TRACE_THREADS(test, trace_create, trace_exit, mask)		\
20951.180SkamilATF_TC(test);								\
20961.180SkamilATF_TC_HEAD(test, tc)							\
20971.180Skamil{									\
20981.180Skamil        atf_tc_set_md_var(tc, "descr",					\
20991.180Skamil            "Verify spawning threads with%s tracing LWP create and"	\
21001.180Skamil	    "with%s tracing LWP exit", trace_create ? "" : "out",	\
21011.180Skamil	    trace_exit ? "" : "out");					\
21021.180Skamil}									\
21031.180Skamil									\
21041.180SkamilATF_TC_BODY(test, tc)							\
21051.180Skamil{									\
21061.180Skamil									\
21071.180Skamil        trace_threads(trace_create, trace_exit, mask);			\
21081.180Skamil}
21091.1Skamil
21101.180SkamilTRACE_THREADS(trace_thread_nolwpevents, false, false, false)
21111.180SkamilTRACE_THREADS(trace_thread_lwpexit, false, true, false)
21121.180SkamilTRACE_THREADS(trace_thread_lwpcreate, true, false, false)
21131.180SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true, false)
21141.102Skamil
21151.180SkamilTRACE_THREADS(trace_thread_lwpexit_masked_sigtrap, false, true, true)
21161.180SkamilTRACE_THREADS(trace_thread_lwpcreate_masked_sigtrap, true, false, true)
21171.180SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit_masked_sigtrap, true, true, true)
21181.1Skamil
21191.180Skamil/// ----------------------------------------------------------------------------
21201.1Skamil
21211.151Skamilstatic void *
21221.151Skamilthread_and_exec_thread_cb(void *arg __unused)
21231.151Skamil{
21241.151Skamil
21251.151Skamil	execlp("/bin/echo", "/bin/echo", NULL);
21261.151Skamil
21271.151Skamil	abort();
21281.151Skamil}
21291.151Skamil
21301.151Skamilstatic void
21311.151Skamilthreads_and_exec(void)
21321.151Skamil{
21331.151Skamil	const int sigval = SIGSTOP;
21341.151Skamil	pid_t child, wpid;
21351.151Skamil#if defined(TWAIT_HAVE_STATUS)
21361.151Skamil	int status;
21371.151Skamil#endif
21381.151Skamil	ptrace_state_t state;
21391.151Skamil	const int slen = sizeof(state);
21401.151Skamil	ptrace_event_t event;
21411.151Skamil	const int elen = sizeof(event);
21421.151Skamil	struct ptrace_siginfo info;
21431.151Skamil
21441.151Skamil	pthread_t t;
21451.151Skamil	lwpid_t lid;
21461.151Skamil
21471.151Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
21481.151Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
21491.151Skamil	if (child == 0) {
21501.151Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
21511.151Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
21521.151Skamil
21531.151Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
21541.151Skamil		FORKEE_ASSERT(raise(sigval) == 0);
21551.151Skamil
21561.151Skamil		FORKEE_ASSERT(pthread_create(&t, NULL,
21571.151Skamil		    thread_and_exec_thread_cb, NULL) == 0);
21581.151Skamil
21591.151Skamil		for (;;)
21601.151Skamil			continue;
21611.151Skamil
21621.151Skamil		FORKEE_ASSERT(0 && "Not reached");
21631.151Skamil	}
21641.151Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
21651.151Skamil
21661.151Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
21671.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
21681.151Skamil
21691.151Skamil	validate_status_stopped(status, sigval);
21701.151Skamil
21711.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
21721.151Skamil	SYSCALL_REQUIRE(
21731.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
21741.151Skamil
21751.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
21761.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
21771.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
21781.151Skamil	    info.psi_siginfo.si_errno);
21791.151Skamil
21801.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
21811.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
21821.151Skamil
21831.151Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
21841.151Skamil	memset(&event, 0, sizeof(event));
21851.151Skamil	event.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
21861.151Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
21871.151Skamil
21881.151Skamil	DPRINTF("Before resuming the child process where it left off and "
21891.151Skamil	    "without signal to be sent\n");
21901.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
21911.151Skamil
21921.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
21931.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
21941.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
21951.151Skamil	    child);
21961.151Skamil
21971.151Skamil	validate_status_stopped(status, SIGTRAP);
21981.151Skamil
21991.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
22001.151Skamil	    "child\n");
22011.151Skamil	SYSCALL_REQUIRE(
22021.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
22031.151Skamil
22041.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
22051.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
22061.151Skamil	    "si_errno=%#x\n",
22071.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
22081.151Skamil	    info.psi_siginfo.si_errno);
22091.151Skamil
22101.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
22111.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
22121.151Skamil
22131.151Skamil	SYSCALL_REQUIRE(
22141.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
22151.151Skamil
22161.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
22171.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
22181.151Skamil
22191.151Skamil	lid = state.pe_lwp;
22201.151Skamil	DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
22211.151Skamil
22221.151Skamil	DPRINTF("Before resuming the child process where it left off "
22231.151Skamil	    "and without signal to be sent\n");
22241.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
22251.151Skamil
22261.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
22271.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
22281.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
22291.151Skamil	    child);
22301.151Skamil
22311.151Skamil	validate_status_stopped(status, SIGTRAP);
22321.151Skamil
22331.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
22341.151Skamil	    "child\n");
22351.151Skamil	SYSCALL_REQUIRE(
22361.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
22371.151Skamil
22381.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
22391.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
22401.151Skamil	    "si_errno=%#x\n",
22411.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
22421.151Skamil	    info.psi_siginfo.si_errno);
22431.151Skamil
22441.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
22451.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
22461.151Skamil
22471.151Skamil	SYSCALL_REQUIRE(
22481.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
22491.151Skamil
22501.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
22511.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
22521.151Skamil
22531.151Skamil	lid = state.pe_lwp;
22541.151Skamil	DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
22551.151Skamil
22561.151Skamil	DPRINTF("Before resuming the child process where it left off "
22571.151Skamil	    "and without signal to be sent\n");
22581.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
22591.151Skamil
22601.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
22611.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
22621.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
22631.151Skamil	    child);
22641.151Skamil
22651.151Skamil	validate_status_stopped(status, SIGTRAP);
22661.151Skamil
22671.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
22681.151Skamil	    "child\n");
22691.151Skamil	SYSCALL_REQUIRE(
22701.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
22711.151Skamil
22721.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
22731.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
22741.151Skamil	    "si_errno=%#x\n",
22751.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
22761.151Skamil	    info.psi_siginfo.si_errno);
22771.151Skamil
22781.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
22791.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
22801.151Skamil
22811.151Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
22821.151Skamil
22831.151Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
22841.151Skamil	    TWAIT_FNAME);
22851.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
22861.151Skamil
22871.151Skamil	validate_status_signaled(status, SIGKILL, 0);
22881.151Skamil
22891.151Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
22901.151Skamil	    TWAIT_FNAME);
22911.151Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
22921.151Skamil}
22931.151Skamil
22941.151SkamilATF_TC(threads_and_exec);
22951.151SkamilATF_TC_HEAD(threads_and_exec, tc)
22961.151Skamil{
22971.151Skamil        atf_tc_set_md_var(tc, "descr",
22981.151Skamil            "Verify that multithreaded application on exec() will report "
22991.151Skamil	    "LWP_EXIT events");
23001.151Skamil}
23011.151Skamil
23021.151SkamilATF_TC_BODY(threads_and_exec, tc)
23031.151Skamil{
23041.151Skamil
23051.151Skamil        threads_and_exec();
23061.151Skamil}
23071.151Skamil
23081.151Skamil/// ----------------------------------------------------------------------------
23091.151Skamil
23101.154SkamilATF_TC(suspend_no_deadlock);
23111.154SkamilATF_TC_HEAD(suspend_no_deadlock, tc)
23121.1Skamil{
23131.1Skamil	atf_tc_set_md_var(tc, "descr",
23141.1Skamil	    "Verify that the while the only thread within a process is "
23151.1Skamil	    "suspended, the whole process cannot be unstopped");
23161.1Skamil}
23171.1Skamil
23181.154SkamilATF_TC_BODY(suspend_no_deadlock, tc)
23191.1Skamil{
23201.1Skamil	const int exitval = 5;
23211.1Skamil	const int sigval = SIGSTOP;
23221.1Skamil	pid_t child, wpid;
23231.1Skamil#if defined(TWAIT_HAVE_STATUS)
23241.1Skamil	int status;
23251.1Skamil#endif
23261.1Skamil	struct ptrace_siginfo psi;
23271.1Skamil
23281.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
23291.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
23301.1Skamil	if (child == 0) {
23311.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
23321.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
23331.1Skamil
23341.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
23351.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
23361.1Skamil
23371.13Schristos		DPRINTF("Before exiting of the child process\n");
23381.1Skamil		_exit(exitval);
23391.1Skamil	}
23401.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
23411.1Skamil
23421.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
23431.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
23441.1Skamil
23451.1Skamil	validate_status_stopped(status, sigval);
23461.1Skamil
23471.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
23481.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
23491.1Skamil
23501.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
23511.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
23521.1Skamil
23531.13Schristos	DPRINTF("Before resuming the child process where it left off and "
23541.1Skamil	    "without signal to be sent\n");
23551.1Skamil	ATF_REQUIRE_ERRNO(EDEADLK,
23561.1Skamil	    ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
23571.1Skamil
23581.13Schristos	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
23591.13Schristos	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
23601.1Skamil
23611.13Schristos	DPRINTF("Before resuming the child process where it left off and "
23621.1Skamil	    "without signal to be sent\n");
23631.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
23641.1Skamil
23651.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
23661.1Skamil	    TWAIT_FNAME);
23671.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
23681.1Skamil
23691.1Skamil	validate_status_exited(status, exitval);
23701.1Skamil
23711.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
23721.1Skamil	    TWAIT_FNAME);
23731.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
23741.1Skamil}
23751.1Skamil
23761.154Skamil/// ----------------------------------------------------------------------------
23771.154Skamil
23781.155Skamilstatic pthread_barrier_t barrier1_resume;
23791.155Skamilstatic pthread_barrier_t barrier2_resume;
23801.154Skamil
23811.155Skamilstatic void *
23821.155Skamilresume_thread(void *arg)
23831.154Skamil{
23841.154Skamil
23851.155Skamil	raise(SIGUSR1);
23861.155Skamil
23871.155Skamil	pthread_barrier_wait(&barrier1_resume);
23881.155Skamil
23891.155Skamil	/* Debugger will suspend the process here */
23901.155Skamil
23911.155Skamil	pthread_barrier_wait(&barrier2_resume);
23921.154Skamil
23931.155Skamil	raise(SIGUSR2);
23941.155Skamil
23951.155Skamil	return infinite_thread(arg);
23961.154Skamil}
23971.154Skamil
23981.155SkamilATF_TC(resume);
23991.155SkamilATF_TC_HEAD(resume, tc)
24001.1Skamil{
24011.1Skamil	atf_tc_set_md_var(tc, "descr",
24021.1Skamil	    "Verify that a thread can be suspended by a debugger and later "
24031.1Skamil	    "resumed by the debugger");
24041.1Skamil}
24051.1Skamil
24061.155SkamilATF_TC_BODY(resume, tc)
24071.1Skamil{
24081.1Skamil	const int sigval = SIGSTOP;
24091.1Skamil	pid_t child, wpid;
24101.1Skamil#if defined(TWAIT_HAVE_STATUS)
24111.1Skamil	int status;
24121.1Skamil#endif
24131.1Skamil	lwpid_t lid;
24141.1Skamil	struct ptrace_siginfo psi;
24151.155Skamil	pthread_t t;
24161.1Skamil
24171.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
24181.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
24191.1Skamil	if (child == 0) {
24201.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
24211.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
24221.1Skamil
24231.155Skamil		pthread_barrier_init(&barrier1_resume, NULL, 2);
24241.155Skamil		pthread_barrier_init(&barrier2_resume, NULL, 2);
24251.155Skamil
24261.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
24271.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
24281.1Skamil
24291.155Skamil		DPRINTF("Before creating new thread in child\n");
24301.155Skamil		FORKEE_ASSERT(pthread_create(&t, NULL, resume_thread, NULL) == 0);
24311.1Skamil
24321.155Skamil		pthread_barrier_wait(&barrier1_resume);
24331.1Skamil
24341.155Skamil		pthread_barrier_wait(&barrier2_resume);
24351.1Skamil
24361.155Skamil		infinite_thread(NULL);
24371.1Skamil	}
24381.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
24391.1Skamil
24401.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
24411.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
24421.1Skamil
24431.1Skamil	validate_status_stopped(status, sigval);
24441.1Skamil
24451.13Schristos	DPRINTF("Before resuming the child process where it left off and "
24461.1Skamil	    "without signal to be sent\n");
24471.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
24481.1Skamil
24491.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
24501.155Skamil	    "SIGUSR1\n", TWAIT_FNAME);
24511.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
24521.1Skamil
24531.155Skamil	validate_status_stopped(status, SIGUSR1);
24541.1Skamil
24551.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
24561.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
24571.1Skamil
24581.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
24591.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
24601.1Skamil
24611.155Skamil	lid = psi.psi_lwpid;
24621.1Skamil
24631.13Schristos	DPRINTF("Before resuming the child process where it left off and "
24641.1Skamil	    "without signal to be sent\n");
24651.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
24661.1Skamil
24671.155Skamil	DPRINTF("Before suspending the parent for 1 second, we expect no signals\n");
24681.155Skamil	SYSCALL_REQUIRE(sleep(1) == 0);
24691.155Skamil
24701.155Skamil#if defined(TWAIT_HAVE_OPTIONS)
24711.155Skamil	DPRINTF("Before calling %s() for the child - expected no status\n",
24721.155Skamil	    TWAIT_FNAME);
24731.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, WNOHANG), 0);
24741.155Skamil#endif
24751.155Skamil
24761.155Skamil	DPRINTF("Before resuming the child process where it left off and "
24771.155Skamil	    "without signal to be sent\n");
24781.155Skamil	SYSCALL_REQUIRE(ptrace(PT_STOP, child, NULL, 0) != -1);
24791.155Skamil
24801.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
24811.155Skamil	    "SIGSTOP\n", TWAIT_FNAME);
24821.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
24831.1Skamil
24841.155Skamil	validate_status_stopped(status, SIGSTOP);
24851.1Skamil
24861.155Skamil	DPRINTF("Before resuming LWP %d\n", lid);
24871.155Skamil	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, lid) != -1);
24881.155Skamil
24891.155Skamil	DPRINTF("Before resuming the child process where it left off and "
24901.155Skamil	    "without signal to be sent\n");
24911.155Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
24921.1Skamil
24931.155Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
24941.155Skamil	    "SIGUSR2\n", TWAIT_FNAME);
24951.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
24961.1Skamil
24971.155Skamil	validate_status_stopped(status, SIGUSR2);
24981.1Skamil
24991.13Schristos	DPRINTF("Before resuming the child process where it left off and "
25001.1Skamil	    "without signal to be sent\n");
25011.155Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
25021.1Skamil
25031.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
25041.1Skamil	    TWAIT_FNAME);
25051.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
25061.1Skamil
25071.155Skamil	validate_status_signaled(status, SIGKILL, 0);
25081.1Skamil
25091.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
25101.1Skamil	    TWAIT_FNAME);
25111.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
25121.155Skamil}
25131.1Skamil
25141.155Skamil/// ----------------------------------------------------------------------------
25151.1Skamil
25161.106Skamilstatic void
25171.122Skamiluser_va0_disable(int operation)
25181.122Skamil{
25191.122Skamil	pid_t child, wpid;
25201.122Skamil#if defined(TWAIT_HAVE_STATUS)
25211.122Skamil	int status;
25221.122Skamil#endif
25231.122Skamil	const int sigval = SIGSTOP;
25241.122Skamil	int rv;
25251.122Skamil
25261.122Skamil	struct ptrace_siginfo info;
25271.122Skamil
25281.122Skamil	if (get_user_va0_disable() == 0)
25291.122Skamil		atf_tc_skip("vm.user_va0_disable is set to 0");
25301.122Skamil
25311.122Skamil	memset(&info, 0, sizeof(info));
25321.122Skamil
25331.122Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
25341.122Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
25351.122Skamil	if (child == 0) {
25361.122Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
25371.122Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
25381.122Skamil
25391.122Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
25401.122Skamil		FORKEE_ASSERT(raise(sigval) == 0);
25411.122Skamil
25421.122Skamil		/* NOTREACHED */
25431.122Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
25441.122Skamil		__unreachable();
25451.122Skamil	}
25461.122Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
25471.122Skamil
25481.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
25491.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
25501.122Skamil
25511.122Skamil	validate_status_stopped(status, sigval);
25521.122Skamil
25531.122Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
25541.122Skamil		"child\n");
25551.122Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
25561.122Skamil		sizeof(info)) != -1);
25571.122Skamil
25581.122Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
25591.122Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
25601.122Skamil		"si_errno=%#x\n",
25611.122Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
25621.122Skamil		info.psi_siginfo.si_errno);
25631.122Skamil
25641.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
25651.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
25661.122Skamil
25671.122Skamil	DPRINTF("Before resuming the child process in PC=0x0 "
25681.122Skamil	    "and without signal to be sent\n");
25691.122Skamil	errno = 0;
25701.122Skamil	rv = ptrace(operation, child, (void *)0, 0);
25711.122Skamil	ATF_REQUIRE_EQ(errno, EINVAL);
25721.122Skamil	ATF_REQUIRE_EQ(rv, -1);
25731.122Skamil
25741.122Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
25751.122Skamil
25761.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
25771.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
25781.122Skamil	validate_status_signaled(status, SIGKILL, 0);
25791.122Skamil
25801.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
25811.122Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
25821.122Skamil}
25831.122Skamil
25841.122Skamil#define USER_VA0_DISABLE(test, operation)				\
25851.122SkamilATF_TC(test);								\
25861.122SkamilATF_TC_HEAD(test, tc)							\
25871.122Skamil{									\
25881.122Skamil	atf_tc_set_md_var(tc, "descr",					\
25891.122Skamil	    "Verify behavior of " #operation " with PC set to 0x0");	\
25901.122Skamil}									\
25911.122Skamil									\
25921.122SkamilATF_TC_BODY(test, tc)							\
25931.122Skamil{									\
25941.122Skamil									\
25951.122Skamil	user_va0_disable(operation);					\
25961.122Skamil}
25971.122Skamil
25981.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_continue, PT_CONTINUE)
25991.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_syscall, PT_SYSCALL)
26001.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_detach, PT_DETACH)
26011.122Skamil
26021.122Skamil/// ----------------------------------------------------------------------------
26031.122Skamil
26041.130Smgorny/*
26051.130Smgorny * Parse the core file and find the requested note.  If the reading or parsing
26061.130Smgorny * fails, the test is failed.  If the note is found, it is read onto buf, up to
26071.130Smgorny * buf_len.  The actual length of the note is returned (which can be greater
26081.130Smgorny * than buf_len, indicating that it has been truncated).  If the note is not
26091.130Smgorny * found, -1 is returned.
26101.172Sthorpej *
26111.172Sthorpej * If the note_name ends in '*', then we find the first note that matches
26121.172Sthorpej * the note_name prefix up to the '*' character, e.g.:
26131.172Sthorpej *
26141.172Sthorpej *	NetBSD-CORE@*
26151.172Sthorpej *
26161.172Sthorpej * finds the first note whose name prefix matches "NetBSD-CORE@".
26171.130Smgorny */
26181.130Smgornystatic ssize_t core_find_note(const char *core_path,
26191.130Smgorny    const char *note_name, uint64_t note_type, void *buf, size_t buf_len)
26201.130Smgorny{
26211.130Smgorny	int core_fd;
26221.130Smgorny	Elf *core_elf;
26231.130Smgorny	size_t core_numhdr, i;
26241.130Smgorny	ssize_t ret = -1;
26251.172Sthorpej	size_t name_len = strlen(note_name);
26261.172Sthorpej	bool prefix_match = false;
26271.172Sthorpej
26281.172Sthorpej	if (note_name[name_len - 1] == '*') {
26291.172Sthorpej		prefix_match = true;
26301.172Sthorpej		name_len--;
26311.172Sthorpej	} else {
26321.172Sthorpej		/* note: we assume note name will be null-terminated */
26331.172Sthorpej		name_len++;
26341.172Sthorpej	}
26351.130Smgorny
26361.130Smgorny	SYSCALL_REQUIRE((core_fd = open(core_path, O_RDONLY)) != -1);
26371.130Smgorny	SYSCALL_REQUIRE(elf_version(EV_CURRENT) != EV_NONE);
26381.130Smgorny	SYSCALL_REQUIRE((core_elf = elf_begin(core_fd, ELF_C_READ, NULL)));
26391.130Smgorny
26401.130Smgorny	SYSCALL_REQUIRE(elf_getphnum(core_elf, &core_numhdr) != 0);
26411.130Smgorny	for (i = 0; i < core_numhdr && ret == -1; i++) {
26421.130Smgorny		GElf_Phdr core_hdr;
26431.130Smgorny		size_t offset;
26441.130Smgorny		SYSCALL_REQUIRE(gelf_getphdr(core_elf, i, &core_hdr));
26451.130Smgorny		if (core_hdr.p_type != PT_NOTE)
26461.130Smgorny		    continue;
26471.130Smgorny
26481.130Smgorny		for (offset = core_hdr.p_offset;
26491.130Smgorny		    offset < core_hdr.p_offset + core_hdr.p_filesz;) {
26501.130Smgorny			Elf64_Nhdr note_hdr;
26511.130Smgorny			char name_buf[64];
26521.130Smgorny
26531.130Smgorny			switch (gelf_getclass(core_elf)) {
26541.130Smgorny			case ELFCLASS64:
26551.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &note_hdr,
26561.130Smgorny				    sizeof(note_hdr), offset)
26571.130Smgorny				    == sizeof(note_hdr));
26581.130Smgorny				offset += sizeof(note_hdr);
26591.130Smgorny				break;
26601.130Smgorny			case ELFCLASS32:
26611.130Smgorny				{
26621.130Smgorny				Elf32_Nhdr tmp_hdr;
26631.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &tmp_hdr,
26641.130Smgorny				    sizeof(tmp_hdr), offset)
26651.130Smgorny				    == sizeof(tmp_hdr));
26661.130Smgorny				offset += sizeof(tmp_hdr);
26671.130Smgorny				note_hdr.n_namesz = tmp_hdr.n_namesz;
26681.130Smgorny				note_hdr.n_descsz = tmp_hdr.n_descsz;
26691.130Smgorny				note_hdr.n_type = tmp_hdr.n_type;
26701.130Smgorny				}
26711.130Smgorny				break;
26721.130Smgorny			}
26731.130Smgorny
26741.130Smgorny			/* indicates end of notes */
26751.130Smgorny			if (note_hdr.n_namesz == 0 || note_hdr.n_descsz == 0)
26761.130Smgorny				break;
26771.172Sthorpej			if (((prefix_match &&
26781.172Sthorpej			      note_hdr.n_namesz > name_len) ||
26791.172Sthorpej			     (!prefix_match &&
26801.172Sthorpej			      note_hdr.n_namesz == name_len)) &&
26811.130Smgorny			    note_hdr.n_namesz <= sizeof(name_buf)) {
26821.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, name_buf,
26831.130Smgorny				    note_hdr.n_namesz, offset)
26841.131Skamil				    == (ssize_t)(size_t)note_hdr.n_namesz);
26851.130Smgorny
26861.130Smgorny				if (!strncmp(note_name, name_buf, name_len) &&
26871.130Smgorny				    note_hdr.n_type == note_type)
26881.130Smgorny					ret = note_hdr.n_descsz;
26891.130Smgorny			}
26901.130Smgorny
26911.130Smgorny			offset += note_hdr.n_namesz;
26921.130Smgorny			/* fix to alignment */
26931.146Smgorny			offset = roundup(offset, core_hdr.p_align);
26941.130Smgorny
26951.130Smgorny			/* if name & type matched above */
26961.130Smgorny			if (ret != -1) {
26971.130Smgorny				ssize_t read_len = MIN(buf_len,
26981.130Smgorny				    note_hdr.n_descsz);
26991.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, buf,
27001.130Smgorny				    read_len, offset) == read_len);
27011.130Smgorny				break;
27021.130Smgorny			}
27031.130Smgorny
27041.130Smgorny			offset += note_hdr.n_descsz;
27051.146Smgorny			/* fix to alignment */
27061.146Smgorny			offset = roundup(offset, core_hdr.p_align);
27071.130Smgorny		}
27081.130Smgorny	}
27091.130Smgorny
27101.130Smgorny	elf_end(core_elf);
27111.130Smgorny	close(core_fd);
27121.130Smgorny
27131.130Smgorny	return ret;
27141.130Smgorny}
27151.130Smgorny
27161.130SmgornyATF_TC(core_dump_procinfo);
27171.130SmgornyATF_TC_HEAD(core_dump_procinfo, tc)
27181.130Smgorny{
27191.130Smgorny	atf_tc_set_md_var(tc, "descr",
27201.130Smgorny		"Trigger a core dump and verify its contents.");
27211.130Smgorny}
27221.130Smgorny
27231.130SmgornyATF_TC_BODY(core_dump_procinfo, tc)
27241.130Smgorny{
27251.130Smgorny	const int exitval = 5;
27261.130Smgorny	pid_t child, wpid;
27271.130Smgorny#if defined(TWAIT_HAVE_STATUS)
27281.130Smgorny	const int sigval = SIGTRAP;
27291.130Smgorny	int status;
27301.130Smgorny#endif
27311.130Smgorny	char core_path[] = "/tmp/core.XXXXXX";
27321.130Smgorny	int core_fd;
27331.130Smgorny	struct netbsd_elfcore_procinfo procinfo;
27341.130Smgorny
27351.130Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
27361.130Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
27371.130Smgorny	if (child == 0) {
27381.130Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
27391.130Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
27401.130Smgorny
27411.130Smgorny		DPRINTF("Before triggering SIGTRAP\n");
27421.130Smgorny		trigger_trap();
27431.130Smgorny
27441.130Smgorny		DPRINTF("Before exiting of the child process\n");
27451.130Smgorny		_exit(exitval);
27461.130Smgorny	}
27471.130Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
27481.130Smgorny
27491.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
27501.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
27511.130Smgorny
27521.130Smgorny	validate_status_stopped(status, sigval);
27531.130Smgorny
27541.130Smgorny	SYSCALL_REQUIRE((core_fd = mkstemp(core_path)) != -1);
27551.130Smgorny	close(core_fd);
27561.130Smgorny
27571.130Smgorny	DPRINTF("Call DUMPCORE for the child process\n");
27581.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_DUMPCORE, child, core_path, strlen(core_path))
27591.130Smgorny	    != -1);
27601.130Smgorny
27611.130Smgorny	DPRINTF("Read core file\n");
27621.130Smgorny	ATF_REQUIRE_EQ(core_find_note(core_path, "NetBSD-CORE",
27631.130Smgorny	    ELF_NOTE_NETBSD_CORE_PROCINFO, &procinfo, sizeof(procinfo)),
27641.130Smgorny	    sizeof(procinfo));
27651.130Smgorny
27661.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_version, 1);
27671.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_cpisize, sizeof(procinfo));
27681.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_signo, SIGTRAP);
27691.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pid, child);
27701.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ppid, getpid());
27711.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pgrp, getpgid(child));
27721.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_sid, getsid(child));
27731.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ruid, getuid());
27741.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_euid, geteuid());
27751.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_rgid, getgid());
27761.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_egid, getegid());
27771.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_nlwps, 1);
27781.173Skamil	ATF_CHECK(procinfo.cpi_siglwp > 0);
27791.130Smgorny
27801.130Smgorny	unlink(core_path);
27811.130Smgorny
27821.130Smgorny	DPRINTF("Before resuming the child process where it left off and "
27831.130Smgorny	    "without signal to be sent\n");
27841.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
27851.130Smgorny
27861.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
27871.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
27881.130Smgorny
27891.130Smgorny	validate_status_exited(status, exitval);
27901.130Smgorny
27911.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
27921.130Smgorny	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
27931.130Smgorny}
27941.130Smgorny
27951.130Smgorny/// ----------------------------------------------------------------------------
27961.130Smgorny
27971.138Smgorny#if defined(TWAIT_HAVE_STATUS)
27981.138Smgorny
27991.160Smgorny#define THREAD_CONCURRENT_BREAKPOINT_NUM 50
28001.156Smgorny#define THREAD_CONCURRENT_SIGNALS_NUM 50
28011.161Smgorny#define THREAD_CONCURRENT_WATCHPOINT_NUM 50
28021.138Smgorny
28031.138Smgorny/* List of signals to use for the test */
28041.138Smgornyconst int thread_concurrent_signals_list[] = {
28051.138Smgorny	SIGIO,
28061.138Smgorny	SIGXCPU,
28071.138Smgorny	SIGXFSZ,
28081.138Smgorny	SIGVTALRM,
28091.138Smgorny	SIGPROF,
28101.138Smgorny	SIGWINCH,
28111.138Smgorny	SIGINFO,
28121.138Smgorny	SIGUSR1,
28131.138Smgorny	SIGUSR2
28141.138Smgorny};
28151.138Smgorny
28161.157Smgornyenum thread_concurrent_signal_handling {
28171.157Smgorny	/* the signal is discarded by debugger */
28181.157Smgorny	TCSH_DISCARD,
28191.157Smgorny	/* the handler is set to SIG_IGN */
28201.157Smgorny	TCSH_SIG_IGN,
28211.157Smgorny	/* an actual handler is used */
28221.157Smgorny	TCSH_HANDLER
28231.157Smgorny};
28241.157Smgorny
28251.156Smgornystatic pthread_barrier_t thread_concurrent_barrier;
28261.158Smgornystatic pthread_key_t thread_concurrent_key;
28271.161Smgornystatic uint32_t thread_concurrent_watchpoint_var = 0;
28281.138Smgorny
28291.160Smgornystatic void *
28301.160Smgornythread_concurrent_breakpoint_thread(void *arg)
28311.160Smgorny{
28321.160Smgorny	static volatile int watchme = 1;
28331.160Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
28341.160Smgorny	DPRINTF("Before entering breakpoint func from LWP %d\n", _lwp_self());
28351.160Smgorny	check_happy(watchme);
28361.160Smgorny	return NULL;
28371.160Smgorny}
28381.160Smgorny
28391.157Smgornystatic void
28401.157Smgornythread_concurrent_sig_handler(int sig)
28411.157Smgorny{
28421.158Smgorny	void *tls_val = pthread_getspecific(thread_concurrent_key);
28431.158Smgorny	DPRINTF("Before increment, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
28441.158Smgorny	FORKEE_ASSERT(pthread_setspecific(thread_concurrent_key,
28451.158Smgorny	    (void*)((uintptr_t)tls_val + 1)) == 0);
28461.157Smgorny}
28471.157Smgorny
28481.138Smgornystatic void *
28491.138Smgornythread_concurrent_signals_thread(void *arg)
28501.138Smgorny{
28511.138Smgorny	int sigval = thread_concurrent_signals_list[
28521.138Smgorny	    _lwp_self() % __arraycount(thread_concurrent_signals_list)];
28531.158Smgorny	enum thread_concurrent_signal_handling *signal_handle = arg;
28541.158Smgorny	void *tls_val;
28551.158Smgorny
28561.156Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
28571.138Smgorny	DPRINTF("Before raising %s from LWP %d\n", strsignal(sigval),
28581.138Smgorny		_lwp_self());
28591.138Smgorny	pthread_kill(pthread_self(), sigval);
28601.158Smgorny	if (*signal_handle == TCSH_HANDLER) {
28611.158Smgorny	    tls_val = pthread_getspecific(thread_concurrent_key);
28621.158Smgorny	    DPRINTF("After raising, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
28631.158Smgorny	    FORKEE_ASSERT(tls_val == (void*)1);
28641.158Smgorny	}
28651.138Smgorny	return NULL;
28661.138Smgorny}
28671.138Smgorny
28681.161Smgornystatic void *
28691.161Smgornythread_concurrent_watchpoint_thread(void *arg)
28701.161Smgorny{
28711.161Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
28721.161Smgorny	DPRINTF("Before modifying var from LWP %d\n", _lwp_self());
28731.161Smgorny	thread_concurrent_watchpoint_var = 1;
28741.161Smgorny	return NULL;
28751.161Smgorny}
28761.161Smgorny
28771.160Smgorny#if defined(__i386__) || defined(__x86_64__)
28781.160Smgornyenum thread_concurrent_sigtrap_event {
28791.160Smgorny	TCSE_UNKNOWN,
28801.161Smgorny	TCSE_BREAKPOINT,
28811.161Smgorny	TCSE_WATCHPOINT
28821.160Smgorny};
28831.160Smgorny
28841.160Smgornystatic void
28851.160Smgornythread_concurrent_lwp_setup(pid_t child, lwpid_t lwpid);
28861.160Smgornystatic enum thread_concurrent_sigtrap_event
28871.160Smgornythread_concurrent_handle_sigtrap(pid_t child, ptrace_siginfo_t *info);
28881.160Smgorny#endif
28891.160Smgorny
28901.156Smgornystatic void
28911.157Smgornythread_concurrent_test(enum thread_concurrent_signal_handling signal_handle,
28921.161Smgorny    int breakpoint_threads, int signal_threads, int watchpoint_threads)
28931.138Smgorny{
28941.138Smgorny	const int exitval = 5;
28951.138Smgorny	const int sigval = SIGSTOP;
28961.138Smgorny	pid_t child, wpid;
28971.138Smgorny	int status;
28981.141Skamil	struct lwp_event_count signal_counts[THREAD_CONCURRENT_SIGNALS_NUM]
28991.141Skamil	    = {{0, 0}};
29001.160Smgorny	struct lwp_event_count bp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
29011.160Smgorny	    = {{0, 0}};
29021.161Smgorny	struct lwp_event_count wp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
29031.161Smgorny	    = {{0, 0}};
29041.159Smgorny	ptrace_event_t event;
29051.156Smgorny	int i;
29061.156Smgorny
29071.164Skamil#if defined(HAVE_DBREGS)
29081.164Skamil	if (!can_we_set_dbregs()) {
29091.164Skamil		atf_tc_skip("Either run this test as root or set sysctl(3) "
29101.164Skamil		            "security.models.extensions.user_set_dbregs to 1");
29111.164Skamil        }
29121.164Skamil#endif
29131.164Skamil
29141.164Skamil	atf_tc_skip("PR kern/54960");
29151.157Smgorny
29161.156Smgorny	/* Protect against out-of-bounds array access. */
29171.160Smgorny	ATF_REQUIRE(breakpoint_threads <= THREAD_CONCURRENT_BREAKPOINT_NUM);
29181.156Smgorny	ATF_REQUIRE(signal_threads <= THREAD_CONCURRENT_SIGNALS_NUM);
29191.161Smgorny	ATF_REQUIRE(watchpoint_threads <= THREAD_CONCURRENT_WATCHPOINT_NUM);
29201.138Smgorny
29211.138Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
29221.138Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
29231.138Smgorny	if (child == 0) {
29241.160Smgorny		pthread_t bp_threads[THREAD_CONCURRENT_BREAKPOINT_NUM];
29251.156Smgorny		pthread_t sig_threads[THREAD_CONCURRENT_SIGNALS_NUM];
29261.161Smgorny		pthread_t wp_threads[THREAD_CONCURRENT_WATCHPOINT_NUM];
29271.138Smgorny
29281.138Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
29291.138Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
29301.138Smgorny
29311.138Smgorny		DPRINTF("Before raising %s from child\n", strsignal(sigval));
29321.138Smgorny		FORKEE_ASSERT(raise(sigval) == 0);
29331.138Smgorny
29341.157Smgorny		if (signal_handle != TCSH_DISCARD) {
29351.157Smgorny			struct sigaction sa;
29361.157Smgorny			unsigned int j;
29371.157Smgorny
29381.157Smgorny			memset(&sa, 0, sizeof(sa));
29391.157Smgorny			if (signal_handle == TCSH_SIG_IGN)
29401.157Smgorny				sa.sa_handler = SIG_IGN;
29411.157Smgorny			else
29421.157Smgorny				sa.sa_handler = thread_concurrent_sig_handler;
29431.157Smgorny			sigemptyset(&sa.sa_mask);
29441.157Smgorny
29451.157Smgorny			for (j = 0;
29461.157Smgorny			    j < __arraycount(thread_concurrent_signals_list);
29471.157Smgorny			    j++)
29481.157Smgorny				FORKEE_ASSERT(sigaction(
29491.157Smgorny				    thread_concurrent_signals_list[j], &sa, NULL)
29501.157Smgorny				    != -1);
29511.157Smgorny		}
29521.157Smgorny
29531.138Smgorny		DPRINTF("Before starting threads from the child\n");
29541.138Smgorny		FORKEE_ASSERT(pthread_barrier_init(
29551.156Smgorny		    &thread_concurrent_barrier, NULL,
29561.161Smgorny		    breakpoint_threads + signal_threads + watchpoint_threads)
29571.161Smgorny		    == 0);
29581.158Smgorny		FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL)
29591.158Smgorny		    == 0);
29601.138Smgorny
29611.156Smgorny		for (i = 0; i < signal_threads; i++) {
29621.156Smgorny			FORKEE_ASSERT(pthread_create(&sig_threads[i], NULL,
29631.158Smgorny			    thread_concurrent_signals_thread,
29641.158Smgorny			    &signal_handle) == 0);
29651.138Smgorny		}
29661.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
29671.160Smgorny			FORKEE_ASSERT(pthread_create(&bp_threads[i], NULL,
29681.160Smgorny			    thread_concurrent_breakpoint_thread, NULL) == 0);
29691.160Smgorny		}
29701.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
29711.161Smgorny			FORKEE_ASSERT(pthread_create(&wp_threads[i], NULL,
29721.161Smgorny			    thread_concurrent_watchpoint_thread, NULL) == 0);
29731.161Smgorny		}
29741.138Smgorny
29751.138Smgorny		DPRINTF("Before joining threads from the child\n");
29761.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
29771.161Smgorny			FORKEE_ASSERT(pthread_join(wp_threads[i], NULL) == 0);
29781.161Smgorny		}
29791.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
29801.160Smgorny			FORKEE_ASSERT(pthread_join(bp_threads[i], NULL) == 0);
29811.160Smgorny		}
29821.156Smgorny		for (i = 0; i < signal_threads; i++) {
29831.156Smgorny			FORKEE_ASSERT(pthread_join(sig_threads[i], NULL) == 0);
29841.138Smgorny		}
29851.138Smgorny
29861.158Smgorny		FORKEE_ASSERT(pthread_key_delete(thread_concurrent_key) == 0);
29871.138Smgorny		FORKEE_ASSERT(pthread_barrier_destroy(
29881.156Smgorny		    &thread_concurrent_barrier) == 0);
29891.138Smgorny
29901.138Smgorny		DPRINTF("Before exiting of the child process\n");
29911.138Smgorny		_exit(exitval);
29921.138Smgorny	}
29931.138Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
29941.138Smgorny
29951.138Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29961.138Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
29971.138Smgorny
29981.138Smgorny	validate_status_stopped(status, sigval);
29991.138Smgorny
30001.159Smgorny	DPRINTF("Set LWP event mask for the child process\n");
30011.159Smgorny	memset(&event, 0, sizeof(event));
30021.159Smgorny	event.pe_set_event |= PTRACE_LWP_CREATE;
30031.159Smgorny	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, sizeof(event))
30041.159Smgorny	    != -1);
30051.159Smgorny
30061.138Smgorny	DPRINTF("Before resuming the child process where it left off\n");
30071.138Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
30081.138Smgorny
30091.138Smgorny	DPRINTF("Before entering signal collection loop\n");
30101.138Smgorny	while (1) {
30111.138Smgorny		ptrace_siginfo_t info;
30121.138Smgorny
30131.138Smgorny		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
30141.138Smgorny		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
30151.138Smgorny		    child);
30161.138Smgorny		if (WIFEXITED(status))
30171.138Smgorny			break;
30181.138Smgorny		/* Note: we use validate_status_stopped() to get nice error
30191.138Smgorny		 * message.  Signal is irrelevant since it won't be reached.
30201.138Smgorny		 */
30211.138Smgorny		else if (!WIFSTOPPED(status))
30221.138Smgorny			validate_status_stopped(status, 0);
30231.138Smgorny
30241.138Smgorny		DPRINTF("Before calling PT_GET_SIGINFO\n");
30251.138Smgorny		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
30261.138Smgorny		    sizeof(info)) != -1);
30271.138Smgorny
30281.138Smgorny		DPRINTF("Received signal %d from LWP %d (wait: %d)\n",
30291.138Smgorny		    info.psi_siginfo.si_signo, info.psi_lwpid,
30301.138Smgorny		    WSTOPSIG(status));
30311.138Smgorny
30321.159Smgorny		ATF_CHECK_EQ_MSG(info.psi_siginfo.si_signo, WSTOPSIG(status),
30331.159Smgorny		    "lwp=%d, WSTOPSIG=%d, psi_siginfo=%d", info.psi_lwpid,
30341.159Smgorny		    WSTOPSIG(status), info.psi_siginfo.si_signo);
30351.159Smgorny
30361.159Smgorny		if (WSTOPSIG(status) != SIGTRAP) {
30371.159Smgorny			int expected_sig =
30381.159Smgorny			    thread_concurrent_signals_list[info.psi_lwpid %
30391.159Smgorny			    __arraycount(thread_concurrent_signals_list)];
30401.159Smgorny			ATF_CHECK_EQ_MSG(WSTOPSIG(status), expected_sig,
30411.159Smgorny				"lwp=%d, expected %d, got %d", info.psi_lwpid,
30421.159Smgorny				expected_sig, WSTOPSIG(status));
30431.138Smgorny
30441.159Smgorny			*FIND_EVENT_COUNT(signal_counts, info.psi_lwpid) += 1;
30451.160Smgorny		} else if (info.psi_siginfo.si_code == TRAP_LWP) {
30461.160Smgorny#if defined(__i386__) || defined(__x86_64__)
30471.160Smgorny			thread_concurrent_lwp_setup(child, info.psi_lwpid);
30481.160Smgorny#endif
30491.159Smgorny		} else {
30501.160Smgorny#if defined(__i386__) || defined(__x86_64__)
30511.160Smgorny			switch (thread_concurrent_handle_sigtrap(child, &info)) {
30521.160Smgorny				case TCSE_UNKNOWN:
30531.160Smgorny					/* already reported inside the function */
30541.160Smgorny					break;
30551.160Smgorny				case TCSE_BREAKPOINT:
30561.160Smgorny					*FIND_EVENT_COUNT(bp_counts,
30571.160Smgorny					    info.psi_lwpid) += 1;
30581.160Smgorny					break;
30591.161Smgorny				case TCSE_WATCHPOINT:
30601.161Smgorny					*FIND_EVENT_COUNT(wp_counts,
30611.161Smgorny					    info.psi_lwpid) += 1;
30621.161Smgorny					break;
30631.160Smgorny			}
30641.160Smgorny#else
30651.160Smgorny			ATF_CHECK_MSG(0, "Unexpected SIGTRAP, si_code=%d\n",
30661.160Smgorny			    info.psi_siginfo.si_code);
30671.160Smgorny#endif
30681.159Smgorny		}
30691.138Smgorny
30701.138Smgorny		DPRINTF("Before resuming the child process\n");
30711.157Smgorny		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
30721.159Smgorny		     signal_handle != TCSH_DISCARD && WSTOPSIG(status) != SIGTRAP
30731.159Smgorny		     ? WSTOPSIG(status) : 0) != -1);
30741.138Smgorny	}
30751.138Smgorny
30761.156Smgorny	for (i = 0; i < signal_threads; i++)
30771.141Skamil		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 1,
30781.141Skamil		    "signal_counts[%d].lec_count=%d; lec_lwp=%d",
30791.141Skamil		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
30801.156Smgorny	for (i = signal_threads; i < THREAD_CONCURRENT_SIGNALS_NUM; i++)
30811.156Smgorny		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 0,
30821.156Smgorny		    "extraneous signal_counts[%d].lec_count=%d; lec_lwp=%d",
30831.156Smgorny		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
30841.138Smgorny
30851.160Smgorny	for (i = 0; i < breakpoint_threads; i++)
30861.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 1,
30871.160Smgorny		    "bp_counts[%d].lec_count=%d; lec_lwp=%d",
30881.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
30891.160Smgorny	for (i = breakpoint_threads; i < THREAD_CONCURRENT_BREAKPOINT_NUM; i++)
30901.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 0,
30911.160Smgorny		    "extraneous bp_counts[%d].lec_count=%d; lec_lwp=%d",
30921.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
30931.160Smgorny
30941.161Smgorny	for (i = 0; i < watchpoint_threads; i++)
30951.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 1,
30961.161Smgorny		    "wp_counts[%d].lec_count=%d; lec_lwp=%d",
30971.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
30981.161Smgorny	for (i = watchpoint_threads; i < THREAD_CONCURRENT_WATCHPOINT_NUM; i++)
30991.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 0,
31001.161Smgorny		    "extraneous wp_counts[%d].lec_count=%d; lec_lwp=%d",
31011.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
31021.161Smgorny
31031.138Smgorny	validate_status_exited(status, exitval);
31041.138Smgorny}
31051.138Smgorny
31061.161Smgorny#define THREAD_CONCURRENT_TEST(test, sig_hdl, bps, sigs, wps, descr)	\
31071.156SmgornyATF_TC(test);								\
31081.156SmgornyATF_TC_HEAD(test, tc)							\
31091.156Smgorny{									\
31101.156Smgorny	atf_tc_set_md_var(tc, "descr", descr);				\
31111.156Smgorny}									\
31121.156Smgorny									\
31131.156SmgornyATF_TC_BODY(test, tc)							\
31141.156Smgorny{									\
31151.161Smgorny	thread_concurrent_test(sig_hdl, bps, sigs, wps);		\
31161.156Smgorny}
31171.156Smgorny
31181.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals, TCSH_DISCARD,
31191.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
31201.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
31211.157Smgorny    "correctly");
31221.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_sig_ign, TCSH_SIG_IGN,
31231.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
31241.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
31251.157Smgorny    "correctly and passed back to SIG_IGN handler");
31261.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_handler, TCSH_HANDLER,
31271.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
31281.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
31291.157Smgorny    "correctly and passed back to a handler function");
31301.156Smgorny
31311.163Skamil#if defined(__i386__) || defined(__x86_64__)
31321.160SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_breakpoints, TCSH_DISCARD,
31331.161Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, 0,
31341.161Smgorny    "Verify that concurrent breakpoints are reported correctly");
31351.161SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_watchpoints, TCSH_DISCARD,
31361.161Smgorny    0, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
31371.160Smgorny    "Verify that concurrent breakpoints are reported correctly");
31381.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp, TCSH_DISCARD,
31391.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
31401.162Smgorny    "Verify that concurrent breakpoints and watchpoints are reported "
31411.162Smgorny    "correctly");
31421.162Smgorny
31431.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig, TCSH_DISCARD,
31441.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
31451.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly");
31461.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_sig_ign, TCSH_SIG_IGN,
31471.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
31481.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
31491.162Smgorny    "and passed back to SIG_IGN handler");
31501.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_handler, TCSH_HANDLER,
31511.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
31521.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
31531.162Smgorny    "and passed back to a handler function");
31541.162Smgorny
31551.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig, TCSH_DISCARD,
31561.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
31571.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly");
31581.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_sig_ign, TCSH_SIG_IGN,
31591.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
31601.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
31611.162Smgorny    "and passed back to SIG_IGN handler");
31621.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_handler, TCSH_HANDLER,
31631.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
31641.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
31651.162Smgorny    "and passed back to a handler function");
31661.162Smgorny
31671.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig, TCSH_DISCARD,
31681.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
31691.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
31701.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
31711.162Smgorny    "correctly");
31721.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_sig_ign, TCSH_SIG_IGN,
31731.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
31741.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
31751.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
31761.162Smgorny    "correctly and passed back to SIG_IGN handler");
31771.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_handler, TCSH_HANDLER,
31781.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
31791.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
31801.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
31811.162Smgorny    "correctly and passed back to a handler function");
31821.163Skamil#endif
31831.160Smgorny
31841.138Smgorny#endif /*defined(TWAIT_HAVE_STATUS)*/
31851.138Smgorny
31861.138Smgorny/// ----------------------------------------------------------------------------
31871.138Smgorny
31881.174Skamil#include "t_ptrace_register_wait.h"
31891.175Skamil#include "t_ptrace_syscall_wait.h"
31901.176Skamil#include "t_ptrace_step_wait.h"
31911.177Skamil#include "t_ptrace_kill_wait.h"
31921.178Skamil#include "t_ptrace_bytetransfer_wait.h"
31931.179Skamil#include "t_ptrace_clone_wait.h"
31941.180Skamil#include "t_ptrace_fork_wait.h"
31951.181Skamil#include "t_ptrace_signal_wait.h"
31961.174Skamil
31971.174Skamil/// ----------------------------------------------------------------------------
31981.174Skamil
31991.1Skamil#include "t_ptrace_amd64_wait.h"
32001.1Skamil#include "t_ptrace_i386_wait.h"
32011.1Skamil#include "t_ptrace_x86_wait.h"
32021.1Skamil
32031.165Skamil/// ----------------------------------------------------------------------------
32041.165Skamil
32051.165Skamil#else
32061.165SkamilATF_TC(dummy);
32071.165SkamilATF_TC_HEAD(dummy, tc)
32081.165Skamil{
32091.165Skamil	atf_tc_set_md_var(tc, "descr", "A dummy test");
32101.165Skamil}
32111.165Skamil
32121.165SkamilATF_TC_BODY(dummy, tc)
32131.165Skamil{
32141.165Skamil
32151.165Skamil	// Dummy, skipped
32161.165Skamil	// The ATF framework requires at least a single defined test.
32171.165Skamil}
32181.165Skamil#endif
32191.165Skamil
32201.1SkamilATF_TP_ADD_TCS(tp)
32211.1Skamil{
32221.1Skamil	setvbuf(stdout, NULL, _IONBF, 0);
32231.1Skamil	setvbuf(stderr, NULL, _IONBF, 0);
32241.33Skamil
32251.165Skamil#ifdef ENABLE_TESTS
32261.37Skamil	ATF_TP_ADD_TC(tp, traceme_pid1_parent);
32271.37Skamil
32281.43Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_exec);
32291.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_exec);
32301.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_exec);
32311.43Skamil
32321.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sees_terminaton_before_the_parent);
32331.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sysctl_lookup_without_duplicates);
32341.61Skre	ATF_TP_ADD_TC_HAVE_PID(tp,
32351.61Skre		unrelated_tracer_sees_terminaton_before_the_parent);
32361.67Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_attach_to_unrelated_stopped_process);
32371.51Skamil
32381.51Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_child);
32391.66Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_stopped_child);
32401.51Skamil
32411.51Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_parent);
32421.65Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_stopped_parent);
32431.51Skamil
32441.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
32451.51Skamil		tracee_sees_its_original_parent_getppid);
32461.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
32471.51Skamil		tracee_sees_its_original_parent_sysctl_kinfo_proc2);
32481.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
32491.51Skamil		tracee_sees_its_original_parent_procfs_status);
32501.1Skamil
32511.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_empty);
32521.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_fork);
32531.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork);
32541.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork_done);
32551.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_create);
32561.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_exit);
32571.125Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_posix_spawn);
32581.1Skamil
32591.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8);
32601.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16);
32611.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32);
32621.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64);
32631.54Skamil
32641.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8);
32651.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16);
32661.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32);
32671.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64);
32681.54Skamil
32691.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8);
32701.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16);
32711.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32);
32721.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64);
32731.54Skamil
32741.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8);
32751.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16);
32761.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32);
32771.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64);
32781.54Skamil
32791.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d);
32801.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i);
32811.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d);
32821.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i);
32831.54Skamil
32841.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8_text);
32851.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16_text);
32861.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32_text);
32871.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64_text);
32881.54Skamil
32891.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8_text);
32901.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16_text);
32911.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32_text);
32921.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64_text);
32931.54Skamil
32941.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8_text);
32951.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16_text);
32961.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32_text);
32971.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64_text);
32981.54Skamil
32991.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8_text);
33001.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16_text);
33011.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32_text);
33021.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64_text);
33031.54Skamil
33041.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d_text);
33051.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i_text);
33061.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d_text);
33071.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i_text);
33081.1Skamil
33091.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_auxv);
33101.1Skamil
33111.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_i);
33121.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_d);
33131.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_i);
33141.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_d);
33151.101Skamil
33161.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_i);
33171.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_d);
33181.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_i);
33191.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_d);
33201.101Skamil
33211.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_auxv);
33221.101Skamil
33231.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_i);
33241.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_d);
33251.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_i);
33261.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_d);
33271.115Skamil
33281.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_i);
33291.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_d);
33301.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_i);
33311.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_d);
33321.115Skamil
33331.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0);
33341.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1);
33351.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2);
33361.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3);
33371.77Skamil
33381.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus);
33391.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus);
33401.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus);
33411.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus);
33421.143Skamil
33431.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_sigmask);
33441.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_sigmask);
33451.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_sigmask);
33461.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_sigmask);
33471.143Skamil
33481.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_name);
33491.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_name);
33501.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_name);
33511.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_name);
33521.143Skamil
33531.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_private);
33541.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_private);
33551.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_private);
33561.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_private);
33571.143Skamil
33581.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0);
33591.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1);
33601.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2);
33611.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3);
33621.143Skamil
33631.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_sigmask);
33641.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_sigmask);
33651.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_sigmask);
33661.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_sigmask);
33671.143Skamil
33681.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_name);
33691.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_name);
33701.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_name);
33711.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_name);
33721.143Skamil
33731.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_private);
33741.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_private);
33751.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_private);
33761.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_private);
33771.143Skamil
33781.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo0);
33791.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo1);
33801.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo2);
33811.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo3);
33821.1Skamil
33831.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_unmodified);
33841.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_faked);
33851.79Skamil
33861.82Skamil	ATF_TP_ADD_TC(tp, traceme_exec);
33871.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_exec);
33881.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_exec);
33891.1Skamil
33901.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_nolwpevents);
33911.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit);
33921.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate);
33931.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit);
33941.1Skamil
33951.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit_masked_sigtrap);
33961.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_masked_sigtrap);
33971.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit_masked_sigtrap);
33981.153Skamil
33991.151Skamil	ATF_TP_ADD_TC(tp, threads_and_exec);
34001.151Skamil
34011.154Skamil	ATF_TP_ADD_TC(tp, suspend_no_deadlock);
34021.1Skamil
34031.155Skamil	ATF_TP_ADD_TC(tp, resume);
34041.1Skamil
34051.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_continue);
34061.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall);
34071.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach);
34081.122Skamil
34091.130Smgorny	ATF_TP_ADD_TC(tp, core_dump_procinfo);
34101.130Smgorny
34111.138Smgorny#if defined(TWAIT_HAVE_STATUS)
34121.138Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals);
34131.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_sig_ign);
34141.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_handler);
34151.160Smgorny#if defined(__i386__) || defined(__x86_64__)
34161.160Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_breakpoints);
34171.161Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_watchpoints);
34181.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp);
34191.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig);
34201.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_sig_ign);
34211.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_handler);
34221.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig);
34231.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_sig_ign);
34241.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_handler);
34251.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig);
34261.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_sig_ign);
34271.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_handler);
34281.160Smgorny#endif
34291.138Smgorny#endif
34301.138Smgorny
34311.174Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_REGISTER();
34321.175Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_SYSCALL();
34331.176Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_STEP();
34341.177Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_KILL();
34351.178Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_BYTETRANSFER();
34361.179Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_CLONE();
34371.180Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_FORK();
34381.181Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_SIGNAL();
34391.174Skamil
34401.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
34411.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_I386();
34421.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_X86();
34431.1Skamil
34441.165Skamil#else
34451.165Skamil	ATF_TP_ADD_TC(tp, dummy);
34461.165Skamil#endif
34471.165Skamil
34481.1Skamil	return atf_no_error();
34491.1Skamil}
3450