t_ptrace_wait.c revision 1.183
11.183Skamil/*	$NetBSD: t_ptrace_wait.c,v 1.183 2020/05/05 00:01:14 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.183Skamil__RCSID("$NetBSD: t_ptrace_wait.c,v 1.183 2020/05/05 00:01:14 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.180Skamilstatic int lwpinfo_thread_sigmask[] = {SIGXCPU, SIGPIPE, SIGALRM, SIGURG};
9311.180Skamil
9321.180Skamilstatic pthread_mutex_t lwpinfo_thread_mtx = PTHREAD_MUTEX_INITIALIZER;
9331.180Skamilstatic pthread_cond_t lwpinfo_thread_cnd = PTHREAD_COND_INITIALIZER;
9341.180Skamilstatic volatile size_t lwpinfo_thread_done;
9351.180Skamil
9361.180Skamilstatic void *
9371.180Skamillwpinfo_thread(void *arg)
9381.180Skamil{
9391.180Skamil	sigset_t s;
9401.180Skamil	volatile void **tcb;
9411.180Skamil
9421.180Skamil	tcb = (volatile void **)arg;
9431.180Skamil
9441.180Skamil	*tcb = _lwp_getprivate();
9451.180Skamil	DPRINTF("Storing tcb[] = %p from thread %d\n", *tcb, _lwp_self());
9461.180Skamil
9471.180Skamil	pthread_setname_np(pthread_self(), "thread %d",
9481.180Skamil	    (void *)(intptr_t)_lwp_self());
9491.180Skamil
9501.180Skamil	sigemptyset(&s);
9511.180Skamil	pthread_mutex_lock(&lwpinfo_thread_mtx);
9521.180Skamil	sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
9531.180Skamil	lwpinfo_thread_done++;
9541.180Skamil	pthread_sigmask(SIG_BLOCK, &s, NULL);
9551.180Skamil	pthread_cond_signal(&lwpinfo_thread_cnd);
9561.180Skamil	pthread_mutex_unlock(&lwpinfo_thread_mtx);
9571.180Skamil
9581.180Skamil	return infinite_thread(NULL);
9591.180Skamil}
9601.180Skamil
9611.28Skamilstatic void
9621.180Skamiltraceme_lwpinfo(const size_t threads, const char *iter)
9631.1Skamil{
9641.1Skamil	const int sigval = SIGSTOP;
9651.180Skamil	const int sigval2 = SIGINT;
9661.180Skamil	pid_t child, wpid;
9671.1Skamil#if defined(TWAIT_HAVE_STATUS)
9681.1Skamil	int status;
9691.1Skamil#endif
9701.180Skamil	struct ptrace_lwpinfo lwp = {0, 0};
9711.180Skamil	struct ptrace_lwpstatus lwpstatus = {0};
9721.180Skamil	struct ptrace_siginfo info;
9731.180Skamil	void *private;
9741.180Skamil	char *name;
9751.180Skamil	char namebuf[PL_LNAMELEN];
9761.180Skamil	volatile void *tcb[4];
9771.180Skamil	bool found;
9781.180Skamil	sigset_t s;
9791.180Skamil
9801.180Skamil	/* Maximum number of supported threads in this test */
9811.180Skamil	pthread_t t[__arraycount(tcb) - 1];
9821.180Skamil	size_t n, m;
9831.180Skamil	int rv;
9841.180Skamil	size_t bytes_read;
9851.180Skamil
9861.180Skamil	struct ptrace_io_desc io;
9871.180Skamil	sigset_t sigmask;
9881.1Skamil
9891.180Skamil	ATF_REQUIRE(__arraycount(t) >= threads);
9901.180Skamil	memset(tcb, 0, sizeof(tcb));
9911.124Skamil
9921.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
9931.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
9941.1Skamil	if (child == 0) {
9951.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
9961.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
9971.1Skamil
9981.180Skamil		tcb[0] = _lwp_getprivate();
9991.180Skamil		DPRINTF("Storing tcb[0] = %p\n", tcb[0]);
10001.180Skamil
10011.180Skamil		pthread_setname_np(pthread_self(), "thread %d",
10021.180Skamil		    (void *)(intptr_t)_lwp_self());
10031.180Skamil
10041.180Skamil		sigemptyset(&s);
10051.180Skamil		sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
10061.180Skamil		pthread_sigmask(SIG_BLOCK, &s, NULL);
10071.180Skamil
10081.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
10091.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
10101.1Skamil
10111.180Skamil		for (n = 0; n < threads; n++) {
10121.180Skamil			rv = pthread_create(&t[n], NULL, lwpinfo_thread,
10131.180Skamil			    &tcb[n + 1]);
10141.180Skamil			FORKEE_ASSERT(rv == 0);
10151.180Skamil		}
10161.1Skamil
10171.180Skamil		pthread_mutex_lock(&lwpinfo_thread_mtx);
10181.180Skamil		while (lwpinfo_thread_done < threads) {
10191.180Skamil			pthread_cond_wait(&lwpinfo_thread_cnd,
10201.180Skamil			    &lwpinfo_thread_mtx);
10211.124Skamil		}
10221.180Skamil		pthread_mutex_unlock(&lwpinfo_thread_mtx);
10231.1Skamil
10241.180Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval2));
10251.180Skamil		FORKEE_ASSERT(raise(sigval2) == 0);
10261.1Skamil
10271.180Skamil		/* NOTREACHED */
10281.180Skamil		FORKEE_ASSERTX(0 && "Not reached");
10291.1Skamil	}
10301.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
10311.1Skamil
10321.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10331.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
10341.1Skamil
10351.1Skamil	validate_status_stopped(status, sigval);
10361.1Skamil
10371.180Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
10381.180Skamil	SYSCALL_REQUIRE(
10391.180Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
10401.1Skamil
10411.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
10421.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
10431.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
10441.180Skamil	    info.psi_siginfo.si_errno);
10451.1Skamil
10461.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
10471.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
10481.1Skamil
10491.180Skamil	if (strstr(iter, "LWPINFO") != NULL) {
10501.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
10511.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
10521.180Skamil		    != -1);
10531.1Skamil
10541.180Skamil		DPRINTF("Assert that there exists a single thread only\n");
10551.180Skamil		ATF_REQUIRE(lwp.pl_lwpid > 0);
10561.1Skamil
10571.180Skamil		DPRINTF("Assert that lwp thread %d received event "
10581.180Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
10591.180Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
10601.1Skamil
10611.180Skamil		if (strstr(iter, "LWPSTATUS") != NULL) {
10621.180Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPSTATUS "
10631.180Skamil			    "for child\n");
10641.180Skamil			lwpstatus.pl_lwpid = lwp.pl_lwpid;
10651.180Skamil			SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child, &lwpstatus,
10661.180Skamil			    sizeof(lwpstatus)) != -1);
10671.30Skamil		}
10681.30Skamil
10691.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
10701.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
10711.180Skamil		    != -1);
10721.29Skamil
10731.180Skamil		DPRINTF("Assert that there exists a single thread only\n");
10741.180Skamil		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
10751.180Skamil	} else {
10761.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
10771.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
10781.180Skamil		    sizeof(lwpstatus)) != -1);
10791.29Skamil
10801.180Skamil		DPRINTF("Assert that there exists a single thread only %d\n", lwpstatus.pl_lwpid);
10811.180Skamil		ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
10821.30Skamil
10831.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
10841.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
10851.180Skamil		    sizeof(lwpstatus)) != -1);
10861.30Skamil
10871.180Skamil		DPRINTF("Assert that there exists a single thread only\n");
10881.180Skamil		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
10891.30Skamil	}
10901.29Skamil
10911.13Schristos	DPRINTF("Before resuming the child process where it left off and "
10921.1Skamil	    "without signal to be sent\n");
10931.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
10941.1Skamil
10951.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10961.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
10971.1Skamil
10981.180Skamil	validate_status_stopped(status, sigval2);
10991.180Skamil
11001.180Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
11011.180Skamil	SYSCALL_REQUIRE(
11021.180Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
11031.180Skamil
11041.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
11051.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
11061.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
11071.180Skamil	    info.psi_siginfo.si_errno);
11081.1Skamil
11091.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval2);
11101.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
11111.28Skamil
11121.180Skamil	memset(&lwp, 0, sizeof(lwp));
11131.180Skamil	memset(&lwpstatus, 0, sizeof(lwpstatus));
11141.32Skamil
11151.180Skamil	memset(&io, 0, sizeof(io));
11161.1Skamil
11171.180Skamil	bytes_read = 0;
11181.180Skamil	io.piod_op = PIOD_READ_D;
11191.180Skamil	io.piod_len = sizeof(tcb);
11201.125Skamil
11211.180Skamil	do {
11221.180Skamil		io.piod_addr = (char *)&tcb + bytes_read;
11231.180Skamil		io.piod_offs = io.piod_addr;
11241.124Skamil
11251.180Skamil		rv = ptrace(PT_IO, child, &io, sizeof(io));
11261.180Skamil		ATF_REQUIRE(rv != -1 && io.piod_len != 0);
11271.31Skamil
11281.180Skamil		bytes_read += io.piod_len;
11291.180Skamil		io.piod_len = sizeof(tcb) - bytes_read;
11301.180Skamil	} while (bytes_read < sizeof(tcb));
11311.149Skamil
11321.180Skamil	for (n = 0; n <= threads; n++) {
11331.180Skamil		if (strstr(iter, "LWPINFO") != NULL) {
11341.180Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
11351.180Skamil			    "child\n");
11361.180Skamil			SYSCALL_REQUIRE(
11371.180Skamil			    ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
11381.180Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
11391.149Skamil
11401.180Skamil			DPRINTF("Assert that the thread exists\n");
11411.180Skamil			ATF_REQUIRE(lwp.pl_lwpid > 0);
11421.149Skamil
11431.180Skamil			DPRINTF("Assert that lwp thread %d received expected "
11441.180Skamil			    "event\n", lwp.pl_lwpid);
11451.180Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
11461.180Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
11471.180Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
11481.149Skamil
11491.180Skamil			if (strstr(iter, "LWPSTATUS") != NULL) {
11501.180Skamil				DPRINTF("Before calling ptrace(2) with "
11511.180Skamil				    "PT_LWPSTATUS for child\n");
11521.180Skamil				lwpstatus.pl_lwpid = lwp.pl_lwpid;
11531.180Skamil				SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child,
11541.180Skamil				    &lwpstatus, sizeof(lwpstatus)) != -1);
11551.149Skamil
11561.180Skamil				goto check_lwpstatus;
11571.180Skamil			}
11581.149Skamil		} else {
11591.180Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for "
11601.180Skamil			    "child\n");
11611.180Skamil			SYSCALL_REQUIRE(
11621.180Skamil			    ptrace(PT_LWPNEXT, child, &lwpstatus,
11631.180Skamil			    sizeof(lwpstatus)) != -1);
11641.180Skamil			DPRINTF("LWP=%d\n", lwpstatus.pl_lwpid);
11651.149Skamil
11661.180Skamil			DPRINTF("Assert that the thread exists\n");
11671.180Skamil			ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
11681.149Skamil
11691.180Skamil		check_lwpstatus:
11701.149Skamil
11711.180Skamil			if (strstr(iter, "pl_sigmask") != NULL) {
11721.180Skamil				sigmask = lwpstatus.pl_sigmask;
11731.149Skamil
11741.180Skamil				DPRINTF("Retrieved sigmask: "
11751.180Skamil				    "%02x%02x%02x%02x\n",
11761.180Skamil				    sigmask.__bits[0], sigmask.__bits[1],
11771.180Skamil				    sigmask.__bits[2], sigmask.__bits[3]);
11781.149Skamil
11791.180Skamil				found = false;
11801.180Skamil				for (m = 0;
11811.180Skamil				     m < __arraycount(lwpinfo_thread_sigmask);
11821.180Skamil				     m++) {
11831.180Skamil					if (sigismember(&sigmask,
11841.180Skamil					    lwpinfo_thread_sigmask[m])) {
11851.180Skamil						found = true;
11861.180Skamil						lwpinfo_thread_sigmask[m] = 0;
11871.180Skamil						break;
11881.180Skamil					}
11891.180Skamil				}
11901.180Skamil				ATF_REQUIRE(found == true);
11911.180Skamil			} else if (strstr(iter, "pl_name") != NULL) {
11921.180Skamil				name = lwpstatus.pl_name;
11931.149Skamil
11941.180Skamil				DPRINTF("Retrieved thread name: "
11951.180Skamil				    "%s\n", name);
11961.149Skamil
11971.180Skamil				snprintf(namebuf, sizeof namebuf, "thread %d",
11981.180Skamil				    lwpstatus.pl_lwpid);
11991.149Skamil
12001.180Skamil				ATF_REQUIRE(strcmp(name, namebuf) == 0);
12011.180Skamil			} else if (strstr(iter, "pl_private") != NULL) {
12021.180Skamil				private = lwpstatus.pl_private;
12031.149Skamil
12041.180Skamil				DPRINTF("Retrieved thread private pointer: "
12051.180Skamil				    "%p\n", private);
12061.149Skamil
12071.180Skamil				found = false;
12081.180Skamil				for (m = 0; m < __arraycount(tcb); m++) {
12091.180Skamil					DPRINTF("Comparing %p and %p\n",
12101.180Skamil					    private, tcb[m]);
12111.180Skamil					if (private == tcb[m]) {
12121.180Skamil						found = true;
12131.180Skamil						break;
12141.180Skamil					}
12151.180Skamil				}
12161.180Skamil				ATF_REQUIRE(found == true);
12171.180Skamil			}
12181.180Skamil		}
12191.180Skamil	}
12201.149Skamil
12211.180Skamil	if (strstr(iter, "LWPINFO") != NULL) {
12221.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
12231.180Skamil		    "child\n");
12241.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
12251.180Skamil		    != -1);
12261.180Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
12271.149Skamil
12281.180Skamil		DPRINTF("Assert that there are no more threads\n");
12291.180Skamil		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
12301.180Skamil	} else {
12311.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
12321.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
12331.180Skamil		    sizeof(lwpstatus)) != -1);
12341.149Skamil
12351.180Skamil		DPRINTF("Assert that there exists a single thread only\n");
12361.180Skamil		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
12371.180Skamil	}
12381.149Skamil
12391.180Skamil	DPRINTF("Before resuming the child process where it left off and "
12401.180Skamil	    "without signal to be sent\n");
12411.180Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, SIGKILL) != -1);
12421.149Skamil
12431.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12441.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
12451.149Skamil
12461.180Skamil	validate_status_signaled(status, SIGKILL, 0);
12471.149Skamil
12481.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12491.180Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
12501.180Skamil}
12511.149Skamil
12521.180Skamil#define TRACEME_LWPINFO(test, threads, iter)				\
12531.180SkamilATF_TC(test);								\
12541.180SkamilATF_TC_HEAD(test, tc)							\
12551.180Skamil{									\
12561.180Skamil	atf_tc_set_md_var(tc, "descr",					\
12571.180Skamil	    "Verify " iter " with the child with " #threads		\
12581.180Skamil	    " spawned extra threads");					\
12591.180Skamil}									\
12601.180Skamil									\
12611.180SkamilATF_TC_BODY(test, tc)							\
12621.180Skamil{									\
12631.180Skamil									\
12641.180Skamil	traceme_lwpinfo(threads, iter);					\
12651.180Skamil}
12661.149Skamil
12671.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0, 0, "LWPINFO")
12681.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1, 1, "LWPINFO")
12691.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2, 2, "LWPINFO")
12701.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3, 3, "LWPINFO")
12711.149Skamil
12721.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus, 0, "LWPINFO+LWPSTATUS")
12731.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus, 1, "LWPINFO+LWPSTATUS")
12741.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus, 2, "LWPINFO+LWPSTATUS")
12751.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus, 3, "LWPINFO+LWPSTATUS")
12761.149Skamil
12771.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_sigmask, 0,
12781.180Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
12791.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_sigmask, 1,
12801.180Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
12811.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_sigmask, 2,
12821.180Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
12831.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_sigmask, 3,
12841.180Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
12851.149Skamil
12861.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_name, 0,
12871.180Skamil    "LWPINFO+LWPSTATUS+pl_name")
12881.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_name, 1,
12891.180Skamil    "LWPINFO+LWPSTATUS+pl_name")
12901.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_name, 2,
12911.180Skamil    "LWPINFO+LWPSTATUS+pl_name")
12921.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_name, 3,
12931.180Skamil    "LWPINFO+LWPSTATUS+pl_name")
12941.149Skamil
12951.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_private, 0,
12961.180Skamil    "LWPINFO+LWPSTATUS+pl_private")
12971.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_private, 1,
12981.180Skamil    "LWPINFO+LWPSTATUS+pl_private")
12991.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_private, 2,
13001.180Skamil    "LWPINFO+LWPSTATUS+pl_private")
13011.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_private, 3,
13021.180Skamil    "LWPINFO+LWPSTATUS+pl_private")
13031.149Skamil
13041.180SkamilTRACEME_LWPINFO(traceme_lwpnext0, 0, "LWPNEXT")
13051.180SkamilTRACEME_LWPINFO(traceme_lwpnext1, 1, "LWPNEXT")
13061.180SkamilTRACEME_LWPINFO(traceme_lwpnext2, 2, "LWPNEXT")
13071.180SkamilTRACEME_LWPINFO(traceme_lwpnext3, 3, "LWPNEXT")
13081.149Skamil
13091.180SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_sigmask, 0, "LWPNEXT+pl_sigmask")
13101.180SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_sigmask, 1, "LWPNEXT+pl_sigmask")
13111.180SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_sigmask, 2, "LWPNEXT+pl_sigmask")
13121.180SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_sigmask, 3, "LWPNEXT+pl_sigmask")
13131.149Skamil
13141.180SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_name, 0, "LWPNEXT+pl_name")
13151.180SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_name, 1, "LWPNEXT+pl_name")
13161.180SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_name, 2, "LWPNEXT+pl_name")
13171.180SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_name, 3, "LWPNEXT+pl_name")
13181.149Skamil
13191.180SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_private, 0, "LWPNEXT+pl_private")
13201.180SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_private, 1, "LWPNEXT+pl_private")
13211.180SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_private, 2, "LWPNEXT+pl_private")
13221.180SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_private, 3, "LWPNEXT+pl_private")
13231.149Skamil
13241.180Skamil/// ----------------------------------------------------------------------------
13251.149Skamil
13261.180Skamil#if defined(TWAIT_HAVE_PID)
13271.180Skamilstatic void
13281.180Skamilattach_lwpinfo(const int threads)
13291.180Skamil{
13301.180Skamil	const int sigval = SIGINT;
13311.180Skamil	struct msg_fds parent_tracee, parent_tracer;
13321.180Skamil	const int exitval_tracer = 10;
13331.180Skamil	pid_t tracee, tracer, wpid;
13341.180Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
13351.180Skamil#if defined(TWAIT_HAVE_STATUS)
13361.180Skamil	int status;
13371.180Skamil#endif
13381.180Skamil	struct ptrace_lwpinfo lwp = {0, 0};
13391.180Skamil	struct ptrace_siginfo info;
13401.149Skamil
13411.180Skamil	/* Maximum number of supported threads in this test */
13421.180Skamil	pthread_t t[3];
13431.180Skamil	int n, rv;
13441.149Skamil
13451.180Skamil	DPRINTF("Spawn tracee\n");
13461.180Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
13471.180Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
13481.180Skamil	tracee = atf_utils_fork();
13491.180Skamil	if (tracee == 0) {
13501.180Skamil		/* Wait for message from the parent */
13511.180Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
13521.149Skamil
13531.180Skamil		CHILD_FROM_PARENT("spawn threads", parent_tracee, msg);
13541.149Skamil
13551.180Skamil		for (n = 0; n < threads; n++) {
13561.180Skamil			rv = pthread_create(&t[n], NULL, infinite_thread, NULL);
13571.180Skamil			FORKEE_ASSERT(rv == 0);
13581.149Skamil		}
13591.149Skamil
13601.180Skamil		CHILD_TO_PARENT("tracee exit", parent_tracee, msg);
13611.149Skamil
13621.180Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
13631.180Skamil		FORKEE_ASSERT(raise(sigval) == 0);
13641.149Skamil
13651.180Skamil		/* NOTREACHED */
13661.180Skamil		FORKEE_ASSERTX(0 && "Not reached");
13671.150Skamil	}
13681.180Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
13691.150Skamil
13701.150Skamil	DPRINTF("Spawn debugger\n");
13711.150Skamil	tracer = atf_utils_fork();
13721.150Skamil	if (tracer == 0) {
13731.180Skamil		/* No IPC to communicate with the child */
13741.150Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
13751.150Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
13761.150Skamil
13771.150Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
13781.150Skamil		FORKEE_REQUIRE_SUCCESS(
13791.150Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
13801.150Skamil
13811.150Skamil		forkee_status_stopped(status, SIGSTOP);
13821.150Skamil
13831.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
13841.180Skamil		    "tracee");
13851.180Skamil		FORKEE_ASSERT(
13861.150Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
13871.150Skamil
13881.150Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
13891.150Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
13901.180Skamil		    "si_errno=%#x\n",
13911.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
13921.180Skamil		    info.psi_siginfo.si_errno);
13931.150Skamil
13941.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
13951.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
13961.150Skamil
13971.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
13981.180Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
13991.180Skamil		    != -1);
14001.180Skamil
14011.180Skamil		DPRINTF("Assert that there exists a thread\n");
14021.180Skamil		FORKEE_ASSERTX(lwp.pl_lwpid > 0);
14031.180Skamil
14041.180Skamil		DPRINTF("Assert that lwp thread %d received event "
14051.180Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
14061.180Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
14071.180Skamil
14081.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
14091.180Skamil		    "tracee\n");
14101.180Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
14111.180Skamil		    != -1);
14121.180Skamil
14131.180Skamil		DPRINTF("Assert that there are no more lwp threads in "
14141.180Skamil		    "tracee\n");
14151.180Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
14161.180Skamil
14171.150Skamil		/* Resume tracee with PT_CONTINUE */
14181.150Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
14191.150Skamil
14201.150Skamil		/* Inform parent that tracer has attached to tracee */
14211.150Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
14221.150Skamil
14231.180Skamil		/* Wait for parent */
14241.180Skamil		CHILD_FROM_PARENT("tracer wait", parent_tracer, msg);
14251.150Skamil
14261.180Skamil		/* Wait for tracee and assert that it raised a signal */
14271.150Skamil		FORKEE_REQUIRE_SUCCESS(
14281.150Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
14291.150Skamil
14301.180Skamil		forkee_status_stopped(status, SIGINT);
14311.150Skamil
14321.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
14331.180Skamil		    "child");
14341.180Skamil		FORKEE_ASSERT(
14351.150Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
14361.150Skamil
14371.150Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
14381.150Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
14391.180Skamil		    "si_errno=%#x\n",
14401.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
14411.180Skamil		    info.psi_siginfo.si_errno);
14421.150Skamil
14431.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
14441.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
14451.150Skamil
14461.180Skamil		memset(&lwp, 0, sizeof(lwp));
14471.150Skamil
14481.180Skamil		for (n = 0; n <= threads; n++) {
14491.180Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
14501.180Skamil			    "child\n");
14511.180Skamil			FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp,
14521.180Skamil			    sizeof(lwp)) != -1);
14531.180Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
14541.150Skamil
14551.180Skamil			DPRINTF("Assert that the thread exists\n");
14561.180Skamil			FORKEE_ASSERT(lwp.pl_lwpid > 0);
14571.150Skamil
14581.180Skamil			DPRINTF("Assert that lwp thread %d received expected "
14591.180Skamil			    "event\n", lwp.pl_lwpid);
14601.180Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
14611.180Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
14621.180Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
14631.180Skamil		}
14641.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
14651.180Skamil		    "tracee\n");
14661.180Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
14671.180Skamil		    != -1);
14681.180Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
14691.150Skamil
14701.180Skamil		DPRINTF("Assert that there are no more threads\n");
14711.180Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
14721.150Skamil
14731.180Skamil		DPRINTF("Before resuming the child process where it left off "
14741.150Skamil		    "and without signal to be sent\n");
14751.180Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, SIGKILL)
14761.180Skamil		    != -1);
14771.150Skamil
14781.180Skamil		/* Wait for tracee and assert that it exited */
14791.180Skamil		FORKEE_REQUIRE_SUCCESS(
14801.180Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
14811.150Skamil
14821.180Skamil		forkee_status_signaled(status, SIGKILL, 0);
14831.150Skamil
14841.150Skamil		DPRINTF("Before exiting of the tracer process\n");
14851.180Skamil		_exit(exitval_tracer);
14861.97Skamil	}
14871.97Skamil
14881.180Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
14891.180Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
14901.97Skamil
14911.180Skamil	DPRINTF("Resume the tracee and spawn threads\n");
14921.180Skamil	PARENT_TO_CHILD("spawn threads", parent_tracee, msg);
14931.97Skamil
14941.180Skamil	DPRINTF("Resume the tracee and let it exit\n");
14951.180Skamil	PARENT_FROM_CHILD("tracee exit", parent_tracee, msg);
14961.97Skamil
14971.180Skamil	DPRINTF("Resume the tracer and let it detect multiple threads\n");
14981.180Skamil	PARENT_TO_CHILD("tracer wait", parent_tracer, msg);
14991.1Skamil
15001.180Skamil	DPRINTF("Wait for tracer to finish its job and exit - calling %s()\n",
15011.180Skamil	    TWAIT_FNAME);
15021.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
15031.180Skamil	    tracer);
15041.1Skamil
15051.180Skamil	validate_status_exited(status, exitval_tracer);
15061.1Skamil
15071.180Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
15081.180Skamil	    TWAIT_FNAME);
15091.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
15101.180Skamil	    tracee);
15111.1Skamil
15121.180Skamil	validate_status_signaled(status, SIGKILL, 0);
15131.1Skamil
15141.180Skamil	msg_close(&parent_tracer);
15151.180Skamil	msg_close(&parent_tracee);
15161.1Skamil}
15171.1Skamil
15181.180Skamil#define ATTACH_LWPINFO(test, threads)					\
15191.97SkamilATF_TC(test);								\
15201.97SkamilATF_TC_HEAD(test, tc)							\
15211.97Skamil{									\
15221.180Skamil	atf_tc_set_md_var(tc, "descr",					\
15231.180Skamil	    "Verify LWPINFO with the child with " #threads		\
15241.180Skamil	    " spawned extra threads (tracer is not the original "	\
15251.180Skamil	    "parent)");							\
15261.97Skamil}									\
15271.97Skamil									\
15281.97SkamilATF_TC_BODY(test, tc)							\
15291.97Skamil{									\
15301.97Skamil									\
15311.180Skamil	attach_lwpinfo(threads);					\
15321.97Skamil}
15331.97Skamil
15341.180SkamilATTACH_LWPINFO(attach_lwpinfo0, 0)
15351.180SkamilATTACH_LWPINFO(attach_lwpinfo1, 1)
15361.180SkamilATTACH_LWPINFO(attach_lwpinfo2, 2)
15371.180SkamilATTACH_LWPINFO(attach_lwpinfo3, 3)
15381.180Skamil#endif
15391.97Skamil
15401.82Skamil/// ----------------------------------------------------------------------------
15411.82Skamil
15421.83Skamilstatic void
15431.180Skamilptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c), int *signal_caught)
15441.1Skamil{
15451.180Skamil	const int exitval = 5;
15461.180Skamil	const int sigval = SIGINT;
15471.180Skamil	const int sigfaked = SIGTRAP;
15481.180Skamil	const int sicodefaked = TRAP_BRKPT;
15491.1Skamil	pid_t child, wpid;
15501.180Skamil	struct sigaction sa;
15511.1Skamil#if defined(TWAIT_HAVE_STATUS)
15521.1Skamil	int status;
15531.1Skamil#endif
15541.83Skamil	struct ptrace_siginfo info;
15551.180Skamil	memset(&info, 0, sizeof(info));
15561.83Skamil
15571.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
15581.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
15591.1Skamil	if (child == 0) {
15601.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
15611.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
15621.1Skamil
15631.180Skamil		sa.sa_sigaction = sah;
15641.180Skamil		sa.sa_flags = SA_SIGINFO;
15651.180Skamil		sigemptyset(&sa.sa_mask);
15661.180Skamil
15671.180Skamil		FORKEE_ASSERT(sigaction(faked ? sigfaked : sigval, &sa, NULL)
15681.180Skamil		    != -1);
15691.153Skamil
15701.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
15711.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
15721.1Skamil
15731.180Skamil		FORKEE_ASSERT_EQ(*signal_caught, 1);
15741.1Skamil
15751.180Skamil		DPRINTF("Before exiting of the child process\n");
15761.180Skamil		_exit(exitval);
15771.1Skamil	}
15781.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
15791.1Skamil
15801.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15811.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
15821.1Skamil
15831.1Skamil	validate_status_stopped(status, sigval);
15841.1Skamil
15851.83Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
15861.83Skamil	SYSCALL_REQUIRE(
15871.83Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
15881.1Skamil
15891.83Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
15901.83Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
15911.83Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
15921.83Skamil	    info.psi_siginfo.si_errno);
15931.1Skamil
15941.180Skamil	if (faked) {
15951.180Skamil		DPRINTF("Before setting new faked signal to signo=%d "
15961.180Skamil		    "si_code=%d\n", sigfaked, sicodefaked);
15971.180Skamil		info.psi_siginfo.si_signo = sigfaked;
15981.180Skamil		info.psi_siginfo.si_code = sicodefaked;
15991.83Skamil	}
16001.1Skamil
16011.180Skamil	DPRINTF("Before calling ptrace(2) with PT_SET_SIGINFO for child\n");
16021.180Skamil	SYSCALL_REQUIRE(
16031.180Skamil	    ptrace(PT_SET_SIGINFO, child, &info, sizeof(info)) != -1);
16041.1Skamil
16051.180Skamil	if (faked) {
16061.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
16071.83Skamil		    "child\n");
16081.180Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
16091.180Skamil		    sizeof(info)) != -1);
16101.1Skamil
16111.180Skamil		DPRINTF("Before checking siginfo_t\n");
16121.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigfaked);
16131.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, sicodefaked);
16141.83Skamil	}
16151.1Skamil
16161.180Skamil	DPRINTF("Before resuming the child process where it left off and "
16171.180Skamil	    "without signal to be sent\n");
16181.180Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
16191.180Skamil	    faked ? sigfaked : sigval) != -1);
16201.1Skamil
16211.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16221.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
16231.1Skamil
16241.180Skamil	validate_status_exited(status, exitval);
16251.1Skamil
16261.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16271.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
16281.1Skamil}
16291.1Skamil
16301.180Skamil#define PTRACE_SIGINFO(test, faked)					\
16311.83SkamilATF_TC(test);								\
16321.83SkamilATF_TC_HEAD(test, tc)							\
16331.83Skamil{									\
16341.180Skamil	atf_tc_set_md_var(tc, "descr",					\
16351.180Skamil	    "Verify basic PT_GET_SIGINFO and PT_SET_SIGINFO calls"	\
16361.180Skamil	    "with%s setting signal to new value", faked ? "" : "out");	\
16371.180Skamil}									\
16381.180Skamil									\
16391.180Skamilstatic int test##_caught = 0;						\
16401.180Skamil									\
16411.180Skamilstatic void								\
16421.180Skamiltest##_sighandler(int sig, siginfo_t *info, void *ctx)			\
16431.180Skamil{									\
16441.180Skamil	if (faked) {							\
16451.180Skamil		FORKEE_ASSERT_EQ(sig, SIGTRAP);				\
16461.180Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGTRAP);		\
16471.180Skamil		FORKEE_ASSERT_EQ(info->si_code, TRAP_BRKPT);		\
16481.180Skamil	} else {							\
16491.180Skamil		FORKEE_ASSERT_EQ(sig, SIGINT);				\
16501.180Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGINT);		\
16511.180Skamil		FORKEE_ASSERT_EQ(info->si_code, SI_LWP);		\
16521.180Skamil	}								\
16531.180Skamil									\
16541.180Skamil	++ test##_caught;						\
16551.83Skamil}									\
16561.83Skamil									\
16571.83SkamilATF_TC_BODY(test, tc)							\
16581.83Skamil{									\
16591.83Skamil									\
16601.180Skamil	ptrace_siginfo(faked, test##_sighandler, & test##_caught); 	\
16611.83Skamil}
16621.83Skamil
16631.180SkamilPTRACE_SIGINFO(siginfo_set_unmodified, false)
16641.180SkamilPTRACE_SIGINFO(siginfo_set_faked, true)
16651.83Skamil
16661.83Skamil/// ----------------------------------------------------------------------------
16671.83Skamil
16681.180Skamilstatic void
16691.180Skamiltraceme_exec(bool masked, bool ignored)
16701.1Skamil{
16711.180Skamil	const int sigval = SIGTRAP;
16721.1Skamil	pid_t child, wpid;
16731.1Skamil#if defined(TWAIT_HAVE_STATUS)
16741.1Skamil	int status;
16751.1Skamil#endif
16761.180Skamil	struct sigaction sa;
16771.180Skamil	struct ptrace_siginfo info;
16781.1Skamil	sigset_t intmask;
16791.180Skamil	struct kinfo_proc2 kp;
16801.180Skamil	size_t len = sizeof(kp);
16811.180Skamil
16821.180Skamil	int name[6];
16831.180Skamil	const size_t namelen = __arraycount(name);
16841.180Skamil	ki_sigset_t kp_sigmask;
16851.180Skamil	ki_sigset_t kp_sigignore;
16861.180Skamil
16871.180Skamil	memset(&info, 0, sizeof(info));
16881.1Skamil
16891.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
16901.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
16911.1Skamil	if (child == 0) {
16921.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
16931.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
16941.1Skamil
16951.180Skamil		if (masked) {
16961.180Skamil			sigemptyset(&intmask);
16971.180Skamil			sigaddset(&intmask, sigval);
16981.180Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
16991.180Skamil		}
17001.1Skamil
17011.180Skamil		if (ignored) {
17021.180Skamil			memset(&sa, 0, sizeof(sa));
17031.180Skamil			sa.sa_handler = SIG_IGN;
17041.180Skamil			sigemptyset(&sa.sa_mask);
17051.180Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
17061.180Skamil		}
17071.1Skamil
17081.180Skamil		DPRINTF("Before calling execve(2) from child\n");
17091.180Skamil		execlp("/bin/echo", "/bin/echo", NULL);
17101.1Skamil
17111.180Skamil		FORKEE_ASSERT(0 && "Not reached");
17121.1Skamil	}
17131.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
17141.1Skamil
17151.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17161.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17171.1Skamil
17181.1Skamil	validate_status_stopped(status, sigval);
17191.1Skamil
17201.180Skamil	name[0] = CTL_KERN,
17211.180Skamil	name[1] = KERN_PROC2,
17221.180Skamil	name[2] = KERN_PROC_PID;
17231.180Skamil	name[3] = getpid();
17241.180Skamil	name[4] = sizeof(kp);
17251.180Skamil	name[5] = 1;
17261.180Skamil
17271.180Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
17281.180Skamil
17291.180Skamil	if (masked)
17301.180Skamil		kp_sigmask = kp.p_sigmask;
17311.180Skamil
17321.180Skamil	if (ignored)
17331.180Skamil		kp_sigignore = kp.p_sigignore;
17341.180Skamil
17351.180Skamil	name[3] = getpid();
17361.180Skamil
17371.180Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
17381.180Skamil
17391.180Skamil	if (masked) {
17401.180Skamil		DPRINTF("kp_sigmask="
17411.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
17421.180Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
17431.180Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
17441.180Skamil
17451.180Skamil		DPRINTF("kp.p_sigmask="
17461.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
17471.180Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
17481.180Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
17491.180Skamil
17501.180Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
17511.180Skamil		    sizeof(kp_sigmask)));
17521.180Skamil	}
17531.180Skamil
17541.180Skamil	if (ignored) {
17551.180Skamil		DPRINTF("kp_sigignore="
17561.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
17571.180Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
17581.180Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
17591.180Skamil
17601.180Skamil		DPRINTF("kp.p_sigignore="
17611.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
17621.180Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
17631.180Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
17641.180Skamil
17651.180Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
17661.180Skamil		    sizeof(kp_sigignore)));
17671.180Skamil	}
17681.180Skamil
17691.180Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
17701.180Skamil	SYSCALL_REQUIRE(
17711.180Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
17721.1Skamil
17731.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
17741.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
17751.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
17761.180Skamil	    info.psi_siginfo.si_errno);
17771.1Skamil
17781.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
17791.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
17801.1Skamil
17811.13Schristos	DPRINTF("Before resuming the child process where it left off and "
17821.1Skamil	    "without signal to be sent\n");
17831.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
17841.1Skamil
17851.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17861.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17871.1Skamil
17881.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17891.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
17901.1Skamil}
17911.1Skamil
17921.180Skamil#define TRACEME_EXEC(test, masked, ignored)				\
17931.180SkamilATF_TC(test);								\
17941.180SkamilATF_TC_HEAD(test, tc)							\
17951.180Skamil{									\
17961.180Skamil       atf_tc_set_md_var(tc, "descr",					\
17971.180Skamil           "Detect SIGTRAP TRAP_EXEC from "				\
17981.180Skamil           "child%s%s", masked ? " with masked signal" : "",		\
17991.180Skamil           masked ? " with ignored signal" : "");			\
18001.180Skamil}									\
18011.180Skamil									\
18021.180SkamilATF_TC_BODY(test, tc)							\
18031.180Skamil{									\
18041.180Skamil									\
18051.180Skamil       traceme_exec(masked, ignored);					\
18061.180Skamil}
18071.180Skamil
18081.180SkamilTRACEME_EXEC(traceme_exec, false, false)
18091.180SkamilTRACEME_EXEC(traceme_signalmasked_exec, true, false)
18101.180SkamilTRACEME_EXEC(traceme_signalignored_exec, false, true)
18111.180Skamil
18121.84Skamil/// ----------------------------------------------------------------------------
18131.84Skamil
18141.180Skamil#define TRACE_THREADS_NUM 100
18151.180Skamil
18161.180Skamilstatic volatile int done;
18171.180Skamilpthread_mutex_t trace_threads_mtx = PTHREAD_MUTEX_INITIALIZER;
18181.180Skamil
18191.180Skamilstatic void *
18201.180Skamiltrace_threads_cb(void *arg __unused)
18211.180Skamil{
18221.180Skamil
18231.180Skamil	pthread_mutex_lock(&trace_threads_mtx);
18241.180Skamil	done++;
18251.180Skamil	pthread_mutex_unlock(&trace_threads_mtx);
18261.180Skamil
18271.180Skamil	while (done < TRACE_THREADS_NUM)
18281.180Skamil		sched_yield();
18291.180Skamil
18301.180Skamil	return NULL;
18311.180Skamil}
18321.180Skamil
18331.99Skamilstatic void
18341.180Skamiltrace_threads(bool trace_create, bool trace_exit, bool masked)
18351.1Skamil{
18361.1Skamil	const int sigval = SIGSTOP;
18371.180Skamil	pid_t child, wpid;
18381.1Skamil#if defined(TWAIT_HAVE_STATUS)
18391.1Skamil	int status;
18401.1Skamil#endif
18411.1Skamil	ptrace_state_t state;
18421.1Skamil	const int slen = sizeof(state);
18431.1Skamil	ptrace_event_t event;
18441.1Skamil	const int elen = sizeof(event);
18451.99Skamil	struct ptrace_siginfo info;
18461.180Skamil
18471.99Skamil	sigset_t intmask;
18481.99Skamil
18491.180Skamil	pthread_t t[TRACE_THREADS_NUM];
18501.180Skamil	int rv;
18511.180Skamil	size_t n;
18521.180Skamil	lwpid_t lid;
18531.1Skamil
18541.180Skamil	/* Track created and exited threads */
18551.180Skamil	struct lwp_event_count traced_lwps[__arraycount(t)] = {{0, 0}};
18561.14Schristos
18571.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
18581.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
18591.1Skamil	if (child == 0) {
18601.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
18611.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
18621.1Skamil
18631.99Skamil		if (masked) {
18641.99Skamil			sigemptyset(&intmask);
18651.99Skamil			sigaddset(&intmask, SIGTRAP);
18661.99Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
18671.99Skamil		}
18681.99Skamil
18691.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
18701.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
18711.1Skamil
18721.180Skamil		for (n = 0; n < __arraycount(t); n++) {
18731.180Skamil			rv = pthread_create(&t[n], NULL, trace_threads_cb,
18741.180Skamil			    NULL);
18751.180Skamil			FORKEE_ASSERT(rv == 0);
18761.126Skamil		}
18771.1Skamil
18781.180Skamil		for (n = 0; n < __arraycount(t); n++) {
18791.180Skamil			rv = pthread_join(t[n], NULL);
18801.180Skamil			FORKEE_ASSERT(rv == 0);
18811.180Skamil		}
18821.1Skamil
18831.180Skamil		/*
18841.180Skamil		 * There is race between _exit() and pthread_join() detaching
18851.180Skamil		 * a thread. For simplicity kill the process after detecting
18861.180Skamil		 * LWP events.
18871.180Skamil		 */
18881.180Skamil		while (true)
18891.180Skamil			continue;
18901.1Skamil
18911.180Skamil		FORKEE_ASSERT(0 && "Not reached");
18921.1Skamil	}
18931.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
18941.1Skamil
18951.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18961.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
18971.1Skamil
18981.1Skamil	validate_status_stopped(status, sigval);
18991.1Skamil
19001.99Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
19011.99Skamil	SYSCALL_REQUIRE(
19021.99Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
19031.99Skamil
19041.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
19051.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
19061.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
19071.180Skamil	    info.psi_siginfo.si_errno);
19081.180Skamil
19091.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
19101.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
19111.1Skamil
19121.180Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
19131.180Skamil	memset(&event, 0, sizeof(event));
19141.180Skamil	if (trace_create)
19151.180Skamil		event.pe_set_event |= PTRACE_LWP_CREATE;
19161.180Skamil	if (trace_exit)
19171.180Skamil		event.pe_set_event |= PTRACE_LWP_EXIT;
19181.99Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
19191.1Skamil
19201.99Skamil	DPRINTF("Before resuming the child process where it left off and "
19211.99Skamil	    "without signal to be sent\n");
19221.99Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
19231.1Skamil
19241.180Skamil	for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
19251.180Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
19261.180Skamil		    "SIGTRAP\n", TWAIT_FNAME);
19271.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
19281.99Skamil		    child);
19291.1Skamil
19301.99Skamil		validate_status_stopped(status, SIGTRAP);
19311.1Skamil
19321.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
19331.180Skamil		    "child\n");
19341.180Skamil		SYSCALL_REQUIRE(
19351.180Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
19361.180Skamil
19371.180Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
19381.180Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
19391.180Skamil		    "si_errno=%#x\n",
19401.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
19411.180Skamil		    info.psi_siginfo.si_errno);
19421.1Skamil
19431.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
19441.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
19451.1Skamil
19461.180Skamil		SYSCALL_REQUIRE(
19471.180Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
19481.1Skamil
19491.180Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
19501.180Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
19511.1Skamil
19521.180Skamil		lid = state.pe_lwp;
19531.180Skamil		DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
19541.1Skamil
19551.180Skamil		*FIND_EVENT_COUNT(traced_lwps, lid) += 1;
19561.1Skamil
19571.180Skamil		DPRINTF("Before resuming the child process where it left off "
19581.180Skamil		    "and without signal to be sent\n");
19591.180Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
19601.180Skamil	}
19611.1Skamil
19621.180Skamil	for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
19631.180Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
19641.180Skamil		    "SIGTRAP\n", TWAIT_FNAME);
19651.180Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
19661.180Skamil		    child);
19671.1Skamil
19681.99Skamil		validate_status_stopped(status, SIGTRAP);
19691.1Skamil
19701.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
19711.180Skamil		    "child\n");
19721.180Skamil		SYSCALL_REQUIRE(
19731.180Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
19741.1Skamil
19751.180Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
19761.180Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
19771.180Skamil		    "si_errno=%#x\n",
19781.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
19791.180Skamil		    info.psi_siginfo.si_errno);
19801.1Skamil
19811.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
19821.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
19831.14Schristos
19841.180Skamil		SYSCALL_REQUIRE(
19851.180Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
19861.1Skamil
19871.180Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
19881.180Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
19891.1Skamil
19901.180Skamil		lid = state.pe_lwp;
19911.180Skamil		DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
19921.1Skamil
19931.180Skamil		if (trace_create) {
19941.180Skamil			int *count = FIND_EVENT_COUNT(traced_lwps, lid);
19951.180Skamil			ATF_REQUIRE_EQ(*count, 1);
19961.180Skamil			*count = 0;
19971.99Skamil		}
19981.1Skamil
19991.99Skamil		DPRINTF("Before resuming the child process where it left off "
20001.99Skamil		    "and without signal to be sent\n");
20011.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
20021.1Skamil	}
20031.1Skamil
20041.180Skamil	kill(child, SIGKILL);
20051.180Skamil
20061.180Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
20071.180Skamil	    TWAIT_FNAME);
20081.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
20091.180Skamil
20101.180Skamil	validate_status_signaled(status, SIGKILL, 0);
20111.1Skamil
20121.180Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
20131.180Skamil	    TWAIT_FNAME);
20141.180Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
20151.180Skamil}
20161.1Skamil
20171.180Skamil#define TRACE_THREADS(test, trace_create, trace_exit, mask)		\
20181.180SkamilATF_TC(test);								\
20191.180SkamilATF_TC_HEAD(test, tc)							\
20201.180Skamil{									\
20211.180Skamil        atf_tc_set_md_var(tc, "descr",					\
20221.180Skamil            "Verify spawning threads with%s tracing LWP create and"	\
20231.180Skamil	    "with%s tracing LWP exit", trace_create ? "" : "out",	\
20241.180Skamil	    trace_exit ? "" : "out");					\
20251.180Skamil}									\
20261.180Skamil									\
20271.180SkamilATF_TC_BODY(test, tc)							\
20281.180Skamil{									\
20291.180Skamil									\
20301.180Skamil        trace_threads(trace_create, trace_exit, mask);			\
20311.180Skamil}
20321.1Skamil
20331.180SkamilTRACE_THREADS(trace_thread_nolwpevents, false, false, false)
20341.180SkamilTRACE_THREADS(trace_thread_lwpexit, false, true, false)
20351.180SkamilTRACE_THREADS(trace_thread_lwpcreate, true, false, false)
20361.180SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true, false)
20371.102Skamil
20381.180SkamilTRACE_THREADS(trace_thread_lwpexit_masked_sigtrap, false, true, true)
20391.180SkamilTRACE_THREADS(trace_thread_lwpcreate_masked_sigtrap, true, false, true)
20401.180SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit_masked_sigtrap, true, true, true)
20411.1Skamil
20421.180Skamil/// ----------------------------------------------------------------------------
20431.1Skamil
20441.151Skamilstatic void *
20451.151Skamilthread_and_exec_thread_cb(void *arg __unused)
20461.151Skamil{
20471.151Skamil
20481.151Skamil	execlp("/bin/echo", "/bin/echo", NULL);
20491.151Skamil
20501.151Skamil	abort();
20511.151Skamil}
20521.151Skamil
20531.151Skamilstatic void
20541.151Skamilthreads_and_exec(void)
20551.151Skamil{
20561.151Skamil	const int sigval = SIGSTOP;
20571.151Skamil	pid_t child, wpid;
20581.151Skamil#if defined(TWAIT_HAVE_STATUS)
20591.151Skamil	int status;
20601.151Skamil#endif
20611.151Skamil	ptrace_state_t state;
20621.151Skamil	const int slen = sizeof(state);
20631.151Skamil	ptrace_event_t event;
20641.151Skamil	const int elen = sizeof(event);
20651.151Skamil	struct ptrace_siginfo info;
20661.151Skamil
20671.151Skamil	pthread_t t;
20681.151Skamil	lwpid_t lid;
20691.151Skamil
20701.151Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
20711.151Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
20721.151Skamil	if (child == 0) {
20731.151Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
20741.151Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
20751.151Skamil
20761.151Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
20771.151Skamil		FORKEE_ASSERT(raise(sigval) == 0);
20781.151Skamil
20791.151Skamil		FORKEE_ASSERT(pthread_create(&t, NULL,
20801.151Skamil		    thread_and_exec_thread_cb, NULL) == 0);
20811.151Skamil
20821.151Skamil		for (;;)
20831.151Skamil			continue;
20841.151Skamil
20851.151Skamil		FORKEE_ASSERT(0 && "Not reached");
20861.151Skamil	}
20871.151Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
20881.151Skamil
20891.151Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
20901.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
20911.151Skamil
20921.151Skamil	validate_status_stopped(status, sigval);
20931.151Skamil
20941.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
20951.151Skamil	SYSCALL_REQUIRE(
20961.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
20971.151Skamil
20981.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
20991.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
21001.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
21011.151Skamil	    info.psi_siginfo.si_errno);
21021.151Skamil
21031.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
21041.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
21051.151Skamil
21061.151Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
21071.151Skamil	memset(&event, 0, sizeof(event));
21081.151Skamil	event.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
21091.151Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
21101.151Skamil
21111.151Skamil	DPRINTF("Before resuming the child process where it left off and "
21121.151Skamil	    "without signal to be sent\n");
21131.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
21141.151Skamil
21151.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
21161.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
21171.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
21181.151Skamil	    child);
21191.151Skamil
21201.151Skamil	validate_status_stopped(status, SIGTRAP);
21211.151Skamil
21221.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
21231.151Skamil	    "child\n");
21241.151Skamil	SYSCALL_REQUIRE(
21251.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
21261.151Skamil
21271.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
21281.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
21291.151Skamil	    "si_errno=%#x\n",
21301.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
21311.151Skamil	    info.psi_siginfo.si_errno);
21321.151Skamil
21331.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
21341.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
21351.151Skamil
21361.151Skamil	SYSCALL_REQUIRE(
21371.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
21381.151Skamil
21391.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
21401.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
21411.151Skamil
21421.151Skamil	lid = state.pe_lwp;
21431.151Skamil	DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
21441.151Skamil
21451.151Skamil	DPRINTF("Before resuming the child process where it left off "
21461.151Skamil	    "and without signal to be sent\n");
21471.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
21481.151Skamil
21491.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
21501.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
21511.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
21521.151Skamil	    child);
21531.151Skamil
21541.151Skamil	validate_status_stopped(status, SIGTRAP);
21551.151Skamil
21561.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
21571.151Skamil	    "child\n");
21581.151Skamil	SYSCALL_REQUIRE(
21591.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
21601.151Skamil
21611.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
21621.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
21631.151Skamil	    "si_errno=%#x\n",
21641.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
21651.151Skamil	    info.psi_siginfo.si_errno);
21661.151Skamil
21671.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
21681.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
21691.151Skamil
21701.151Skamil	SYSCALL_REQUIRE(
21711.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
21721.151Skamil
21731.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
21741.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
21751.151Skamil
21761.151Skamil	lid = state.pe_lwp;
21771.151Skamil	DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
21781.151Skamil
21791.151Skamil	DPRINTF("Before resuming the child process where it left off "
21801.151Skamil	    "and without signal to be sent\n");
21811.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
21821.151Skamil
21831.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
21841.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
21851.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
21861.151Skamil	    child);
21871.151Skamil
21881.151Skamil	validate_status_stopped(status, SIGTRAP);
21891.151Skamil
21901.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
21911.151Skamil	    "child\n");
21921.151Skamil	SYSCALL_REQUIRE(
21931.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
21941.151Skamil
21951.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
21961.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
21971.151Skamil	    "si_errno=%#x\n",
21981.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
21991.151Skamil	    info.psi_siginfo.si_errno);
22001.151Skamil
22011.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
22021.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
22031.151Skamil
22041.151Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
22051.151Skamil
22061.151Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
22071.151Skamil	    TWAIT_FNAME);
22081.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
22091.151Skamil
22101.151Skamil	validate_status_signaled(status, SIGKILL, 0);
22111.151Skamil
22121.151Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
22131.151Skamil	    TWAIT_FNAME);
22141.151Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
22151.151Skamil}
22161.151Skamil
22171.151SkamilATF_TC(threads_and_exec);
22181.151SkamilATF_TC_HEAD(threads_and_exec, tc)
22191.151Skamil{
22201.151Skamil        atf_tc_set_md_var(tc, "descr",
22211.151Skamil            "Verify that multithreaded application on exec() will report "
22221.151Skamil	    "LWP_EXIT events");
22231.151Skamil}
22241.151Skamil
22251.151SkamilATF_TC_BODY(threads_and_exec, tc)
22261.151Skamil{
22271.151Skamil
22281.151Skamil        threads_and_exec();
22291.151Skamil}
22301.151Skamil
22311.151Skamil/// ----------------------------------------------------------------------------
22321.151Skamil
22331.154SkamilATF_TC(suspend_no_deadlock);
22341.154SkamilATF_TC_HEAD(suspend_no_deadlock, tc)
22351.1Skamil{
22361.1Skamil	atf_tc_set_md_var(tc, "descr",
22371.1Skamil	    "Verify that the while the only thread within a process is "
22381.1Skamil	    "suspended, the whole process cannot be unstopped");
22391.1Skamil}
22401.1Skamil
22411.154SkamilATF_TC_BODY(suspend_no_deadlock, tc)
22421.1Skamil{
22431.1Skamil	const int exitval = 5;
22441.1Skamil	const int sigval = SIGSTOP;
22451.1Skamil	pid_t child, wpid;
22461.1Skamil#if defined(TWAIT_HAVE_STATUS)
22471.1Skamil	int status;
22481.1Skamil#endif
22491.1Skamil	struct ptrace_siginfo psi;
22501.1Skamil
22511.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
22521.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
22531.1Skamil	if (child == 0) {
22541.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
22551.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
22561.1Skamil
22571.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
22581.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
22591.1Skamil
22601.13Schristos		DPRINTF("Before exiting of the child process\n");
22611.1Skamil		_exit(exitval);
22621.1Skamil	}
22631.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
22641.1Skamil
22651.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
22661.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
22671.1Skamil
22681.1Skamil	validate_status_stopped(status, sigval);
22691.1Skamil
22701.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
22711.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
22721.1Skamil
22731.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
22741.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
22751.1Skamil
22761.13Schristos	DPRINTF("Before resuming the child process where it left off and "
22771.1Skamil	    "without signal to be sent\n");
22781.1Skamil	ATF_REQUIRE_ERRNO(EDEADLK,
22791.1Skamil	    ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
22801.1Skamil
22811.13Schristos	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
22821.13Schristos	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
22831.1Skamil
22841.13Schristos	DPRINTF("Before resuming the child process where it left off and "
22851.1Skamil	    "without signal to be sent\n");
22861.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
22871.1Skamil
22881.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
22891.1Skamil	    TWAIT_FNAME);
22901.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
22911.1Skamil
22921.1Skamil	validate_status_exited(status, exitval);
22931.1Skamil
22941.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
22951.1Skamil	    TWAIT_FNAME);
22961.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
22971.1Skamil}
22981.1Skamil
22991.154Skamil/// ----------------------------------------------------------------------------
23001.154Skamil
23011.155Skamilstatic pthread_barrier_t barrier1_resume;
23021.155Skamilstatic pthread_barrier_t barrier2_resume;
23031.154Skamil
23041.155Skamilstatic void *
23051.155Skamilresume_thread(void *arg)
23061.154Skamil{
23071.154Skamil
23081.155Skamil	raise(SIGUSR1);
23091.155Skamil
23101.155Skamil	pthread_barrier_wait(&barrier1_resume);
23111.155Skamil
23121.155Skamil	/* Debugger will suspend the process here */
23131.155Skamil
23141.155Skamil	pthread_barrier_wait(&barrier2_resume);
23151.154Skamil
23161.155Skamil	raise(SIGUSR2);
23171.155Skamil
23181.155Skamil	return infinite_thread(arg);
23191.154Skamil}
23201.154Skamil
23211.155SkamilATF_TC(resume);
23221.155SkamilATF_TC_HEAD(resume, tc)
23231.1Skamil{
23241.1Skamil	atf_tc_set_md_var(tc, "descr",
23251.1Skamil	    "Verify that a thread can be suspended by a debugger and later "
23261.1Skamil	    "resumed by the debugger");
23271.1Skamil}
23281.1Skamil
23291.155SkamilATF_TC_BODY(resume, tc)
23301.1Skamil{
23311.1Skamil	const int sigval = SIGSTOP;
23321.1Skamil	pid_t child, wpid;
23331.1Skamil#if defined(TWAIT_HAVE_STATUS)
23341.1Skamil	int status;
23351.1Skamil#endif
23361.1Skamil	lwpid_t lid;
23371.1Skamil	struct ptrace_siginfo psi;
23381.155Skamil	pthread_t t;
23391.1Skamil
23401.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
23411.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
23421.1Skamil	if (child == 0) {
23431.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
23441.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
23451.1Skamil
23461.155Skamil		pthread_barrier_init(&barrier1_resume, NULL, 2);
23471.155Skamil		pthread_barrier_init(&barrier2_resume, NULL, 2);
23481.155Skamil
23491.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
23501.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
23511.1Skamil
23521.155Skamil		DPRINTF("Before creating new thread in child\n");
23531.155Skamil		FORKEE_ASSERT(pthread_create(&t, NULL, resume_thread, NULL) == 0);
23541.1Skamil
23551.155Skamil		pthread_barrier_wait(&barrier1_resume);
23561.1Skamil
23571.155Skamil		pthread_barrier_wait(&barrier2_resume);
23581.1Skamil
23591.155Skamil		infinite_thread(NULL);
23601.1Skamil	}
23611.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
23621.1Skamil
23631.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
23641.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
23651.1Skamil
23661.1Skamil	validate_status_stopped(status, sigval);
23671.1Skamil
23681.13Schristos	DPRINTF("Before resuming the child process where it left off and "
23691.1Skamil	    "without signal to be sent\n");
23701.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
23711.1Skamil
23721.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
23731.155Skamil	    "SIGUSR1\n", TWAIT_FNAME);
23741.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
23751.1Skamil
23761.155Skamil	validate_status_stopped(status, SIGUSR1);
23771.1Skamil
23781.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
23791.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
23801.1Skamil
23811.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
23821.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
23831.1Skamil
23841.155Skamil	lid = psi.psi_lwpid;
23851.1Skamil
23861.13Schristos	DPRINTF("Before resuming the child process where it left off and "
23871.1Skamil	    "without signal to be sent\n");
23881.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
23891.1Skamil
23901.155Skamil	DPRINTF("Before suspending the parent for 1 second, we expect no signals\n");
23911.155Skamil	SYSCALL_REQUIRE(sleep(1) == 0);
23921.155Skamil
23931.155Skamil#if defined(TWAIT_HAVE_OPTIONS)
23941.155Skamil	DPRINTF("Before calling %s() for the child - expected no status\n",
23951.155Skamil	    TWAIT_FNAME);
23961.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, WNOHANG), 0);
23971.155Skamil#endif
23981.155Skamil
23991.155Skamil	DPRINTF("Before resuming the child process where it left off and "
24001.155Skamil	    "without signal to be sent\n");
24011.155Skamil	SYSCALL_REQUIRE(ptrace(PT_STOP, child, NULL, 0) != -1);
24021.155Skamil
24031.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
24041.155Skamil	    "SIGSTOP\n", TWAIT_FNAME);
24051.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
24061.1Skamil
24071.155Skamil	validate_status_stopped(status, SIGSTOP);
24081.1Skamil
24091.155Skamil	DPRINTF("Before resuming LWP %d\n", lid);
24101.155Skamil	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, lid) != -1);
24111.155Skamil
24121.155Skamil	DPRINTF("Before resuming the child process where it left off and "
24131.155Skamil	    "without signal to be sent\n");
24141.155Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
24151.1Skamil
24161.155Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
24171.155Skamil	    "SIGUSR2\n", TWAIT_FNAME);
24181.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
24191.1Skamil
24201.155Skamil	validate_status_stopped(status, SIGUSR2);
24211.1Skamil
24221.13Schristos	DPRINTF("Before resuming the child process where it left off and "
24231.1Skamil	    "without signal to be sent\n");
24241.155Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
24251.1Skamil
24261.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
24271.1Skamil	    TWAIT_FNAME);
24281.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
24291.1Skamil
24301.155Skamil	validate_status_signaled(status, SIGKILL, 0);
24311.1Skamil
24321.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
24331.1Skamil	    TWAIT_FNAME);
24341.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
24351.155Skamil}
24361.1Skamil
24371.155Skamil/// ----------------------------------------------------------------------------
24381.1Skamil
24391.106Skamilstatic void
24401.122Skamiluser_va0_disable(int operation)
24411.122Skamil{
24421.122Skamil	pid_t child, wpid;
24431.122Skamil#if defined(TWAIT_HAVE_STATUS)
24441.122Skamil	int status;
24451.122Skamil#endif
24461.122Skamil	const int sigval = SIGSTOP;
24471.122Skamil	int rv;
24481.122Skamil
24491.122Skamil	struct ptrace_siginfo info;
24501.122Skamil
24511.122Skamil	if (get_user_va0_disable() == 0)
24521.122Skamil		atf_tc_skip("vm.user_va0_disable is set to 0");
24531.122Skamil
24541.122Skamil	memset(&info, 0, sizeof(info));
24551.122Skamil
24561.122Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
24571.122Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
24581.122Skamil	if (child == 0) {
24591.122Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
24601.122Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
24611.122Skamil
24621.122Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
24631.122Skamil		FORKEE_ASSERT(raise(sigval) == 0);
24641.122Skamil
24651.122Skamil		/* NOTREACHED */
24661.122Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
24671.122Skamil		__unreachable();
24681.122Skamil	}
24691.122Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
24701.122Skamil
24711.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
24721.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
24731.122Skamil
24741.122Skamil	validate_status_stopped(status, sigval);
24751.122Skamil
24761.122Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
24771.122Skamil		"child\n");
24781.122Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
24791.122Skamil		sizeof(info)) != -1);
24801.122Skamil
24811.122Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
24821.122Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
24831.122Skamil		"si_errno=%#x\n",
24841.122Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
24851.122Skamil		info.psi_siginfo.si_errno);
24861.122Skamil
24871.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
24881.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
24891.122Skamil
24901.122Skamil	DPRINTF("Before resuming the child process in PC=0x0 "
24911.122Skamil	    "and without signal to be sent\n");
24921.122Skamil	errno = 0;
24931.122Skamil	rv = ptrace(operation, child, (void *)0, 0);
24941.122Skamil	ATF_REQUIRE_EQ(errno, EINVAL);
24951.122Skamil	ATF_REQUIRE_EQ(rv, -1);
24961.122Skamil
24971.122Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
24981.122Skamil
24991.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
25001.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
25011.122Skamil	validate_status_signaled(status, SIGKILL, 0);
25021.122Skamil
25031.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
25041.122Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
25051.122Skamil}
25061.122Skamil
25071.122Skamil#define USER_VA0_DISABLE(test, operation)				\
25081.122SkamilATF_TC(test);								\
25091.122SkamilATF_TC_HEAD(test, tc)							\
25101.122Skamil{									\
25111.122Skamil	atf_tc_set_md_var(tc, "descr",					\
25121.122Skamil	    "Verify behavior of " #operation " with PC set to 0x0");	\
25131.122Skamil}									\
25141.122Skamil									\
25151.122SkamilATF_TC_BODY(test, tc)							\
25161.122Skamil{									\
25171.122Skamil									\
25181.122Skamil	user_va0_disable(operation);					\
25191.122Skamil}
25201.122Skamil
25211.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_continue, PT_CONTINUE)
25221.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_syscall, PT_SYSCALL)
25231.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_detach, PT_DETACH)
25241.122Skamil
25251.122Skamil/// ----------------------------------------------------------------------------
25261.122Skamil
25271.130Smgorny/*
25281.130Smgorny * Parse the core file and find the requested note.  If the reading or parsing
25291.130Smgorny * fails, the test is failed.  If the note is found, it is read onto buf, up to
25301.130Smgorny * buf_len.  The actual length of the note is returned (which can be greater
25311.130Smgorny * than buf_len, indicating that it has been truncated).  If the note is not
25321.130Smgorny * found, -1 is returned.
25331.172Sthorpej *
25341.172Sthorpej * If the note_name ends in '*', then we find the first note that matches
25351.172Sthorpej * the note_name prefix up to the '*' character, e.g.:
25361.172Sthorpej *
25371.172Sthorpej *	NetBSD-CORE@*
25381.172Sthorpej *
25391.172Sthorpej * finds the first note whose name prefix matches "NetBSD-CORE@".
25401.130Smgorny */
25411.130Smgornystatic ssize_t core_find_note(const char *core_path,
25421.130Smgorny    const char *note_name, uint64_t note_type, void *buf, size_t buf_len)
25431.130Smgorny{
25441.130Smgorny	int core_fd;
25451.130Smgorny	Elf *core_elf;
25461.130Smgorny	size_t core_numhdr, i;
25471.130Smgorny	ssize_t ret = -1;
25481.172Sthorpej	size_t name_len = strlen(note_name);
25491.172Sthorpej	bool prefix_match = false;
25501.172Sthorpej
25511.172Sthorpej	if (note_name[name_len - 1] == '*') {
25521.172Sthorpej		prefix_match = true;
25531.172Sthorpej		name_len--;
25541.172Sthorpej	} else {
25551.172Sthorpej		/* note: we assume note name will be null-terminated */
25561.172Sthorpej		name_len++;
25571.172Sthorpej	}
25581.130Smgorny
25591.130Smgorny	SYSCALL_REQUIRE((core_fd = open(core_path, O_RDONLY)) != -1);
25601.130Smgorny	SYSCALL_REQUIRE(elf_version(EV_CURRENT) != EV_NONE);
25611.130Smgorny	SYSCALL_REQUIRE((core_elf = elf_begin(core_fd, ELF_C_READ, NULL)));
25621.130Smgorny
25631.130Smgorny	SYSCALL_REQUIRE(elf_getphnum(core_elf, &core_numhdr) != 0);
25641.130Smgorny	for (i = 0; i < core_numhdr && ret == -1; i++) {
25651.130Smgorny		GElf_Phdr core_hdr;
25661.130Smgorny		size_t offset;
25671.130Smgorny		SYSCALL_REQUIRE(gelf_getphdr(core_elf, i, &core_hdr));
25681.130Smgorny		if (core_hdr.p_type != PT_NOTE)
25691.130Smgorny		    continue;
25701.130Smgorny
25711.130Smgorny		for (offset = core_hdr.p_offset;
25721.130Smgorny		    offset < core_hdr.p_offset + core_hdr.p_filesz;) {
25731.130Smgorny			Elf64_Nhdr note_hdr;
25741.130Smgorny			char name_buf[64];
25751.130Smgorny
25761.130Smgorny			switch (gelf_getclass(core_elf)) {
25771.130Smgorny			case ELFCLASS64:
25781.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &note_hdr,
25791.130Smgorny				    sizeof(note_hdr), offset)
25801.130Smgorny				    == sizeof(note_hdr));
25811.130Smgorny				offset += sizeof(note_hdr);
25821.130Smgorny				break;
25831.130Smgorny			case ELFCLASS32:
25841.130Smgorny				{
25851.130Smgorny				Elf32_Nhdr tmp_hdr;
25861.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &tmp_hdr,
25871.130Smgorny				    sizeof(tmp_hdr), offset)
25881.130Smgorny				    == sizeof(tmp_hdr));
25891.130Smgorny				offset += sizeof(tmp_hdr);
25901.130Smgorny				note_hdr.n_namesz = tmp_hdr.n_namesz;
25911.130Smgorny				note_hdr.n_descsz = tmp_hdr.n_descsz;
25921.130Smgorny				note_hdr.n_type = tmp_hdr.n_type;
25931.130Smgorny				}
25941.130Smgorny				break;
25951.130Smgorny			}
25961.130Smgorny
25971.130Smgorny			/* indicates end of notes */
25981.130Smgorny			if (note_hdr.n_namesz == 0 || note_hdr.n_descsz == 0)
25991.130Smgorny				break;
26001.172Sthorpej			if (((prefix_match &&
26011.172Sthorpej			      note_hdr.n_namesz > name_len) ||
26021.172Sthorpej			     (!prefix_match &&
26031.172Sthorpej			      note_hdr.n_namesz == name_len)) &&
26041.130Smgorny			    note_hdr.n_namesz <= sizeof(name_buf)) {
26051.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, name_buf,
26061.130Smgorny				    note_hdr.n_namesz, offset)
26071.131Skamil				    == (ssize_t)(size_t)note_hdr.n_namesz);
26081.130Smgorny
26091.130Smgorny				if (!strncmp(note_name, name_buf, name_len) &&
26101.130Smgorny				    note_hdr.n_type == note_type)
26111.130Smgorny					ret = note_hdr.n_descsz;
26121.130Smgorny			}
26131.130Smgorny
26141.130Smgorny			offset += note_hdr.n_namesz;
26151.130Smgorny			/* fix to alignment */
26161.146Smgorny			offset = roundup(offset, core_hdr.p_align);
26171.130Smgorny
26181.130Smgorny			/* if name & type matched above */
26191.130Smgorny			if (ret != -1) {
26201.130Smgorny				ssize_t read_len = MIN(buf_len,
26211.130Smgorny				    note_hdr.n_descsz);
26221.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, buf,
26231.130Smgorny				    read_len, offset) == read_len);
26241.130Smgorny				break;
26251.130Smgorny			}
26261.130Smgorny
26271.130Smgorny			offset += note_hdr.n_descsz;
26281.146Smgorny			/* fix to alignment */
26291.146Smgorny			offset = roundup(offset, core_hdr.p_align);
26301.130Smgorny		}
26311.130Smgorny	}
26321.130Smgorny
26331.130Smgorny	elf_end(core_elf);
26341.130Smgorny	close(core_fd);
26351.130Smgorny
26361.130Smgorny	return ret;
26371.130Smgorny}
26381.130Smgorny
26391.130SmgornyATF_TC(core_dump_procinfo);
26401.130SmgornyATF_TC_HEAD(core_dump_procinfo, tc)
26411.130Smgorny{
26421.130Smgorny	atf_tc_set_md_var(tc, "descr",
26431.130Smgorny		"Trigger a core dump and verify its contents.");
26441.130Smgorny}
26451.130Smgorny
26461.130SmgornyATF_TC_BODY(core_dump_procinfo, tc)
26471.130Smgorny{
26481.130Smgorny	const int exitval = 5;
26491.130Smgorny	pid_t child, wpid;
26501.130Smgorny#if defined(TWAIT_HAVE_STATUS)
26511.130Smgorny	const int sigval = SIGTRAP;
26521.130Smgorny	int status;
26531.130Smgorny#endif
26541.130Smgorny	char core_path[] = "/tmp/core.XXXXXX";
26551.130Smgorny	int core_fd;
26561.130Smgorny	struct netbsd_elfcore_procinfo procinfo;
26571.130Smgorny
26581.130Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
26591.130Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
26601.130Smgorny	if (child == 0) {
26611.130Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
26621.130Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
26631.130Smgorny
26641.130Smgorny		DPRINTF("Before triggering SIGTRAP\n");
26651.130Smgorny		trigger_trap();
26661.130Smgorny
26671.130Smgorny		DPRINTF("Before exiting of the child process\n");
26681.130Smgorny		_exit(exitval);
26691.130Smgorny	}
26701.130Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
26711.130Smgorny
26721.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
26731.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
26741.130Smgorny
26751.130Smgorny	validate_status_stopped(status, sigval);
26761.130Smgorny
26771.130Smgorny	SYSCALL_REQUIRE((core_fd = mkstemp(core_path)) != -1);
26781.130Smgorny	close(core_fd);
26791.130Smgorny
26801.130Smgorny	DPRINTF("Call DUMPCORE for the child process\n");
26811.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_DUMPCORE, child, core_path, strlen(core_path))
26821.130Smgorny	    != -1);
26831.130Smgorny
26841.130Smgorny	DPRINTF("Read core file\n");
26851.130Smgorny	ATF_REQUIRE_EQ(core_find_note(core_path, "NetBSD-CORE",
26861.130Smgorny	    ELF_NOTE_NETBSD_CORE_PROCINFO, &procinfo, sizeof(procinfo)),
26871.130Smgorny	    sizeof(procinfo));
26881.130Smgorny
26891.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_version, 1);
26901.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_cpisize, sizeof(procinfo));
26911.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_signo, SIGTRAP);
26921.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pid, child);
26931.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ppid, getpid());
26941.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pgrp, getpgid(child));
26951.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_sid, getsid(child));
26961.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ruid, getuid());
26971.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_euid, geteuid());
26981.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_rgid, getgid());
26991.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_egid, getegid());
27001.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_nlwps, 1);
27011.173Skamil	ATF_CHECK(procinfo.cpi_siglwp > 0);
27021.130Smgorny
27031.130Smgorny	unlink(core_path);
27041.130Smgorny
27051.130Smgorny	DPRINTF("Before resuming the child process where it left off and "
27061.130Smgorny	    "without signal to be sent\n");
27071.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
27081.130Smgorny
27091.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
27101.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
27111.130Smgorny
27121.130Smgorny	validate_status_exited(status, exitval);
27131.130Smgorny
27141.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
27151.130Smgorny	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
27161.130Smgorny}
27171.130Smgorny
27181.130Smgorny/// ----------------------------------------------------------------------------
27191.130Smgorny
27201.138Smgorny#if defined(TWAIT_HAVE_STATUS)
27211.138Smgorny
27221.160Smgorny#define THREAD_CONCURRENT_BREAKPOINT_NUM 50
27231.156Smgorny#define THREAD_CONCURRENT_SIGNALS_NUM 50
27241.161Smgorny#define THREAD_CONCURRENT_WATCHPOINT_NUM 50
27251.138Smgorny
27261.138Smgorny/* List of signals to use for the test */
27271.138Smgornyconst int thread_concurrent_signals_list[] = {
27281.138Smgorny	SIGIO,
27291.138Smgorny	SIGXCPU,
27301.138Smgorny	SIGXFSZ,
27311.138Smgorny	SIGVTALRM,
27321.138Smgorny	SIGPROF,
27331.138Smgorny	SIGWINCH,
27341.138Smgorny	SIGINFO,
27351.138Smgorny	SIGUSR1,
27361.138Smgorny	SIGUSR2
27371.138Smgorny};
27381.138Smgorny
27391.157Smgornyenum thread_concurrent_signal_handling {
27401.157Smgorny	/* the signal is discarded by debugger */
27411.157Smgorny	TCSH_DISCARD,
27421.157Smgorny	/* the handler is set to SIG_IGN */
27431.157Smgorny	TCSH_SIG_IGN,
27441.157Smgorny	/* an actual handler is used */
27451.157Smgorny	TCSH_HANDLER
27461.157Smgorny};
27471.157Smgorny
27481.156Smgornystatic pthread_barrier_t thread_concurrent_barrier;
27491.158Smgornystatic pthread_key_t thread_concurrent_key;
27501.161Smgornystatic uint32_t thread_concurrent_watchpoint_var = 0;
27511.138Smgorny
27521.160Smgornystatic void *
27531.160Smgornythread_concurrent_breakpoint_thread(void *arg)
27541.160Smgorny{
27551.160Smgorny	static volatile int watchme = 1;
27561.160Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
27571.160Smgorny	DPRINTF("Before entering breakpoint func from LWP %d\n", _lwp_self());
27581.160Smgorny	check_happy(watchme);
27591.160Smgorny	return NULL;
27601.160Smgorny}
27611.160Smgorny
27621.157Smgornystatic void
27631.157Smgornythread_concurrent_sig_handler(int sig)
27641.157Smgorny{
27651.158Smgorny	void *tls_val = pthread_getspecific(thread_concurrent_key);
27661.158Smgorny	DPRINTF("Before increment, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
27671.158Smgorny	FORKEE_ASSERT(pthread_setspecific(thread_concurrent_key,
27681.158Smgorny	    (void*)((uintptr_t)tls_val + 1)) == 0);
27691.157Smgorny}
27701.157Smgorny
27711.138Smgornystatic void *
27721.138Smgornythread_concurrent_signals_thread(void *arg)
27731.138Smgorny{
27741.138Smgorny	int sigval = thread_concurrent_signals_list[
27751.138Smgorny	    _lwp_self() % __arraycount(thread_concurrent_signals_list)];
27761.158Smgorny	enum thread_concurrent_signal_handling *signal_handle = arg;
27771.158Smgorny	void *tls_val;
27781.158Smgorny
27791.156Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
27801.138Smgorny	DPRINTF("Before raising %s from LWP %d\n", strsignal(sigval),
27811.138Smgorny		_lwp_self());
27821.138Smgorny	pthread_kill(pthread_self(), sigval);
27831.158Smgorny	if (*signal_handle == TCSH_HANDLER) {
27841.158Smgorny	    tls_val = pthread_getspecific(thread_concurrent_key);
27851.158Smgorny	    DPRINTF("After raising, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
27861.158Smgorny	    FORKEE_ASSERT(tls_val == (void*)1);
27871.158Smgorny	}
27881.138Smgorny	return NULL;
27891.138Smgorny}
27901.138Smgorny
27911.161Smgornystatic void *
27921.161Smgornythread_concurrent_watchpoint_thread(void *arg)
27931.161Smgorny{
27941.161Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
27951.161Smgorny	DPRINTF("Before modifying var from LWP %d\n", _lwp_self());
27961.161Smgorny	thread_concurrent_watchpoint_var = 1;
27971.161Smgorny	return NULL;
27981.161Smgorny}
27991.161Smgorny
28001.160Smgorny#if defined(__i386__) || defined(__x86_64__)
28011.160Smgornyenum thread_concurrent_sigtrap_event {
28021.160Smgorny	TCSE_UNKNOWN,
28031.161Smgorny	TCSE_BREAKPOINT,
28041.161Smgorny	TCSE_WATCHPOINT
28051.160Smgorny};
28061.160Smgorny
28071.160Smgornystatic void
28081.160Smgornythread_concurrent_lwp_setup(pid_t child, lwpid_t lwpid);
28091.160Smgornystatic enum thread_concurrent_sigtrap_event
28101.160Smgornythread_concurrent_handle_sigtrap(pid_t child, ptrace_siginfo_t *info);
28111.160Smgorny#endif
28121.160Smgorny
28131.156Smgornystatic void
28141.157Smgornythread_concurrent_test(enum thread_concurrent_signal_handling signal_handle,
28151.161Smgorny    int breakpoint_threads, int signal_threads, int watchpoint_threads)
28161.138Smgorny{
28171.138Smgorny	const int exitval = 5;
28181.138Smgorny	const int sigval = SIGSTOP;
28191.138Smgorny	pid_t child, wpid;
28201.138Smgorny	int status;
28211.141Skamil	struct lwp_event_count signal_counts[THREAD_CONCURRENT_SIGNALS_NUM]
28221.141Skamil	    = {{0, 0}};
28231.160Smgorny	struct lwp_event_count bp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
28241.160Smgorny	    = {{0, 0}};
28251.161Smgorny	struct lwp_event_count wp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
28261.161Smgorny	    = {{0, 0}};
28271.159Smgorny	ptrace_event_t event;
28281.156Smgorny	int i;
28291.156Smgorny
28301.164Skamil#if defined(HAVE_DBREGS)
28311.164Skamil	if (!can_we_set_dbregs()) {
28321.164Skamil		atf_tc_skip("Either run this test as root or set sysctl(3) "
28331.164Skamil		            "security.models.extensions.user_set_dbregs to 1");
28341.164Skamil        }
28351.164Skamil#endif
28361.164Skamil
28371.164Skamil	atf_tc_skip("PR kern/54960");
28381.157Smgorny
28391.156Smgorny	/* Protect against out-of-bounds array access. */
28401.160Smgorny	ATF_REQUIRE(breakpoint_threads <= THREAD_CONCURRENT_BREAKPOINT_NUM);
28411.156Smgorny	ATF_REQUIRE(signal_threads <= THREAD_CONCURRENT_SIGNALS_NUM);
28421.161Smgorny	ATF_REQUIRE(watchpoint_threads <= THREAD_CONCURRENT_WATCHPOINT_NUM);
28431.138Smgorny
28441.138Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
28451.138Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
28461.138Smgorny	if (child == 0) {
28471.160Smgorny		pthread_t bp_threads[THREAD_CONCURRENT_BREAKPOINT_NUM];
28481.156Smgorny		pthread_t sig_threads[THREAD_CONCURRENT_SIGNALS_NUM];
28491.161Smgorny		pthread_t wp_threads[THREAD_CONCURRENT_WATCHPOINT_NUM];
28501.138Smgorny
28511.138Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
28521.138Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
28531.138Smgorny
28541.138Smgorny		DPRINTF("Before raising %s from child\n", strsignal(sigval));
28551.138Smgorny		FORKEE_ASSERT(raise(sigval) == 0);
28561.138Smgorny
28571.157Smgorny		if (signal_handle != TCSH_DISCARD) {
28581.157Smgorny			struct sigaction sa;
28591.157Smgorny			unsigned int j;
28601.157Smgorny
28611.157Smgorny			memset(&sa, 0, sizeof(sa));
28621.157Smgorny			if (signal_handle == TCSH_SIG_IGN)
28631.157Smgorny				sa.sa_handler = SIG_IGN;
28641.157Smgorny			else
28651.157Smgorny				sa.sa_handler = thread_concurrent_sig_handler;
28661.157Smgorny			sigemptyset(&sa.sa_mask);
28671.157Smgorny
28681.157Smgorny			for (j = 0;
28691.157Smgorny			    j < __arraycount(thread_concurrent_signals_list);
28701.157Smgorny			    j++)
28711.157Smgorny				FORKEE_ASSERT(sigaction(
28721.157Smgorny				    thread_concurrent_signals_list[j], &sa, NULL)
28731.157Smgorny				    != -1);
28741.157Smgorny		}
28751.157Smgorny
28761.138Smgorny		DPRINTF("Before starting threads from the child\n");
28771.138Smgorny		FORKEE_ASSERT(pthread_barrier_init(
28781.156Smgorny		    &thread_concurrent_barrier, NULL,
28791.161Smgorny		    breakpoint_threads + signal_threads + watchpoint_threads)
28801.161Smgorny		    == 0);
28811.158Smgorny		FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL)
28821.158Smgorny		    == 0);
28831.138Smgorny
28841.156Smgorny		for (i = 0; i < signal_threads; i++) {
28851.156Smgorny			FORKEE_ASSERT(pthread_create(&sig_threads[i], NULL,
28861.158Smgorny			    thread_concurrent_signals_thread,
28871.158Smgorny			    &signal_handle) == 0);
28881.138Smgorny		}
28891.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
28901.160Smgorny			FORKEE_ASSERT(pthread_create(&bp_threads[i], NULL,
28911.160Smgorny			    thread_concurrent_breakpoint_thread, NULL) == 0);
28921.160Smgorny		}
28931.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
28941.161Smgorny			FORKEE_ASSERT(pthread_create(&wp_threads[i], NULL,
28951.161Smgorny			    thread_concurrent_watchpoint_thread, NULL) == 0);
28961.161Smgorny		}
28971.138Smgorny
28981.138Smgorny		DPRINTF("Before joining threads from the child\n");
28991.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
29001.161Smgorny			FORKEE_ASSERT(pthread_join(wp_threads[i], NULL) == 0);
29011.161Smgorny		}
29021.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
29031.160Smgorny			FORKEE_ASSERT(pthread_join(bp_threads[i], NULL) == 0);
29041.160Smgorny		}
29051.156Smgorny		for (i = 0; i < signal_threads; i++) {
29061.156Smgorny			FORKEE_ASSERT(pthread_join(sig_threads[i], NULL) == 0);
29071.138Smgorny		}
29081.138Smgorny
29091.158Smgorny		FORKEE_ASSERT(pthread_key_delete(thread_concurrent_key) == 0);
29101.138Smgorny		FORKEE_ASSERT(pthread_barrier_destroy(
29111.156Smgorny		    &thread_concurrent_barrier) == 0);
29121.138Smgorny
29131.138Smgorny		DPRINTF("Before exiting of the child process\n");
29141.138Smgorny		_exit(exitval);
29151.138Smgorny	}
29161.138Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
29171.138Smgorny
29181.138Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29191.138Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
29201.138Smgorny
29211.138Smgorny	validate_status_stopped(status, sigval);
29221.138Smgorny
29231.159Smgorny	DPRINTF("Set LWP event mask for the child process\n");
29241.159Smgorny	memset(&event, 0, sizeof(event));
29251.159Smgorny	event.pe_set_event |= PTRACE_LWP_CREATE;
29261.159Smgorny	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, sizeof(event))
29271.159Smgorny	    != -1);
29281.159Smgorny
29291.138Smgorny	DPRINTF("Before resuming the child process where it left off\n");
29301.138Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
29311.138Smgorny
29321.138Smgorny	DPRINTF("Before entering signal collection loop\n");
29331.138Smgorny	while (1) {
29341.138Smgorny		ptrace_siginfo_t info;
29351.138Smgorny
29361.138Smgorny		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29371.138Smgorny		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
29381.138Smgorny		    child);
29391.138Smgorny		if (WIFEXITED(status))
29401.138Smgorny			break;
29411.138Smgorny		/* Note: we use validate_status_stopped() to get nice error
29421.138Smgorny		 * message.  Signal is irrelevant since it won't be reached.
29431.138Smgorny		 */
29441.138Smgorny		else if (!WIFSTOPPED(status))
29451.138Smgorny			validate_status_stopped(status, 0);
29461.138Smgorny
29471.138Smgorny		DPRINTF("Before calling PT_GET_SIGINFO\n");
29481.138Smgorny		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
29491.138Smgorny		    sizeof(info)) != -1);
29501.138Smgorny
29511.138Smgorny		DPRINTF("Received signal %d from LWP %d (wait: %d)\n",
29521.138Smgorny		    info.psi_siginfo.si_signo, info.psi_lwpid,
29531.138Smgorny		    WSTOPSIG(status));
29541.138Smgorny
29551.159Smgorny		ATF_CHECK_EQ_MSG(info.psi_siginfo.si_signo, WSTOPSIG(status),
29561.159Smgorny		    "lwp=%d, WSTOPSIG=%d, psi_siginfo=%d", info.psi_lwpid,
29571.159Smgorny		    WSTOPSIG(status), info.psi_siginfo.si_signo);
29581.159Smgorny
29591.159Smgorny		if (WSTOPSIG(status) != SIGTRAP) {
29601.159Smgorny			int expected_sig =
29611.159Smgorny			    thread_concurrent_signals_list[info.psi_lwpid %
29621.159Smgorny			    __arraycount(thread_concurrent_signals_list)];
29631.159Smgorny			ATF_CHECK_EQ_MSG(WSTOPSIG(status), expected_sig,
29641.159Smgorny				"lwp=%d, expected %d, got %d", info.psi_lwpid,
29651.159Smgorny				expected_sig, WSTOPSIG(status));
29661.138Smgorny
29671.159Smgorny			*FIND_EVENT_COUNT(signal_counts, info.psi_lwpid) += 1;
29681.160Smgorny		} else if (info.psi_siginfo.si_code == TRAP_LWP) {
29691.160Smgorny#if defined(__i386__) || defined(__x86_64__)
29701.160Smgorny			thread_concurrent_lwp_setup(child, info.psi_lwpid);
29711.160Smgorny#endif
29721.159Smgorny		} else {
29731.160Smgorny#if defined(__i386__) || defined(__x86_64__)
29741.160Smgorny			switch (thread_concurrent_handle_sigtrap(child, &info)) {
29751.160Smgorny				case TCSE_UNKNOWN:
29761.160Smgorny					/* already reported inside the function */
29771.160Smgorny					break;
29781.160Smgorny				case TCSE_BREAKPOINT:
29791.160Smgorny					*FIND_EVENT_COUNT(bp_counts,
29801.160Smgorny					    info.psi_lwpid) += 1;
29811.160Smgorny					break;
29821.161Smgorny				case TCSE_WATCHPOINT:
29831.161Smgorny					*FIND_EVENT_COUNT(wp_counts,
29841.161Smgorny					    info.psi_lwpid) += 1;
29851.161Smgorny					break;
29861.160Smgorny			}
29871.160Smgorny#else
29881.160Smgorny			ATF_CHECK_MSG(0, "Unexpected SIGTRAP, si_code=%d\n",
29891.160Smgorny			    info.psi_siginfo.si_code);
29901.160Smgorny#endif
29911.159Smgorny		}
29921.138Smgorny
29931.138Smgorny		DPRINTF("Before resuming the child process\n");
29941.157Smgorny		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
29951.159Smgorny		     signal_handle != TCSH_DISCARD && WSTOPSIG(status) != SIGTRAP
29961.159Smgorny		     ? WSTOPSIG(status) : 0) != -1);
29971.138Smgorny	}
29981.138Smgorny
29991.156Smgorny	for (i = 0; i < signal_threads; i++)
30001.141Skamil		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 1,
30011.141Skamil		    "signal_counts[%d].lec_count=%d; lec_lwp=%d",
30021.141Skamil		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
30031.156Smgorny	for (i = signal_threads; i < THREAD_CONCURRENT_SIGNALS_NUM; i++)
30041.156Smgorny		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 0,
30051.156Smgorny		    "extraneous signal_counts[%d].lec_count=%d; lec_lwp=%d",
30061.156Smgorny		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
30071.138Smgorny
30081.160Smgorny	for (i = 0; i < breakpoint_threads; i++)
30091.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 1,
30101.160Smgorny		    "bp_counts[%d].lec_count=%d; lec_lwp=%d",
30111.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
30121.160Smgorny	for (i = breakpoint_threads; i < THREAD_CONCURRENT_BREAKPOINT_NUM; i++)
30131.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 0,
30141.160Smgorny		    "extraneous bp_counts[%d].lec_count=%d; lec_lwp=%d",
30151.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
30161.160Smgorny
30171.161Smgorny	for (i = 0; i < watchpoint_threads; i++)
30181.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 1,
30191.161Smgorny		    "wp_counts[%d].lec_count=%d; lec_lwp=%d",
30201.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
30211.161Smgorny	for (i = watchpoint_threads; i < THREAD_CONCURRENT_WATCHPOINT_NUM; i++)
30221.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 0,
30231.161Smgorny		    "extraneous wp_counts[%d].lec_count=%d; lec_lwp=%d",
30241.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
30251.161Smgorny
30261.138Smgorny	validate_status_exited(status, exitval);
30271.138Smgorny}
30281.138Smgorny
30291.161Smgorny#define THREAD_CONCURRENT_TEST(test, sig_hdl, bps, sigs, wps, descr)	\
30301.156SmgornyATF_TC(test);								\
30311.156SmgornyATF_TC_HEAD(test, tc)							\
30321.156Smgorny{									\
30331.156Smgorny	atf_tc_set_md_var(tc, "descr", descr);				\
30341.156Smgorny}									\
30351.156Smgorny									\
30361.156SmgornyATF_TC_BODY(test, tc)							\
30371.156Smgorny{									\
30381.161Smgorny	thread_concurrent_test(sig_hdl, bps, sigs, wps);		\
30391.156Smgorny}
30401.156Smgorny
30411.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals, TCSH_DISCARD,
30421.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
30431.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
30441.157Smgorny    "correctly");
30451.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_sig_ign, TCSH_SIG_IGN,
30461.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
30471.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
30481.157Smgorny    "correctly and passed back to SIG_IGN handler");
30491.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_handler, TCSH_HANDLER,
30501.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
30511.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
30521.157Smgorny    "correctly and passed back to a handler function");
30531.156Smgorny
30541.163Skamil#if defined(__i386__) || defined(__x86_64__)
30551.160SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_breakpoints, TCSH_DISCARD,
30561.161Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, 0,
30571.161Smgorny    "Verify that concurrent breakpoints are reported correctly");
30581.161SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_watchpoints, TCSH_DISCARD,
30591.161Smgorny    0, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
30601.160Smgorny    "Verify that concurrent breakpoints are reported correctly");
30611.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp, TCSH_DISCARD,
30621.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
30631.162Smgorny    "Verify that concurrent breakpoints and watchpoints are reported "
30641.162Smgorny    "correctly");
30651.162Smgorny
30661.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig, TCSH_DISCARD,
30671.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
30681.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly");
30691.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_sig_ign, TCSH_SIG_IGN,
30701.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
30711.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
30721.162Smgorny    "and passed back to SIG_IGN handler");
30731.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_handler, TCSH_HANDLER,
30741.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
30751.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
30761.162Smgorny    "and passed back to a handler function");
30771.162Smgorny
30781.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig, TCSH_DISCARD,
30791.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
30801.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly");
30811.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_sig_ign, TCSH_SIG_IGN,
30821.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
30831.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
30841.162Smgorny    "and passed back to SIG_IGN handler");
30851.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_handler, TCSH_HANDLER,
30861.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
30871.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
30881.162Smgorny    "and passed back to a handler function");
30891.162Smgorny
30901.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig, TCSH_DISCARD,
30911.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
30921.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
30931.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
30941.162Smgorny    "correctly");
30951.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_sig_ign, TCSH_SIG_IGN,
30961.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
30971.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
30981.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
30991.162Smgorny    "correctly and passed back to SIG_IGN handler");
31001.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_handler, TCSH_HANDLER,
31011.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
31021.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
31031.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
31041.162Smgorny    "correctly and passed back to a handler function");
31051.163Skamil#endif
31061.160Smgorny
31071.138Smgorny#endif /*defined(TWAIT_HAVE_STATUS)*/
31081.138Smgorny
31091.138Smgorny/// ----------------------------------------------------------------------------
31101.138Smgorny
31111.174Skamil#include "t_ptrace_register_wait.h"
31121.175Skamil#include "t_ptrace_syscall_wait.h"
31131.176Skamil#include "t_ptrace_step_wait.h"
31141.177Skamil#include "t_ptrace_kill_wait.h"
31151.178Skamil#include "t_ptrace_bytetransfer_wait.h"
31161.179Skamil#include "t_ptrace_clone_wait.h"
31171.180Skamil#include "t_ptrace_fork_wait.h"
31181.181Skamil#include "t_ptrace_signal_wait.h"
31191.183Skamil#include "t_ptrace_eventmask_wait.h"
31201.174Skamil
31211.174Skamil/// ----------------------------------------------------------------------------
31221.174Skamil
31231.1Skamil#include "t_ptrace_amd64_wait.h"
31241.1Skamil#include "t_ptrace_i386_wait.h"
31251.1Skamil#include "t_ptrace_x86_wait.h"
31261.1Skamil
31271.165Skamil/// ----------------------------------------------------------------------------
31281.165Skamil
31291.165Skamil#else
31301.165SkamilATF_TC(dummy);
31311.165SkamilATF_TC_HEAD(dummy, tc)
31321.165Skamil{
31331.165Skamil	atf_tc_set_md_var(tc, "descr", "A dummy test");
31341.165Skamil}
31351.165Skamil
31361.165SkamilATF_TC_BODY(dummy, tc)
31371.165Skamil{
31381.165Skamil
31391.165Skamil	// Dummy, skipped
31401.165Skamil	// The ATF framework requires at least a single defined test.
31411.165Skamil}
31421.165Skamil#endif
31431.165Skamil
31441.1SkamilATF_TP_ADD_TCS(tp)
31451.1Skamil{
31461.1Skamil	setvbuf(stdout, NULL, _IONBF, 0);
31471.1Skamil	setvbuf(stderr, NULL, _IONBF, 0);
31481.33Skamil
31491.165Skamil#ifdef ENABLE_TESTS
31501.37Skamil	ATF_TP_ADD_TC(tp, traceme_pid1_parent);
31511.37Skamil
31521.43Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_exec);
31531.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_exec);
31541.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_exec);
31551.43Skamil
31561.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sees_terminaton_before_the_parent);
31571.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sysctl_lookup_without_duplicates);
31581.61Skre	ATF_TP_ADD_TC_HAVE_PID(tp,
31591.61Skre		unrelated_tracer_sees_terminaton_before_the_parent);
31601.67Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_attach_to_unrelated_stopped_process);
31611.51Skamil
31621.51Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_child);
31631.66Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_stopped_child);
31641.51Skamil
31651.51Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_parent);
31661.65Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_stopped_parent);
31671.51Skamil
31681.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
31691.51Skamil		tracee_sees_its_original_parent_getppid);
31701.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
31711.51Skamil		tracee_sees_its_original_parent_sysctl_kinfo_proc2);
31721.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
31731.51Skamil		tracee_sees_its_original_parent_procfs_status);
31741.1Skamil
31751.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_empty);
31761.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_fork);
31771.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork);
31781.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork_done);
31791.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_create);
31801.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_exit);
31811.125Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_posix_spawn);
31821.1Skamil
31831.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0);
31841.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1);
31851.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2);
31861.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3);
31871.77Skamil
31881.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus);
31891.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus);
31901.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus);
31911.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus);
31921.143Skamil
31931.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_sigmask);
31941.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_sigmask);
31951.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_sigmask);
31961.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_sigmask);
31971.143Skamil
31981.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_name);
31991.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_name);
32001.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_name);
32011.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_name);
32021.143Skamil
32031.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_private);
32041.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_private);
32051.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_private);
32061.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_private);
32071.143Skamil
32081.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0);
32091.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1);
32101.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2);
32111.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3);
32121.143Skamil
32131.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_sigmask);
32141.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_sigmask);
32151.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_sigmask);
32161.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_sigmask);
32171.143Skamil
32181.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_name);
32191.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_name);
32201.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_name);
32211.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_name);
32221.143Skamil
32231.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_private);
32241.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_private);
32251.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_private);
32261.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_private);
32271.143Skamil
32281.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo0);
32291.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo1);
32301.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo2);
32311.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo3);
32321.1Skamil
32331.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_unmodified);
32341.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_faked);
32351.79Skamil
32361.82Skamil	ATF_TP_ADD_TC(tp, traceme_exec);
32371.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_exec);
32381.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_exec);
32391.1Skamil
32401.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_nolwpevents);
32411.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit);
32421.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate);
32431.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit);
32441.1Skamil
32451.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit_masked_sigtrap);
32461.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_masked_sigtrap);
32471.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit_masked_sigtrap);
32481.153Skamil
32491.151Skamil	ATF_TP_ADD_TC(tp, threads_and_exec);
32501.151Skamil
32511.154Skamil	ATF_TP_ADD_TC(tp, suspend_no_deadlock);
32521.1Skamil
32531.155Skamil	ATF_TP_ADD_TC(tp, resume);
32541.1Skamil
32551.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_continue);
32561.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall);
32571.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach);
32581.122Skamil
32591.130Smgorny	ATF_TP_ADD_TC(tp, core_dump_procinfo);
32601.130Smgorny
32611.138Smgorny#if defined(TWAIT_HAVE_STATUS)
32621.138Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals);
32631.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_sig_ign);
32641.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_handler);
32651.160Smgorny#if defined(__i386__) || defined(__x86_64__)
32661.160Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_breakpoints);
32671.161Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_watchpoints);
32681.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp);
32691.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig);
32701.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_sig_ign);
32711.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_handler);
32721.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig);
32731.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_sig_ign);
32741.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_handler);
32751.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig);
32761.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_sig_ign);
32771.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_handler);
32781.160Smgorny#endif
32791.138Smgorny#endif
32801.138Smgorny
32811.174Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_REGISTER();
32821.175Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_SYSCALL();
32831.176Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_STEP();
32841.177Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_KILL();
32851.178Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_BYTETRANSFER();
32861.179Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_CLONE();
32871.180Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_FORK();
32881.181Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_SIGNAL();
32891.183Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_EVENTMASK();
32901.174Skamil
32911.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
32921.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_I386();
32931.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_X86();
32941.1Skamil
32951.165Skamil#else
32961.165Skamil	ATF_TP_ADD_TC(tp, dummy);
32971.165Skamil#endif
32981.165Skamil
32991.1Skamil	return atf_no_error();
33001.1Skamil}
3301