t_ptrace_wait.c revision 1.165
11.165Skamil/*	$NetBSD: t_ptrace_wait.c,v 1.165 2020/02/22 19:44:07 kamil Exp $	*/
21.1Skamil
31.1Skamil/*-
41.78Skamil * Copyright (c) 2016, 2017, 2018, 2019 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.165Skamil__RCSID("$NetBSD: t_ptrace_wait.c,v 1.165 2020/02/22 19:44:07 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.114Skamil#include <fenv.h>
641.114Skamil#if (__arm__ && !__SOFTFP__) || __aarch64__
651.114Skamil#include <ieeefp.h> /* only need for ARM Cortex/Neon hack */
661.114Skamil#endif
671.114Skamil
681.121Smgorny#if defined(__i386__) || defined(__x86_64__)
691.121Smgorny#include <cpuid.h>
701.121Smgorny#include <x86/cpu_extended_state.h>
711.129Smgorny#include <x86/specialreg.h>
721.121Smgorny#endif
731.121Smgorny
741.130Smgorny#include <libelf.h>
751.130Smgorny#include <gelf.h>
761.130Smgorny
771.1Skamil#include <atf-c.h>
781.1Skamil
791.165Skamil#ifdef ENABLE_TESTS
801.165Skamil
811.132Skamil/* Assumptions in the kernel code that must be kept. */
821.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_report_event) ==
831.132Skamil    sizeof(((siginfo_t *)0)->si_pe_report_event),
841.132Skamil    "pe_report_event and si_pe_report_event must be of the same size");
851.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_other_pid) ==
861.132Skamil    sizeof(((siginfo_t *)0)->si_pe_other_pid),
871.132Skamil    "pe_other_pid and si_pe_other_pid must be of the same size");
881.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_lwp) ==
891.132Skamil    sizeof(((siginfo_t *)0)->si_pe_lwp),
901.132Skamil    "pe_lwp and si_pe_lwp must be of the same size");
911.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_other_pid) ==
921.132Skamil    sizeof(((struct ptrace_state *)0)->pe_lwp),
931.132Skamil    "pe_other_pid and pe_lwp must be of the same size");
941.132Skamil
951.1Skamil#include "h_macros.h"
961.1Skamil
971.1Skamil#include "t_ptrace_wait.h"
981.1Skamil#include "msg.h"
991.1Skamil
1001.1Skamil#define PARENT_TO_CHILD(info, fds, msg) \
1011.61Skre    SYSCALL_REQUIRE(msg_write_child(info " to child " # fds, &fds, &msg, \
1021.61Skre	sizeof(msg)) == 0)
1031.1Skamil
1041.1Skamil#define CHILD_FROM_PARENT(info, fds, msg) \
1051.61Skre    FORKEE_ASSERT(msg_read_parent(info " from parent " # fds, &fds, &msg, \
1061.61Skre	sizeof(msg)) == 0)
1071.1Skamil
1081.1Skamil#define CHILD_TO_PARENT(info, fds, msg) \
1091.61Skre    FORKEE_ASSERT(msg_write_parent(info " to parent " # fds, &fds, &msg, \
1101.61Skre	sizeof(msg)) == 0)
1111.1Skamil
1121.1Skamil#define PARENT_FROM_CHILD(info, fds, msg) \
1131.61Skre    SYSCALL_REQUIRE(msg_read_child(info " from parent " # fds, &fds, &msg, \
1141.61Skre	sizeof(msg)) == 0)
1151.13Schristos
1161.13Schristos#define SYSCALL_REQUIRE(expr) ATF_REQUIRE_MSG(expr, "%s: %s", # expr, \
1171.13Schristos    strerror(errno))
1181.18Schristos#define SYSCALL_REQUIRE_ERRNO(res, exp) ATF_REQUIRE_MSG(res == exp, \
1191.18Schristos    "%d(%s) != %d", res, strerror(res), exp)
1201.13Schristos
1211.152Skamilstatic int debug = 0;
1221.13Schristos
1231.13Schristos#define DPRINTF(a, ...)	do  \
1241.123Skamil	if (debug) \
1251.142Skamil	printf("%s() %d.%d %s:%d " a, \
1261.142Skamil	__func__, getpid(), _lwp_self(), __FILE__, __LINE__,  ##__VA_ARGS__); \
1271.13Schristos    while (/*CONSTCOND*/0)
1281.1Skamil
1291.34Skamil/// ----------------------------------------------------------------------------
1301.34Skamil
1311.33Skamilstatic void
1321.33Skamiltraceme_raise(int sigval)
1331.1Skamil{
1341.1Skamil	const int exitval = 5;
1351.1Skamil	pid_t child, wpid;
1361.1Skamil#if defined(TWAIT_HAVE_STATUS)
1371.1Skamil	int status;
1381.1Skamil#endif
1391.1Skamil
1401.133Skamil	ptrace_state_t state, zero_state;
1411.133Skamil	const int slen = sizeof(state);
1421.45Skamil	struct ptrace_siginfo info;
1431.133Skamil	memset(&zero_state, 0, sizeof(zero_state));
1441.45Skamil	memset(&info, 0, sizeof(info));
1451.45Skamil
1461.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
1471.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
1481.1Skamil	if (child == 0) {
1491.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1501.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
1511.1Skamil
1521.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
1531.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
1541.1Skamil
1551.36Skamil		switch (sigval) {
1561.36Skamil		case SIGKILL:
1571.36Skamil			/* NOTREACHED */
1581.36Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
1591.70Smrg			__unreachable();
1601.36Skamil		default:
1611.36Skamil			DPRINTF("Before exiting of the child process\n");
1621.36Skamil			_exit(exitval);
1631.36Skamil		}
1641.1Skamil	}
1651.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
1661.1Skamil
1671.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1681.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
1691.1Skamil
1701.36Skamil	switch (sigval) {
1711.36Skamil	case SIGKILL:
1721.36Skamil		validate_status_signaled(status, sigval, 0);
1731.133Skamil		SYSCALL_REQUIRE(
1741.133Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) == -1);
1751.133Skamil
1761.36Skamil		break;
1771.36Skamil	default:
1781.36Skamil		validate_status_stopped(status, sigval);
1791.1Skamil
1801.45Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
1811.61Skre			"child\n");
1821.45Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
1831.61Skre			sizeof(info)) != -1);
1841.45Skamil
1851.45Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
1861.45Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
1871.61Skre			"si_errno=%#x\n",
1881.61Skre			info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
1891.61Skre			info.psi_siginfo.si_errno);
1901.45Skamil
1911.45Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
1921.45Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
1931.45Skamil
1941.133Skamil		DPRINTF("Assert that PT_GET_PROCESS_STATE returns non-error");
1951.133Skamil		SYSCALL_REQUIRE(
1961.133Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
1971.133Skamil		ATF_REQUIRE(memcmp(&state, &zero_state, slen) == 0);
1981.133Skamil
1991.36Skamil		DPRINTF("Before resuming the child process where it left off "
2001.36Skamil		    "and without signal to be sent\n");
2011.36Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
2021.1Skamil
2031.36Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2041.36Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
2051.61Skre		    child);
2061.36Skamil		break;
2071.36Skamil	}
2081.1Skamil
2091.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2101.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
2111.1Skamil}
2121.1Skamil
2131.61Skre#define TRACEME_RAISE(test, sig)					\
2141.61SkreATF_TC(test);								\
2151.61SkreATF_TC_HEAD(test, tc)							\
2161.61Skre{									\
2171.61Skre	atf_tc_set_md_var(tc, "descr",					\
2181.61Skre	    "Verify " #sig " followed by _exit(2) in a child");		\
2191.61Skre}									\
2201.61Skre									\
2211.61SkreATF_TC_BODY(test, tc)							\
2221.61Skre{									\
2231.61Skre									\
2241.61Skre	traceme_raise(sig);						\
2251.33Skamil}
2261.33Skamil
2271.36SkamilTRACEME_RAISE(traceme_raise1, SIGKILL) /* non-maskable */
2281.33SkamilTRACEME_RAISE(traceme_raise2, SIGSTOP) /* non-maskable */
2291.33SkamilTRACEME_RAISE(traceme_raise3, SIGABRT) /* regular abort trap */
2301.33SkamilTRACEME_RAISE(traceme_raise4, SIGHUP)  /* hangup */
2311.33SkamilTRACEME_RAISE(traceme_raise5, SIGCONT) /* continued? */
2321.85SkamilTRACEME_RAISE(traceme_raise6, SIGTRAP) /* crash signal */
2331.85SkamilTRACEME_RAISE(traceme_raise7, SIGBUS) /* crash signal */
2341.85SkamilTRACEME_RAISE(traceme_raise8, SIGILL) /* crash signal */
2351.85SkamilTRACEME_RAISE(traceme_raise9, SIGFPE) /* crash signal */
2361.85SkamilTRACEME_RAISE(traceme_raise10, SIGSEGV) /* crash signal */
2371.33Skamil
2381.34Skamil/// ----------------------------------------------------------------------------
2391.1Skamil
2401.1Skamilstatic void
2411.87Skamiltraceme_raisesignal_ignored(int sigignored)
2421.87Skamil{
2431.87Skamil	const int exitval = 5;
2441.87Skamil	const int sigval = SIGSTOP;
2451.87Skamil	pid_t child, wpid;
2461.87Skamil	struct sigaction sa;
2471.87Skamil#if defined(TWAIT_HAVE_STATUS)
2481.87Skamil	int status;
2491.87Skamil#endif
2501.87Skamil	struct ptrace_siginfo info;
2511.87Skamil
2521.87Skamil	memset(&info, 0, sizeof(info));
2531.87Skamil
2541.87Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
2551.87Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
2561.87Skamil	if (child == 0) {
2571.87Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
2581.87Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
2591.87Skamil
2601.87Skamil		memset(&sa, 0, sizeof(sa));
2611.87Skamil		sa.sa_handler = SIG_IGN;
2621.87Skamil		sigemptyset(&sa.sa_mask);
2631.87Skamil		FORKEE_ASSERT(sigaction(sigignored, &sa, NULL) != -1);
2641.87Skamil
2651.87Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
2661.87Skamil		FORKEE_ASSERT(raise(sigval) == 0);
2671.87Skamil
2681.87Skamil		DPRINTF("Before raising %s from child\n",
2691.87Skamil		    strsignal(sigignored));
2701.87Skamil		FORKEE_ASSERT(raise(sigignored) == 0);
2711.87Skamil
2721.87Skamil		DPRINTF("Before exiting of the child process\n");
2731.87Skamil		_exit(exitval);
2741.87Skamil	}
2751.87Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
2761.87Skamil
2771.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2781.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2791.87Skamil
2801.87Skamil	validate_status_stopped(status, sigval);
2811.87Skamil
2821.87Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
2831.87Skamil	SYSCALL_REQUIRE(
2841.87Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
2851.87Skamil
2861.87Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
2871.87Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
2881.87Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
2891.87Skamil	    info.psi_siginfo.si_errno);
2901.87Skamil
2911.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
2921.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
2931.87Skamil
2941.87Skamil	DPRINTF("Before resuming the child process where it left off and "
2951.87Skamil	    "without signal to be sent\n");
2961.87Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
2971.87Skamil
2981.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2991.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
3001.87Skamil
3011.87Skamil	validate_status_stopped(status, sigignored);
3021.87Skamil
3031.87Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
3041.87Skamil	SYSCALL_REQUIRE(
3051.87Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
3061.87Skamil
3071.87Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
3081.87Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
3091.87Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
3101.87Skamil	    info.psi_siginfo.si_errno);
3111.87Skamil
3121.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigignored);
3131.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
3141.87Skamil
3151.87Skamil	DPRINTF("Before resuming the child process where it left off and "
3161.87Skamil	    "without signal to be sent\n");
3171.87Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
3181.87Skamil
3191.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3201.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
3211.87Skamil
3221.87Skamil	validate_status_exited(status, exitval);
3231.87Skamil
3241.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3251.87Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
3261.87Skamil}
3271.87Skamil
3281.87Skamil#define TRACEME_RAISESIGNAL_IGNORED(test, sig)				\
3291.87SkamilATF_TC(test);								\
3301.87SkamilATF_TC_HEAD(test, tc)							\
3311.87Skamil{									\
3321.87Skamil	atf_tc_set_md_var(tc, "descr",					\
3331.87Skamil	    "Verify that ignoring (with SIG_IGN) " #sig " in tracee "	\
3341.87Skamil	    "does not stop tracer from catching this raised signal");	\
3351.87Skamil}									\
3361.87Skamil									\
3371.87SkamilATF_TC_BODY(test, tc)							\
3381.87Skamil{									\
3391.87Skamil									\
3401.87Skamil	traceme_raisesignal_ignored(sig);				\
3411.87Skamil}
3421.87Skamil
3431.87Skamil// A signal handler for SIGKILL and SIGSTOP cannot be ignored.
3441.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored1, SIGABRT) /* abort */
3451.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored2, SIGHUP)  /* hangup */
3461.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored3, SIGCONT) /* cont. */
3471.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored4, SIGTRAP) /* crash */
3481.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored5, SIGBUS) /* crash */
3491.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored6, SIGILL) /* crash */
3501.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored7, SIGFPE) /* crash */
3511.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored8, SIGSEGV) /* crash */
3521.87Skamil
3531.87Skamil/// ----------------------------------------------------------------------------
3541.87Skamil
3551.87Skamilstatic void
3561.86Skamiltraceme_raisesignal_masked(int sigmasked)
3571.86Skamil{
3581.86Skamil	const int exitval = 5;
3591.86Skamil	const int sigval = SIGSTOP;
3601.86Skamil	pid_t child, wpid;
3611.86Skamil#if defined(TWAIT_HAVE_STATUS)
3621.86Skamil	int status;
3631.86Skamil#endif
3641.86Skamil	sigset_t intmask;
3651.86Skamil	struct ptrace_siginfo info;
3661.86Skamil
3671.86Skamil	memset(&info, 0, sizeof(info));
3681.86Skamil
3691.86Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
3701.86Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
3711.86Skamil	if (child == 0) {
3721.86Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
3731.86Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
3741.86Skamil
3751.86Skamil		sigemptyset(&intmask);
3761.86Skamil		sigaddset(&intmask, sigmasked);
3771.86Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
3781.86Skamil
3791.86Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
3801.86Skamil		FORKEE_ASSERT(raise(sigval) == 0);
3811.86Skamil
3821.86Skamil		DPRINTF("Before raising %s breakpoint from child\n",
3831.86Skamil		    strsignal(sigmasked));
3841.86Skamil		FORKEE_ASSERT(raise(sigmasked) == 0);
3851.86Skamil
3861.86Skamil		DPRINTF("Before exiting of the child process\n");
3871.86Skamil		_exit(exitval);
3881.86Skamil	}
3891.86Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
3901.86Skamil
3911.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3921.86Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
3931.86Skamil
3941.86Skamil	validate_status_stopped(status, sigval);
3951.86Skamil
3961.86Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
3971.86Skamil	SYSCALL_REQUIRE(
3981.86Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
3991.86Skamil
4001.86Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
4011.86Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
4021.86Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
4031.86Skamil	    info.psi_siginfo.si_errno);
4041.86Skamil
4051.86Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
4061.86Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
4071.86Skamil
4081.86Skamil	DPRINTF("Before resuming the child process where it left off and "
4091.86Skamil	    "without signal to be sent\n");
4101.86Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
4111.86Skamil
4121.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
4131.86Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
4141.86Skamil
4151.86Skamil	validate_status_exited(status, exitval);
4161.86Skamil
4171.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
4181.86Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
4191.86Skamil}
4201.86Skamil
4211.86Skamil#define TRACEME_RAISESIGNAL_MASKED(test, sig)				\
4221.86SkamilATF_TC(test);								\
4231.86SkamilATF_TC_HEAD(test, tc)							\
4241.86Skamil{									\
4251.86Skamil	atf_tc_set_md_var(tc, "descr",					\
4261.86Skamil	    "Verify that masking (with SIG_BLOCK) " #sig " in tracee "	\
4271.86Skamil	    "stops tracer from catching this raised signal");		\
4281.86Skamil}									\
4291.86Skamil									\
4301.86SkamilATF_TC_BODY(test, tc)							\
4311.86Skamil{									\
4321.86Skamil									\
4331.86Skamil	traceme_raisesignal_masked(sig);				\
4341.86Skamil}
4351.86Skamil
4361.86Skamil// A signal handler for SIGKILL and SIGSTOP cannot be masked.
4371.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked1, SIGABRT) /* abort trap */
4381.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked2, SIGHUP)  /* hangup */
4391.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked3, SIGCONT) /* continued? */
4401.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked4, SIGTRAP) /* crash sig. */
4411.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked5, SIGBUS) /* crash sig. */
4421.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked6, SIGILL) /* crash sig. */
4431.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked7, SIGFPE) /* crash sig. */
4441.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked8, SIGSEGV) /* crash sig. */
4451.86Skamil
4461.86Skamil/// ----------------------------------------------------------------------------
4471.86Skamil
4481.86Skamilstatic void
4491.59Skamiltraceme_crash(int sig)
4501.59Skamil{
4511.59Skamil	pid_t child, wpid;
4521.59Skamil#if defined(TWAIT_HAVE_STATUS)
4531.59Skamil	int status;
4541.59Skamil#endif
4551.59Skamil	struct ptrace_siginfo info;
4561.61Skre
4571.71Skamil#ifndef PTRACE_ILLEGAL_ASM
4581.71Skamil	if (sig == SIGILL)
4591.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
4601.71Skamil#endif
4611.71Skamil
4621.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
4631.114Skamil		atf_tc_skip("FP exceptions are not supported");
4641.114Skamil
4651.59Skamil	memset(&info, 0, sizeof(info));
4661.59Skamil
4671.59Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
4681.59Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
4691.59Skamil	if (child == 0) {
4701.59Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
4711.59Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
4721.59Skamil
4731.59Skamil		DPRINTF("Before executing a trap\n");
4741.59Skamil		switch (sig) {
4751.59Skamil		case SIGTRAP:
4761.59Skamil			trigger_trap();
4771.59Skamil			break;
4781.59Skamil		case SIGSEGV:
4791.59Skamil			trigger_segv();
4801.59Skamil			break;
4811.59Skamil		case SIGILL:
4821.59Skamil			trigger_ill();
4831.59Skamil			break;
4841.59Skamil		case SIGFPE:
4851.59Skamil			trigger_fpe();
4861.59Skamil			break;
4871.59Skamil		case SIGBUS:
4881.59Skamil			trigger_bus();
4891.59Skamil			break;
4901.59Skamil		default:
4911.59Skamil			/* NOTREACHED */
4921.59Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
4931.59Skamil		}
4941.59Skamil
4951.59Skamil		/* NOTREACHED */
4961.59Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
4971.59Skamil	}
4981.59Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
4991.59Skamil
5001.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5011.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
5021.59Skamil
5031.59Skamil	validate_status_stopped(status, sig);
5041.59Skamil
5051.59Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
5061.61Skre	SYSCALL_REQUIRE(
5071.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
5081.59Skamil
5091.59Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
5101.59Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
5111.61Skre	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
5121.61Skre	    info.psi_siginfo.si_errno);
5131.59Skamil
5141.59Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
5151.59Skamil	switch (sig) {
5161.59Skamil	case SIGTRAP:
5171.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
5181.59Skamil		break;
5191.59Skamil	case SIGSEGV:
5201.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
5211.59Skamil		break;
5221.71Skamil	case SIGILL:
5231.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
5241.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
5251.71Skamil		break;
5261.59Skamil	case SIGFPE:
5271.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
5281.59Skamil		break;
5291.59Skamil	case SIGBUS:
5301.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
5311.59Skamil		break;
5321.59Skamil	}
5331.59Skamil
5341.59Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
5351.59Skamil
5361.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5371.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
5381.59Skamil
5391.59Skamil	validate_status_signaled(status, SIGKILL, 0);
5401.59Skamil
5411.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5421.59Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
5431.59Skamil}
5441.59Skamil
5451.61Skre#define TRACEME_CRASH(test, sig)					\
5461.61SkreATF_TC(test);								\
5471.61SkreATF_TC_HEAD(test, tc)							\
5481.61Skre{									\
5491.61Skre	atf_tc_set_md_var(tc, "descr",					\
5501.61Skre	    "Verify crash signal " #sig " in a child after PT_TRACE_ME"); \
5511.61Skre}									\
5521.61Skre									\
5531.61SkreATF_TC_BODY(test, tc)							\
5541.61Skre{									\
5551.61Skre									\
5561.61Skre	traceme_crash(sig);						\
5571.59Skamil}
5581.59Skamil
5591.59SkamilTRACEME_CRASH(traceme_crash_trap, SIGTRAP)
5601.59SkamilTRACEME_CRASH(traceme_crash_segv, SIGSEGV)
5611.71SkamilTRACEME_CRASH(traceme_crash_ill, SIGILL)
5621.59SkamilTRACEME_CRASH(traceme_crash_fpe, SIGFPE)
5631.59SkamilTRACEME_CRASH(traceme_crash_bus, SIGBUS)
5641.59Skamil
5651.59Skamil/// ----------------------------------------------------------------------------
5661.59Skamil
5671.59Skamilstatic void
5681.88Skamiltraceme_signalmasked_crash(int sig)
5691.88Skamil{
5701.89Skamil	const int sigval = SIGSTOP;
5711.88Skamil	pid_t child, wpid;
5721.88Skamil#if defined(TWAIT_HAVE_STATUS)
5731.88Skamil	int status;
5741.88Skamil#endif
5751.88Skamil	struct ptrace_siginfo info;
5761.88Skamil	sigset_t intmask;
5771.89Skamil	struct kinfo_proc2 kp;
5781.89Skamil	size_t len = sizeof(kp);
5791.89Skamil
5801.89Skamil	int name[6];
5811.89Skamil	const size_t namelen = __arraycount(name);
5821.89Skamil	ki_sigset_t kp_sigmask;
5831.88Skamil
5841.88Skamil#ifndef PTRACE_ILLEGAL_ASM
5851.88Skamil	if (sig == SIGILL)
5861.88Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
5871.88Skamil#endif
5881.88Skamil
5891.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
5901.114Skamil		atf_tc_skip("FP exceptions are not supported");
5911.114Skamil
5921.88Skamil	memset(&info, 0, sizeof(info));
5931.88Skamil
5941.88Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
5951.88Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
5961.88Skamil	if (child == 0) {
5971.88Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
5981.88Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
5991.88Skamil
6001.88Skamil		sigemptyset(&intmask);
6011.88Skamil		sigaddset(&intmask, sig);
6021.88Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
6031.88Skamil
6041.89Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
6051.89Skamil		FORKEE_ASSERT(raise(sigval) == 0);
6061.89Skamil
6071.88Skamil		DPRINTF("Before executing a trap\n");
6081.88Skamil		switch (sig) {
6091.88Skamil		case SIGTRAP:
6101.88Skamil			trigger_trap();
6111.88Skamil			break;
6121.88Skamil		case SIGSEGV:
6131.88Skamil			trigger_segv();
6141.88Skamil			break;
6151.88Skamil		case SIGILL:
6161.88Skamil			trigger_ill();
6171.88Skamil			break;
6181.88Skamil		case SIGFPE:
6191.88Skamil			trigger_fpe();
6201.88Skamil			break;
6211.88Skamil		case SIGBUS:
6221.88Skamil			trigger_bus();
6231.88Skamil			break;
6241.88Skamil		default:
6251.88Skamil			/* NOTREACHED */
6261.88Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
6271.88Skamil		}
6281.88Skamil
6291.88Skamil		/* NOTREACHED */
6301.88Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
6311.88Skamil	}
6321.88Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
6331.88Skamil
6341.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6351.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
6361.88Skamil
6371.89Skamil	validate_status_stopped(status, sigval);
6381.89Skamil
6391.89Skamil	name[0] = CTL_KERN,
6401.89Skamil	name[1] = KERN_PROC2,
6411.89Skamil	name[2] = KERN_PROC_PID;
6421.89Skamil	name[3] = child;
6431.89Skamil	name[4] = sizeof(kp);
6441.89Skamil	name[5] = 1;
6451.89Skamil
6461.89Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
6471.89Skamil
6481.89Skamil	kp_sigmask = kp.p_sigmask;
6491.89Skamil
6501.89Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
6511.89Skamil	SYSCALL_REQUIRE(
6521.89Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
6531.89Skamil
6541.89Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
6551.89Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
6561.89Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
6571.89Skamil	    info.psi_siginfo.si_errno);
6581.89Skamil
6591.89Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
6601.89Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
6611.89Skamil
6621.89Skamil	DPRINTF("Before resuming the child process where it left off and "
6631.89Skamil	    "without signal to be sent\n");
6641.89Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
6651.89Skamil
6661.89Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6671.89Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
6681.89Skamil
6691.88Skamil	validate_status_stopped(status, sig);
6701.88Skamil
6711.88Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
6721.88Skamil	SYSCALL_REQUIRE(
6731.88Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
6741.88Skamil
6751.88Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
6761.88Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
6771.88Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
6781.88Skamil	    info.psi_siginfo.si_errno);
6791.88Skamil
6801.89Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
6811.89Skamil
6821.89Skamil	DPRINTF("kp_sigmask="
6831.89Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
6841.89Skamil	    kp_sigmask.__bits[0], kp_sigmask.__bits[1], kp_sigmask.__bits[2],
6851.89Skamil	    kp_sigmask.__bits[3]);
6861.89Skamil
6871.89Skamil	DPRINTF("kp.p_sigmask="
6881.89Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
6891.89Skamil	    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
6901.89Skamil	    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
6911.89Skamil
6921.89Skamil	ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask, sizeof(kp_sigmask)));
6931.89Skamil
6941.88Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
6951.88Skamil	switch (sig) {
6961.88Skamil	case SIGTRAP:
6971.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
6981.88Skamil		break;
6991.88Skamil	case SIGSEGV:
7001.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
7011.88Skamil		break;
7021.88Skamil	case SIGILL:
7031.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
7041.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
7051.88Skamil		break;
7061.88Skamil	case SIGFPE:
7071.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
7081.88Skamil		break;
7091.88Skamil	case SIGBUS:
7101.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
7111.88Skamil		break;
7121.88Skamil	}
7131.88Skamil
7141.88Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
7151.88Skamil
7161.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
7171.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
7181.88Skamil
7191.88Skamil	validate_status_signaled(status, SIGKILL, 0);
7201.88Skamil
7211.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
7221.88Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
7231.88Skamil}
7241.88Skamil
7251.88Skamil#define TRACEME_SIGNALMASKED_CRASH(test, sig)				\
7261.88SkamilATF_TC(test);								\
7271.88SkamilATF_TC_HEAD(test, tc)							\
7281.88Skamil{									\
7291.88Skamil	atf_tc_set_md_var(tc, "descr",					\
7301.88Skamil	    "Verify masked crash signal " #sig " in a child after "	\
7311.88Skamil	    "PT_TRACE_ME is delivered to its tracer");			\
7321.88Skamil}									\
7331.88Skamil									\
7341.88SkamilATF_TC_BODY(test, tc)							\
7351.88Skamil{									\
7361.88Skamil									\
7371.88Skamil	traceme_signalmasked_crash(sig);				\
7381.88Skamil}
7391.88Skamil
7401.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_trap, SIGTRAP)
7411.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_segv, SIGSEGV)
7421.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_ill, SIGILL)
7431.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_fpe, SIGFPE)
7441.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_bus, SIGBUS)
7451.88Skamil
7461.88Skamil/// ----------------------------------------------------------------------------
7471.88Skamil
7481.88Skamilstatic void
7491.88Skamiltraceme_signalignored_crash(int sig)
7501.88Skamil{
7511.90Skamil	const int sigval = SIGSTOP;
7521.88Skamil	pid_t child, wpid;
7531.88Skamil#if defined(TWAIT_HAVE_STATUS)
7541.88Skamil	int status;
7551.88Skamil#endif
7561.88Skamil	struct sigaction sa;
7571.88Skamil	struct ptrace_siginfo info;
7581.90Skamil	struct kinfo_proc2 kp;
7591.90Skamil	size_t len = sizeof(kp);
7601.90Skamil
7611.90Skamil	int name[6];
7621.90Skamil	const size_t namelen = __arraycount(name);
7631.90Skamil	ki_sigset_t kp_sigignore;
7641.88Skamil
7651.88Skamil#ifndef PTRACE_ILLEGAL_ASM
7661.88Skamil	if (sig == SIGILL)
7671.88Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
7681.88Skamil#endif
7691.88Skamil
7701.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
7711.114Skamil		atf_tc_skip("FP exceptions are not supported");
7721.114Skamil
7731.88Skamil	memset(&info, 0, sizeof(info));
7741.88Skamil
7751.88Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
7761.88Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
7771.88Skamil	if (child == 0) {
7781.88Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
7791.88Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
7801.88Skamil
7811.88Skamil		memset(&sa, 0, sizeof(sa));
7821.88Skamil		sa.sa_handler = SIG_IGN;
7831.88Skamil		sigemptyset(&sa.sa_mask);
7841.88Skamil
7851.88Skamil		FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
7861.88Skamil
7871.90Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
7881.90Skamil		FORKEE_ASSERT(raise(sigval) == 0);
7891.90Skamil
7901.88Skamil		DPRINTF("Before executing a trap\n");
7911.88Skamil		switch (sig) {
7921.88Skamil		case SIGTRAP:
7931.88Skamil			trigger_trap();
7941.88Skamil			break;
7951.88Skamil		case SIGSEGV:
7961.88Skamil			trigger_segv();
7971.88Skamil			break;
7981.88Skamil		case SIGILL:
7991.88Skamil			trigger_ill();
8001.88Skamil			break;
8011.88Skamil		case SIGFPE:
8021.88Skamil			trigger_fpe();
8031.88Skamil			break;
8041.88Skamil		case SIGBUS:
8051.88Skamil			trigger_bus();
8061.88Skamil			break;
8071.88Skamil		default:
8081.88Skamil			/* NOTREACHED */
8091.88Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
8101.88Skamil		}
8111.88Skamil
8121.88Skamil		/* NOTREACHED */
8131.88Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
8141.88Skamil	}
8151.88Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
8161.88Skamil
8171.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8181.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8191.88Skamil
8201.90Skamil	validate_status_stopped(status, sigval);
8211.90Skamil
8221.90Skamil	name[0] = CTL_KERN,
8231.90Skamil	name[1] = KERN_PROC2,
8241.90Skamil	name[2] = KERN_PROC_PID;
8251.90Skamil	name[3] = child;
8261.90Skamil	name[4] = sizeof(kp);
8271.90Skamil	name[5] = 1;
8281.90Skamil
8291.90Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
8301.90Skamil
8311.90Skamil	kp_sigignore = kp.p_sigignore;
8321.90Skamil
8331.90Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
8341.90Skamil	SYSCALL_REQUIRE(
8351.90Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
8361.90Skamil
8371.90Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
8381.90Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
8391.90Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
8401.90Skamil	    info.psi_siginfo.si_errno);
8411.90Skamil
8421.90Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
8431.90Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
8441.90Skamil
8451.90Skamil	DPRINTF("Before resuming the child process where it left off and "
8461.90Skamil	    "without signal to be sent\n");
8471.90Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
8481.90Skamil
8491.90Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8501.90Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8511.90Skamil
8521.88Skamil	validate_status_stopped(status, sig);
8531.88Skamil
8541.88Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
8551.88Skamil	SYSCALL_REQUIRE(
8561.88Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
8571.88Skamil
8581.88Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
8591.88Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
8601.88Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
8611.88Skamil	    info.psi_siginfo.si_errno);
8621.88Skamil
8631.90Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
8641.90Skamil
8651.90Skamil	DPRINTF("kp_sigignore="
8661.90Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
8671.90Skamil	    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
8681.90Skamil	    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
8691.90Skamil
8701.90Skamil	DPRINTF("kp.p_sigignore="
8711.90Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
8721.90Skamil	    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
8731.90Skamil	    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
8741.90Skamil
8751.90Skamil	ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore, sizeof(kp_sigignore)));
8761.90Skamil
8771.88Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
8781.88Skamil	switch (sig) {
8791.88Skamil	case SIGTRAP:
8801.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
8811.88Skamil		break;
8821.88Skamil	case SIGSEGV:
8831.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
8841.88Skamil		break;
8851.88Skamil	case SIGILL:
8861.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
8871.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
8881.88Skamil		break;
8891.88Skamil	case SIGFPE:
8901.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
8911.88Skamil		break;
8921.88Skamil	case SIGBUS:
8931.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
8941.88Skamil		break;
8951.88Skamil	}
8961.88Skamil
8971.88Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
8981.88Skamil
8991.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9001.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9011.88Skamil
9021.88Skamil	validate_status_signaled(status, SIGKILL, 0);
9031.88Skamil
9041.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9051.88Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
9061.88Skamil}
9071.88Skamil
9081.88Skamil#define TRACEME_SIGNALIGNORED_CRASH(test, sig)				\
9091.88SkamilATF_TC(test);								\
9101.88SkamilATF_TC_HEAD(test, tc)							\
9111.88Skamil{									\
9121.88Skamil	atf_tc_set_md_var(tc, "descr",					\
9131.88Skamil	    "Verify ignored crash signal " #sig " in a child after "	\
9141.88Skamil	    "PT_TRACE_ME is delivered to its tracer"); 			\
9151.88Skamil}									\
9161.88Skamil									\
9171.88SkamilATF_TC_BODY(test, tc)							\
9181.88Skamil{									\
9191.88Skamil									\
9201.88Skamil	traceme_signalignored_crash(sig);				\
9211.88Skamil}
9221.88Skamil
9231.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_trap, SIGTRAP)
9241.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_segv, SIGSEGV)
9251.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_ill, SIGILL)
9261.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_fpe, SIGFPE)
9271.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_bus, SIGBUS)
9281.88Skamil
9291.88Skamil/// ----------------------------------------------------------------------------
9301.88Skamil
9311.88Skamilstatic void
9321.50Skamiltraceme_sendsignal_handle(int sigsent, void (*sah)(int a), int *traceme_caught)
9331.1Skamil{
9341.1Skamil	const int exitval = 5;
9351.34Skamil	const int sigval = SIGSTOP;
9361.1Skamil	pid_t child, wpid;
9371.1Skamil	struct sigaction sa;
9381.1Skamil#if defined(TWAIT_HAVE_STATUS)
9391.1Skamil	int status;
9401.1Skamil#endif
9411.61Skre	struct ptrace_siginfo info;
9421.1Skamil
9431.45Skamil	memset(&info, 0, sizeof(info));
9441.45Skamil
9451.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
9461.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
9471.1Skamil	if (child == 0) {
9481.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
9491.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
9501.1Skamil
9511.34Skamil		sa.sa_handler = sah;
9521.1Skamil		sa.sa_flags = SA_SIGINFO;
9531.1Skamil		sigemptyset(&sa.sa_mask);
9541.1Skamil
9551.1Skamil		FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
9561.1Skamil
9571.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
9581.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
9591.1Skamil
9601.34Skamil		FORKEE_ASSERT_EQ(*traceme_caught, 1);
9611.1Skamil
9621.13Schristos		DPRINTF("Before exiting of the child process\n");
9631.1Skamil		_exit(exitval);
9641.1Skamil	}
9651.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
9661.1Skamil
9671.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9681.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9691.1Skamil
9701.1Skamil	validate_status_stopped(status, sigval);
9711.1Skamil
9721.45Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
9731.61Skre	SYSCALL_REQUIRE(
9741.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
9751.45Skamil
9761.45Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
9771.45Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
9781.45Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
9791.45Skamil	    info.psi_siginfo.si_errno);
9801.45Skamil
9811.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
9821.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
9831.45Skamil
9841.13Schristos	DPRINTF("Before resuming the child process where it left off and with "
9851.1Skamil	    "signal %s to be sent\n", strsignal(sigsent));
9861.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
9871.1Skamil
9881.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9891.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9901.1Skamil
9911.1Skamil	validate_status_exited(status, exitval);
9921.1Skamil
9931.13Schristos	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
9941.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
9951.1Skamil}
9961.1Skamil
9971.61Skre#define TRACEME_SENDSIGNAL_HANDLE(test, sig)				\
9981.61SkreATF_TC(test);								\
9991.61SkreATF_TC_HEAD(test, tc)							\
10001.61Skre{									\
10011.61Skre	atf_tc_set_md_var(tc, "descr",					\
10021.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
10031.61Skre	    "handled correctly and caught by a signal handler");	\
10041.61Skre}									\
10051.61Skre									\
10061.61Skrestatic int test##_caught = 0;						\
10071.61Skre									\
10081.61Skrestatic void								\
10091.61Skretest##_sighandler(int arg)						\
10101.61Skre{									\
10111.61Skre	FORKEE_ASSERT_EQ(arg, sig);					\
10121.61Skre									\
10131.61Skre	++ test##_caught;						\
10141.61Skre}									\
10151.61Skre									\
10161.61SkreATF_TC_BODY(test, tc)							\
10171.61Skre{									\
10181.61Skre									\
10191.61Skre	traceme_sendsignal_handle(sig, test##_sighandler, & test##_caught); \
10201.34Skamil}
10211.34Skamil
10221.34Skamil// A signal handler for SIGKILL and SIGSTOP cannot be registered.
10231.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle1, SIGABRT) /* abort trap */
10241.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle2, SIGHUP)  /* hangup */
10251.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle3, SIGCONT) /* continued? */
10261.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle4, SIGTRAP) /* crash sig. */
10271.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle5, SIGBUS) /* crash sig. */
10281.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle6, SIGILL) /* crash sig. */
10291.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle7, SIGFPE) /* crash sig. */
10301.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle8, SIGSEGV) /* crash sig. */
10311.34Skamil
10321.34Skamil/// ----------------------------------------------------------------------------
10331.34Skamil
10341.35Skamilstatic void
10351.50Skamiltraceme_sendsignal_masked(int sigsent)
10361.50Skamil{
10371.50Skamil	const int exitval = 5;
10381.50Skamil	const int sigval = SIGSTOP;
10391.50Skamil	pid_t child, wpid;
10401.50Skamil	sigset_t set;
10411.50Skamil#if defined(TWAIT_HAVE_STATUS)
10421.50Skamil	int status;
10431.50Skamil#endif
10441.61Skre	struct ptrace_siginfo info;
10451.50Skamil
10461.50Skamil	memset(&info, 0, sizeof(info));
10471.50Skamil
10481.50Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
10491.50Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
10501.50Skamil	if (child == 0) {
10511.50Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
10521.50Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
10531.50Skamil
10541.50Skamil		sigemptyset(&set);
10551.50Skamil		sigaddset(&set, sigsent);
10561.50Skamil		FORKEE_ASSERT(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
10571.50Skamil
10581.50Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
10591.50Skamil		FORKEE_ASSERT(raise(sigval) == 0);
10601.50Skamil
10611.50Skamil		_exit(exitval);
10621.50Skamil	}
10631.50Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
10641.50Skamil
10651.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10661.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
10671.50Skamil
10681.50Skamil	validate_status_stopped(status, sigval);
10691.50Skamil
10701.50Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
10711.61Skre	SYSCALL_REQUIRE(
10721.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
10731.50Skamil
10741.50Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
10751.50Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
10761.50Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
10771.50Skamil	    info.psi_siginfo.si_errno);
10781.50Skamil
10791.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
10801.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
10811.50Skamil
10821.50Skamil	DPRINTF("Before resuming the child process where it left off and with "
10831.50Skamil	    "signal %s to be sent\n", strsignal(sigsent));
10841.50Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
10851.50Skamil
10861.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10871.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
10881.50Skamil
10891.50Skamil	validate_status_exited(status, exitval);
10901.50Skamil
10911.50Skamil	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
10921.50Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
10931.50Skamil}
10941.50Skamil
10951.61Skre#define TRACEME_SENDSIGNAL_MASKED(test, sig)				\
10961.61SkreATF_TC(test);								\
10971.61SkreATF_TC_HEAD(test, tc)							\
10981.61Skre{									\
10991.61Skre	atf_tc_set_md_var(tc, "descr",					\
11001.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
11011.61Skre	    "handled correctly and the signal is masked by SIG_BLOCK");	\
11021.61Skre}									\
11031.61Skre									\
11041.61SkreATF_TC_BODY(test, tc)							\
11051.61Skre{									\
11061.61Skre									\
11071.61Skre	traceme_sendsignal_masked(sig);					\
11081.50Skamil}
11091.50Skamil
11101.50Skamil// A signal handler for SIGKILL and SIGSTOP cannot be masked.
11111.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked1, SIGABRT) /* abort trap */
11121.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked2, SIGHUP)  /* hangup */
11131.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked3, SIGCONT) /* continued? */
11141.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked4, SIGTRAP) /* crash sig. */
11151.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked5, SIGBUS) /* crash sig. */
11161.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked6, SIGILL) /* crash sig. */
11171.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked7, SIGFPE) /* crash sig. */
11181.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked8, SIGSEGV) /* crash sig. */
11191.50Skamil
11201.50Skamil/// ----------------------------------------------------------------------------
11211.50Skamil
11221.50Skamilstatic void
11231.50Skamiltraceme_sendsignal_ignored(int sigsent)
11241.50Skamil{
11251.50Skamil	const int exitval = 5;
11261.50Skamil	const int sigval = SIGSTOP;
11271.50Skamil	pid_t child, wpid;
11281.50Skamil	struct sigaction sa;
11291.50Skamil#if defined(TWAIT_HAVE_STATUS)
11301.50Skamil	int status;
11311.50Skamil#endif
11321.61Skre	struct ptrace_siginfo info;
11331.50Skamil
11341.50Skamil	memset(&info, 0, sizeof(info));
11351.50Skamil
11361.50Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
11371.50Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
11381.50Skamil	if (child == 0) {
11391.50Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
11401.61Skre
11411.50Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
11421.50Skamil
11431.50Skamil		memset(&sa, 0, sizeof(sa));
11441.50Skamil		sa.sa_handler = SIG_IGN;
11451.50Skamil		sigemptyset(&sa.sa_mask);
11461.50Skamil		FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
11471.50Skamil
11481.50Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
11491.50Skamil		FORKEE_ASSERT(raise(sigval) == 0);
11501.50Skamil
11511.50Skamil		_exit(exitval);
11521.50Skamil	}
11531.50Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
11541.50Skamil
11551.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11561.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11571.50Skamil
11581.50Skamil	validate_status_stopped(status, sigval);
11591.50Skamil
11601.50Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
11611.61Skre	SYSCALL_REQUIRE(
11621.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
11631.50Skamil
11641.50Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
11651.50Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
11661.50Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
11671.50Skamil	    info.psi_siginfo.si_errno);
11681.50Skamil
11691.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
11701.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
11711.50Skamil
11721.50Skamil	DPRINTF("Before resuming the child process where it left off and with "
11731.50Skamil	    "signal %s to be sent\n", strsignal(sigsent));
11741.50Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
11751.50Skamil
11761.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11771.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11781.50Skamil
11791.50Skamil	validate_status_exited(status, exitval);
11801.50Skamil
11811.50Skamil	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
11821.50Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
11831.50Skamil}
11841.50Skamil
11851.61Skre#define TRACEME_SENDSIGNAL_IGNORED(test, sig)				\
11861.61SkreATF_TC(test);								\
11871.61SkreATF_TC_HEAD(test, tc)							\
11881.61Skre{									\
11891.61Skre	atf_tc_set_md_var(tc, "descr",					\
11901.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
11911.61Skre	    "handled correctly and the signal is masked by SIG_IGN");	\
11921.61Skre}									\
11931.61Skre									\
11941.61SkreATF_TC_BODY(test, tc)							\
11951.61Skre{									\
11961.61Skre									\
11971.61Skre	traceme_sendsignal_ignored(sig);				\
11981.50Skamil}
11991.50Skamil
12001.50Skamil// A signal handler for SIGKILL and SIGSTOP cannot be ignored.
12011.61SkreTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored1, SIGABRT) /* abort */
12021.50SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored2, SIGHUP)  /* hangup */
12031.61SkreTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored3, SIGCONT) /* continued */
12041.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored4, SIGTRAP) /* crash s. */
12051.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored5, SIGBUS) /* crash s. */
12061.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored6, SIGILL) /* crash s. */
12071.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored7, SIGFPE) /* crash s. */
12081.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored8, SIGSEGV) /* crash s. */
12091.50Skamil
12101.50Skamil/// ----------------------------------------------------------------------------
12111.50Skamil
12121.50Skamilstatic void
12131.50Skamiltraceme_sendsignal_simple(int sigsent)
12141.1Skamil{
12151.35Skamil	const int sigval = SIGSTOP;
12161.35Skamil	int exitval = 0;
12171.1Skamil	pid_t child, wpid;
12181.1Skamil#if defined(TWAIT_HAVE_STATUS)
12191.1Skamil	int status;
12201.85Skamil	int expect_core;
12211.85Skamil
12221.85Skamil	switch (sigsent) {
12231.85Skamil	case SIGABRT:
12241.85Skamil	case SIGTRAP:
12251.85Skamil	case SIGBUS:
12261.85Skamil	case SIGILL:
12271.85Skamil	case SIGFPE:
12281.85Skamil	case SIGSEGV:
12291.85Skamil		expect_core = 1;
12301.85Skamil		break;
12311.85Skamil	default:
12321.85Skamil		expect_core = 0;
12331.85Skamil		break;
12341.85Skamil	}
12351.1Skamil#endif
12361.61Skre	struct ptrace_siginfo info;
12371.1Skamil
12381.45Skamil	memset(&info, 0, sizeof(info));
12391.45Skamil
12401.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
12411.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
12421.1Skamil	if (child == 0) {
12431.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
12441.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
12451.1Skamil
12461.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
12471.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
12481.1Skamil
12491.35Skamil		switch (sigsent) {
12501.35Skamil		case SIGCONT:
12511.48Skamil		case SIGSTOP:
12521.35Skamil			_exit(exitval);
12531.35Skamil		default:
12541.35Skamil			/* NOTREACHED */
12551.35Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
12561.35Skamil		}
12571.1Skamil	}
12581.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
12591.1Skamil
12601.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12611.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
12621.1Skamil
12631.1Skamil	validate_status_stopped(status, sigval);
12641.1Skamil
12651.45Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
12661.61Skre	SYSCALL_REQUIRE(
12671.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
12681.45Skamil
12691.45Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12701.45Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
12711.45Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12721.45Skamil	    info.psi_siginfo.si_errno);
12731.45Skamil
12741.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
12751.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
12761.45Skamil
12771.13Schristos	DPRINTF("Before resuming the child process where it left off and with "
12781.1Skamil	    "signal %s to be sent\n", strsignal(sigsent));
12791.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
12801.1Skamil
12811.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12821.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
12831.1Skamil
12841.35Skamil	switch (sigsent) {
12851.48Skamil	case SIGSTOP:
12861.48Skamil		validate_status_stopped(status, sigsent);
12871.48Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
12881.61Skre		    "child\n");
12891.48Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
12901.61Skre		    sizeof(info)) != -1);
12911.48Skamil
12921.48Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12931.48Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
12941.61Skre		    "si_errno=%#x\n",
12951.61Skre		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12961.61Skre		    info.psi_siginfo.si_errno);
12971.48Skamil
12981.48Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
12991.48Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
13001.48Skamil
13011.48Skamil		DPRINTF("Before resuming the child process where it left off "
13021.61Skre		    "and with signal %s to be sent\n", strsignal(sigsent));
13031.48Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
13041.48Skamil
13051.48Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
13061.48Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
13071.61Skre		    child);
13081.48Skamil		/* FALLTHROUGH */
13091.35Skamil	case SIGCONT:
13101.35Skamil		validate_status_exited(status, exitval);
13111.35Skamil		break;
13121.35Skamil	default:
13131.35Skamil		validate_status_signaled(status, sigsent, expect_core);
13141.35Skamil		break;
13151.35Skamil	}
13161.1Skamil
13171.13Schristos	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
13181.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
13191.1Skamil}
13201.1Skamil
13211.61Skre#define TRACEME_SENDSIGNAL_SIMPLE(test, sig)				\
13221.61SkreATF_TC(test);								\
13231.61SkreATF_TC_HEAD(test, tc)							\
13241.61Skre{									\
13251.61Skre	atf_tc_set_md_var(tc, "descr",					\
13261.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
13271.61Skre	    "handled correctly in a child without a signal handler");	\
13281.61Skre}									\
13291.61Skre									\
13301.61SkreATF_TC_BODY(test, tc)							\
13311.61Skre{									\
13321.61Skre									\
13331.61Skre	traceme_sendsignal_simple(sig);					\
13341.35Skamil}
13351.35Skamil
13361.61SkreTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple1, SIGKILL) /* non-maskable*/
13371.61SkreTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple2, SIGSTOP) /* non-maskable*/
13381.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple3, SIGABRT) /* abort trap */
13391.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple4, SIGHUP)  /* hangup */
13401.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple5, SIGCONT) /* continued? */
13411.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple6, SIGTRAP) /* crash sig. */
13421.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple7, SIGBUS) /* crash sig. */
13431.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple8, SIGILL) /* crash sig. */
13441.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple9, SIGFPE) /* crash sig. */
13451.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple10, SIGSEGV) /* crash sig. */
13461.35Skamil
13471.35Skamil/// ----------------------------------------------------------------------------
13481.35Skamil
13491.37SkamilATF_TC(traceme_pid1_parent);
13501.37SkamilATF_TC_HEAD(traceme_pid1_parent, tc)
13511.37Skamil{
13521.37Skamil	atf_tc_set_md_var(tc, "descr",
13531.37Skamil	    "Verify that PT_TRACE_ME is not allowed when our parent is PID1");
13541.37Skamil}
13551.37Skamil
13561.37SkamilATF_TC_BODY(traceme_pid1_parent, tc)
13571.37Skamil{
13581.37Skamil	struct msg_fds parent_child;
13591.37Skamil	int exitval_child1 = 1, exitval_child2 = 2;
13601.37Skamil	pid_t child1, child2, wpid;
13611.37Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
13621.37Skamil#if defined(TWAIT_HAVE_STATUS)
13631.37Skamil	int status;
13641.37Skamil#endif
13651.37Skamil
13661.37Skamil	SYSCALL_REQUIRE(msg_open(&parent_child) == 0);
13671.37Skamil
13681.37Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
13691.37Skamil	SYSCALL_REQUIRE((child1 = fork()) != -1);
13701.37Skamil	if (child1 == 0) {
13711.37Skamil		DPRINTF("Before forking process PID=%d\n", getpid());
13721.37Skamil		SYSCALL_REQUIRE((child2 = fork()) != -1);
13731.37Skamil		if (child2 != 0) {
13741.37Skamil			DPRINTF("Parent process PID=%d, child2's PID=%d\n",
13751.61Skre			    getpid(), child2);
13761.37Skamil			_exit(exitval_child1);
13771.37Skamil		}
13781.37Skamil		CHILD_FROM_PARENT("exit child1", parent_child, msg);
13791.37Skamil
13801.37Skamil		DPRINTF("Assert that our parent is PID1 (initproc)\n");
13811.37Skamil		FORKEE_ASSERT_EQ(getppid(), 1);
13821.37Skamil
13831.37Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
13841.37Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) == -1);
13851.37Skamil		SYSCALL_REQUIRE_ERRNO(errno, EPERM);
13861.37Skamil
13871.37Skamil		CHILD_TO_PARENT("child2 exiting", parent_child, msg);
13881.37Skamil
13891.37Skamil		_exit(exitval_child2);
13901.37Skamil	}
13911.37Skamil	DPRINTF("Parent process PID=%d, child1's PID=%d\n", getpid(), child1);
13921.37Skamil
13931.37Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
13941.61Skre	TWAIT_REQUIRE_SUCCESS(
13951.61Skre	    wpid = TWAIT_GENERIC(child1, &status, WEXITED), child1);
13961.37Skamil
13971.37Skamil	validate_status_exited(status, exitval_child1);
13981.37Skamil
13991.37Skamil	DPRINTF("Notify that child1 is dead\n");
14001.37Skamil	PARENT_TO_CHILD("exit child1", parent_child, msg);
14011.37Skamil
14021.37Skamil	DPRINTF("Wait for exiting of child2\n");
14031.37Skamil	PARENT_FROM_CHILD("child2 exiting", parent_child, msg);
14041.37Skamil}
14051.37Skamil
14061.37Skamil/// ----------------------------------------------------------------------------
14071.37Skamil
14081.40Skamilstatic void
14091.40Skamiltraceme_vfork_raise(int sigval)
14101.40Skamil{
14111.46Skamil	const int exitval = 5, exitval_watcher = 10;
14121.46Skamil	pid_t child, parent, watcher, wpid;
14131.46Skamil	int rv;
14141.40Skamil#if defined(TWAIT_HAVE_STATUS)
14151.40Skamil	int status;
14161.85Skamil
14171.85Skamil	/* volatile workarounds GCC -Werror=clobbered */
14181.85Skamil	volatile int expect_core;
14191.85Skamil
14201.85Skamil	switch (sigval) {
14211.85Skamil	case SIGABRT:
14221.85Skamil	case SIGTRAP:
14231.85Skamil	case SIGBUS:
14241.85Skamil	case SIGILL:
14251.85Skamil	case SIGFPE:
14261.85Skamil	case SIGSEGV:
14271.85Skamil		expect_core = 1;
14281.85Skamil		break;
14291.85Skamil	default:
14301.85Skamil		expect_core = 0;
14311.85Skamil		break;
14321.85Skamil	}
14331.40Skamil#endif
14341.40Skamil
14351.46Skamil	/*
14361.46Skamil	 * Spawn a dedicated thread to watch for a stopped child and emit
14371.46Skamil	 * the SIGKILL signal to it.
14381.46Skamil	 *
14391.46Skamil	 * vfork(2) might clobber watcher, this means that it's safer and
14401.46Skamil	 * simpler to reparent this process to initproc and forget about it.
14411.46Skamil	 */
14421.46Skamil	if (sigval == SIGSTOP) {
14431.46Skamil		parent = getpid();
14441.46Skamil
14451.46Skamil		watcher = fork();
14461.46Skamil		ATF_REQUIRE(watcher != 1);
14471.46Skamil		if (watcher == 0) {
14481.46Skamil			/* Double fork(2) trick to reparent to initproc */
14491.46Skamil			watcher = fork();
14501.46Skamil			FORKEE_ASSERT_NEQ(watcher, -1);
14511.46Skamil			if (watcher != 0)
14521.46Skamil				_exit(exitval_watcher);
14531.46Skamil
14541.46Skamil			child = await_stopped_child(parent);
14551.46Skamil
14561.46Skamil			errno = 0;
14571.46Skamil			rv = kill(child, SIGKILL);
14581.46Skamil			FORKEE_ASSERT_EQ(rv, 0);
14591.46Skamil			FORKEE_ASSERT_EQ(errno, 0);
14601.46Skamil
14611.46Skamil			/* This exit value will be collected by initproc */
14621.46Skamil			_exit(0);
14631.46Skamil		}
14641.46Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14651.46Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(watcher, &status, 0),
14661.61Skre		    watcher);
14671.46Skamil
14681.46Skamil		validate_status_exited(status, exitval_watcher);
14691.46Skamil
14701.46Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14711.61Skre		TWAIT_REQUIRE_FAILURE(ECHILD,
14721.61Skre		    wpid = TWAIT_GENERIC(watcher, &status, 0));
14731.46Skamil	}
14741.46Skamil
14751.40Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
14761.40Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
14771.40Skamil	if (child == 0) {
14781.40Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
14791.40Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
14801.40Skamil
14811.40Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
14821.40Skamil		FORKEE_ASSERT(raise(sigval) == 0);
14831.40Skamil
14841.40Skamil		switch (sigval) {
14851.46Skamil		case SIGSTOP:
14861.40Skamil		case SIGKILL:
14871.40Skamil		case SIGABRT:
14881.40Skamil		case SIGHUP:
14891.85Skamil		case SIGTRAP:
14901.85Skamil		case SIGBUS:
14911.85Skamil		case SIGILL:
14921.85Skamil		case SIGFPE:
14931.85Skamil		case SIGSEGV:
14941.40Skamil			/* NOTREACHED */
14951.40Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
14961.70Smrg			__unreachable();
14971.40Skamil		default:
14981.40Skamil			DPRINTF("Before exiting of the child process\n");
14991.40Skamil			_exit(exitval);
15001.40Skamil		}
15011.40Skamil	}
15021.40Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
15031.40Skamil
15041.40Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15051.40Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
15061.40Skamil
15071.40Skamil	switch (sigval) {
15081.40Skamil	case SIGKILL:
15091.40Skamil	case SIGABRT:
15101.40Skamil	case SIGHUP:
15111.85Skamil	case SIGTRAP:
15121.85Skamil	case SIGBUS:
15131.85Skamil	case SIGILL:
15141.85Skamil	case SIGFPE:
15151.85Skamil	case SIGSEGV:
15161.40Skamil		validate_status_signaled(status, sigval, expect_core);
15171.40Skamil		break;
15181.40Skamil	case SIGSTOP:
15191.46Skamil		validate_status_signaled(status, SIGKILL, 0);
15201.46Skamil		break;
15211.40Skamil	case SIGCONT:
15221.47Skamil	case SIGTSTP:
15231.47Skamil	case SIGTTIN:
15241.47Skamil	case SIGTTOU:
15251.40Skamil		validate_status_exited(status, exitval);
15261.40Skamil		break;
15271.40Skamil	default:
15281.40Skamil		/* NOTREACHED */
15291.40Skamil		ATF_REQUIRE(0 && "NOT IMPLEMENTED");
15301.40Skamil		break;
15311.40Skamil	}
15321.40Skamil
15331.40Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15341.40Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
15351.40Skamil}
15361.40Skamil
15371.61Skre#define TRACEME_VFORK_RAISE(test, sig)					\
15381.61SkreATF_TC(test);								\
15391.61SkreATF_TC_HEAD(test, tc)							\
15401.61Skre{									\
15411.61Skre	atf_tc_set_md_var(tc, "descr",					\
15421.61Skre	    "Verify PT_TRACE_ME followed by raise of " #sig " in a "	\
15431.61Skre	    "vfork(2)ed child");					\
15441.61Skre}									\
15451.61Skre									\
15461.61SkreATF_TC_BODY(test, tc)							\
15471.61Skre{									\
15481.61Skre									\
15491.61Skre	traceme_vfork_raise(sig);					\
15501.40Skamil}
15511.40Skamil
15521.40SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise1, SIGKILL) /* non-maskable */
15531.46SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise2, SIGSTOP) /* non-maskable */
15541.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise3, SIGTSTP) /* ignored in vfork(2) */
15551.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise4, SIGTTIN) /* ignored in vfork(2) */
15561.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise5, SIGTTOU) /* ignored in vfork(2) */
15571.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise6, SIGABRT) /* regular abort trap */
15581.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise7, SIGHUP)  /* hangup */
15591.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise8, SIGCONT) /* continued? */
15601.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise9, SIGTRAP) /* crash signal */
15611.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise10, SIGBUS) /* crash signal */
15621.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise11, SIGILL) /* crash signal */
15631.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise12, SIGFPE) /* crash signal */
15641.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise13, SIGSEGV) /* crash signal */
15651.40Skamil
15661.40Skamil/// ----------------------------------------------------------------------------
15671.40Skamil
15681.52Skamilstatic void
15691.52Skamiltraceme_vfork_crash(int sig)
15701.41Skamil{
15711.41Skamil	pid_t child, wpid;
15721.41Skamil#if defined(TWAIT_HAVE_STATUS)
15731.41Skamil	int status;
15741.41Skamil#endif
15751.41Skamil
15761.71Skamil#ifndef PTRACE_ILLEGAL_ASM
15771.71Skamil	if (sig == SIGILL)
15781.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
15791.71Skamil#endif
15801.71Skamil
15811.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
15821.114Skamil		atf_tc_skip("FP exceptions are not supported");
15831.114Skamil
15841.41Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
15851.41Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
15861.41Skamil	if (child == 0) {
15871.41Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
15881.41Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
15891.41Skamil
15901.52Skamil		DPRINTF("Before executing a trap\n");
15911.52Skamil		switch (sig) {
15921.52Skamil		case SIGTRAP:
15931.52Skamil			trigger_trap();
15941.52Skamil			break;
15951.52Skamil		case SIGSEGV:
15961.52Skamil			trigger_segv();
15971.52Skamil			break;
15981.52Skamil		case SIGILL:
15991.52Skamil			trigger_ill();
16001.52Skamil			break;
16011.52Skamil		case SIGFPE:
16021.52Skamil			trigger_fpe();
16031.52Skamil			break;
16041.52Skamil		case SIGBUS:
16051.52Skamil			trigger_bus();
16061.52Skamil			break;
16071.52Skamil		default:
16081.52Skamil			/* NOTREACHED */
16091.52Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
16101.52Skamil		}
16111.41Skamil
16121.41Skamil		/* NOTREACHED */
16131.41Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
16141.41Skamil	}
16151.41Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
16161.41Skamil
16171.41Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16181.41Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
16191.41Skamil
16201.52Skamil	validate_status_signaled(status, sig, 1);
16211.41Skamil
16221.41Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16231.41Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
16241.41Skamil}
16251.41Skamil
16261.61Skre#define TRACEME_VFORK_CRASH(test, sig)					\
16271.61SkreATF_TC(test);								\
16281.61SkreATF_TC_HEAD(test, tc)							\
16291.61Skre{									\
16301.61Skre	atf_tc_set_md_var(tc, "descr",					\
16311.61Skre	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
16321.61Skre	    "vfork(2)ed child");					\
16331.61Skre}									\
16341.61Skre									\
16351.61SkreATF_TC_BODY(test, tc)							\
16361.61Skre{									\
16371.61Skre									\
16381.61Skre	traceme_vfork_crash(sig);					\
16391.52Skamil}
16401.52Skamil
16411.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_trap, SIGTRAP)
16421.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_segv, SIGSEGV)
16431.71SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_ill, SIGILL)
16441.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_fpe, SIGFPE)
16451.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_bus, SIGBUS)
16461.52Skamil
16471.41Skamil/// ----------------------------------------------------------------------------
16481.41Skamil
16491.92Skamilstatic void
16501.92Skamiltraceme_vfork_signalmasked_crash(int sig)
16511.92Skamil{
16521.92Skamil	pid_t child, wpid;
16531.92Skamil#if defined(TWAIT_HAVE_STATUS)
16541.92Skamil	int status;
16551.92Skamil#endif
16561.92Skamil	sigset_t intmask;
16571.92Skamil
16581.92Skamil#ifndef PTRACE_ILLEGAL_ASM
16591.92Skamil	if (sig == SIGILL)
16601.92Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
16611.92Skamil#endif
16621.92Skamil
16631.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
16641.114Skamil		atf_tc_skip("FP exceptions are not supported");
16651.114Skamil
16661.92Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
16671.92Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
16681.92Skamil	if (child == 0) {
16691.92Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
16701.92Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
16711.92Skamil
16721.92Skamil		sigemptyset(&intmask);
16731.92Skamil		sigaddset(&intmask, sig);
16741.92Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
16751.92Skamil
16761.92Skamil		DPRINTF("Before executing a trap\n");
16771.92Skamil		switch (sig) {
16781.92Skamil		case SIGTRAP:
16791.92Skamil			trigger_trap();
16801.92Skamil			break;
16811.92Skamil		case SIGSEGV:
16821.92Skamil			trigger_segv();
16831.92Skamil			break;
16841.92Skamil		case SIGILL:
16851.92Skamil			trigger_ill();
16861.92Skamil			break;
16871.92Skamil		case SIGFPE:
16881.92Skamil			trigger_fpe();
16891.92Skamil			break;
16901.92Skamil		case SIGBUS:
16911.92Skamil			trigger_bus();
16921.92Skamil			break;
16931.92Skamil		default:
16941.92Skamil			/* NOTREACHED */
16951.92Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
16961.92Skamil		}
16971.92Skamil
16981.92Skamil		/* NOTREACHED */
16991.92Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
17001.92Skamil	}
17011.92Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
17021.92Skamil
17031.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17041.92Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17051.92Skamil
17061.92Skamil	validate_status_signaled(status, sig, 1);
17071.92Skamil
17081.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17091.92Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
17101.92Skamil}
17111.92Skamil
17121.92Skamil#define TRACEME_VFORK_SIGNALMASKED_CRASH(test, sig)			\
17131.92SkamilATF_TC(test);								\
17141.92SkamilATF_TC_HEAD(test, tc)							\
17151.92Skamil{									\
17161.92Skamil	atf_tc_set_md_var(tc, "descr",					\
17171.92Skamil	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
17181.92Skamil	    "vfork(2)ed child with a masked signal");			\
17191.92Skamil}									\
17201.92Skamil									\
17211.92SkamilATF_TC_BODY(test, tc)							\
17221.92Skamil{									\
17231.92Skamil									\
17241.92Skamil	traceme_vfork_signalmasked_crash(sig);				\
17251.92Skamil}
17261.92Skamil
17271.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_trap, SIGTRAP)
17281.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_segv, SIGSEGV)
17291.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_ill, SIGILL)
17301.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_fpe, SIGFPE)
17311.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_bus, SIGBUS)
17321.92Skamil
17331.92Skamil/// ----------------------------------------------------------------------------
17341.92Skamil
17351.92Skamilstatic void
17361.92Skamiltraceme_vfork_signalignored_crash(int sig)
17371.92Skamil{
17381.92Skamil	pid_t child, wpid;
17391.92Skamil#if defined(TWAIT_HAVE_STATUS)
17401.92Skamil	int status;
17411.92Skamil#endif
17421.92Skamil	struct sigaction sa;
17431.92Skamil
17441.92Skamil#ifndef PTRACE_ILLEGAL_ASM
17451.92Skamil	if (sig == SIGILL)
17461.92Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
17471.92Skamil#endif
17481.92Skamil
17491.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
17501.114Skamil		atf_tc_skip("FP exceptions are not supported");
17511.114Skamil
17521.92Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
17531.92Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
17541.92Skamil	if (child == 0) {
17551.92Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
17561.92Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
17571.92Skamil
17581.92Skamil		memset(&sa, 0, sizeof(sa));
17591.92Skamil		sa.sa_handler = SIG_IGN;
17601.92Skamil		sigemptyset(&sa.sa_mask);
17611.92Skamil
17621.92Skamil		FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
17631.92Skamil
17641.92Skamil		DPRINTF("Before executing a trap\n");
17651.92Skamil		switch (sig) {
17661.92Skamil		case SIGTRAP:
17671.92Skamil			trigger_trap();
17681.92Skamil			break;
17691.92Skamil		case SIGSEGV:
17701.92Skamil			trigger_segv();
17711.92Skamil			break;
17721.92Skamil		case SIGILL:
17731.92Skamil			trigger_ill();
17741.92Skamil			break;
17751.92Skamil		case SIGFPE:
17761.92Skamil			trigger_fpe();
17771.92Skamil			break;
17781.92Skamil		case SIGBUS:
17791.92Skamil			trigger_bus();
17801.92Skamil			break;
17811.92Skamil		default:
17821.92Skamil			/* NOTREACHED */
17831.92Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
17841.92Skamil		}
17851.92Skamil
17861.92Skamil		/* NOTREACHED */
17871.92Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
17881.92Skamil	}
17891.92Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
17901.92Skamil
17911.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17921.92Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17931.92Skamil
17941.92Skamil	validate_status_signaled(status, sig, 1);
17951.92Skamil
17961.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17971.92Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
17981.92Skamil}
17991.92Skamil
18001.92Skamil#define TRACEME_VFORK_SIGNALIGNORED_CRASH(test, sig)			\
18011.92SkamilATF_TC(test);								\
18021.92SkamilATF_TC_HEAD(test, tc)							\
18031.92Skamil{									\
18041.92Skamil	atf_tc_set_md_var(tc, "descr",					\
18051.92Skamil	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
18061.92Skamil	    "vfork(2)ed child with ignored signal");			\
18071.92Skamil}									\
18081.92Skamil									\
18091.92SkamilATF_TC_BODY(test, tc)							\
18101.92Skamil{									\
18111.92Skamil									\
18121.92Skamil	traceme_vfork_signalignored_crash(sig);				\
18131.92Skamil}
18141.92Skamil
18151.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_trap,
18161.92Skamil    SIGTRAP)
18171.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_segv,
18181.92Skamil    SIGSEGV)
18191.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_ill,
18201.92Skamil    SIGILL)
18211.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_fpe,
18221.92Skamil    SIGFPE)
18231.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_bus,
18241.92Skamil    SIGBUS)
18251.92Skamil
18261.92Skamil/// ----------------------------------------------------------------------------
18271.92Skamil
18281.96Skamilstatic void
18291.96Skamiltraceme_vfork_exec(bool masked, bool ignored)
18301.43Skamil{
18311.43Skamil	const int sigval = SIGTRAP;
18321.43Skamil	pid_t child, wpid;
18331.43Skamil#if defined(TWAIT_HAVE_STATUS)
18341.43Skamil	int status;
18351.43Skamil#endif
18361.96Skamil	struct sigaction sa;
18371.61Skre	struct ptrace_siginfo info;
18381.96Skamil	sigset_t intmask;
18391.96Skamil	struct kinfo_proc2 kp;
18401.96Skamil	size_t len = sizeof(kp);
18411.96Skamil
18421.96Skamil	int name[6];
18431.96Skamil	const size_t namelen = __arraycount(name);
18441.96Skamil	ki_sigset_t kp_sigmask;
18451.96Skamil	ki_sigset_t kp_sigignore;
18461.43Skamil
18471.43Skamil	memset(&info, 0, sizeof(info));
18481.43Skamil
18491.43Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
18501.43Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
18511.43Skamil	if (child == 0) {
18521.43Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
18531.43Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
18541.43Skamil
18551.96Skamil		if (masked) {
18561.96Skamil			sigemptyset(&intmask);
18571.96Skamil			sigaddset(&intmask, sigval);
18581.96Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
18591.96Skamil		}
18601.96Skamil
18611.96Skamil		if (ignored) {
18621.96Skamil			memset(&sa, 0, sizeof(sa));
18631.96Skamil			sa.sa_handler = SIG_IGN;
18641.96Skamil			sigemptyset(&sa.sa_mask);
18651.96Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
18661.96Skamil		}
18671.96Skamil
18681.43Skamil		DPRINTF("Before calling execve(2) from child\n");
18691.43Skamil		execlp("/bin/echo", "/bin/echo", NULL);
18701.43Skamil
18711.43Skamil		/* NOTREACHED */
18721.43Skamil		FORKEE_ASSERTX(0 && "Not reached");
18731.43Skamil	}
18741.43Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
18751.43Skamil
18761.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18771.43Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
18781.43Skamil
18791.43Skamil	validate_status_stopped(status, sigval);
18801.43Skamil
18811.96Skamil	name[0] = CTL_KERN,
18821.96Skamil	name[1] = KERN_PROC2,
18831.96Skamil	name[2] = KERN_PROC_PID;
18841.96Skamil	name[3] = getpid();
18851.96Skamil	name[4] = sizeof(kp);
18861.96Skamil	name[5] = 1;
18871.96Skamil
18881.96Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
18891.96Skamil
18901.96Skamil	if (masked)
18911.96Skamil		kp_sigmask = kp.p_sigmask;
18921.96Skamil
18931.96Skamil	if (ignored)
18941.96Skamil		kp_sigignore = kp.p_sigignore;
18951.96Skamil
18961.96Skamil	name[3] = getpid();
18971.96Skamil
18981.96Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
18991.96Skamil
19001.96Skamil	if (masked) {
19011.96Skamil		DPRINTF("kp_sigmask="
19021.96Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19031.96Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
19041.96Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
19051.96Skamil
19061.96Skamil	        DPRINTF("kp.p_sigmask="
19071.96Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19081.96Skamil	            kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
19091.96Skamil	            kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
19101.96Skamil
19111.96Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
19121.96Skamil		    sizeof(kp_sigmask)));
19131.96Skamil	}
19141.96Skamil
19151.96Skamil	if (ignored) {
19161.96Skamil		DPRINTF("kp_sigignore="
19171.96Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19181.96Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
19191.96Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
19201.96Skamil
19211.96Skamil	        DPRINTF("kp.p_sigignore="
19221.96Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19231.96Skamil	            kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
19241.96Skamil	            kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
19251.96Skamil
19261.96Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
19271.96Skamil		    sizeof(kp_sigignore)));
19281.96Skamil	}
19291.96Skamil
19301.43Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
19311.61Skre	SYSCALL_REQUIRE(
19321.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
19331.43Skamil
19341.43Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
19351.43Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
19361.43Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
19371.43Skamil	    info.psi_siginfo.si_errno);
19381.43Skamil
19391.43Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
19401.43Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
19411.43Skamil
19421.43Skamil	DPRINTF("Before resuming the child process where it left off and "
19431.43Skamil	    "without signal to be sent\n");
19441.43Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
19451.43Skamil
19461.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
19471.43Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
19481.43Skamil
19491.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
19501.43Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
19511.43Skamil}
19521.43Skamil
19531.96Skamil#define TRACEME_VFORK_EXEC(test, masked, ignored)			\
19541.96SkamilATF_TC(test);								\
19551.96SkamilATF_TC_HEAD(test, tc)							\
19561.96Skamil{									\
19571.96Skamil	atf_tc_set_md_var(tc, "descr",					\
19581.96Skamil	    "Verify PT_TRACE_ME followed by exec(3) in a vfork(2)ed "	\
19591.96Skamil	    "child%s%s", masked ? " with masked signal" : "",		\
19601.96Skamil	    masked ? " with ignored signal" : "");			\
19611.96Skamil}									\
19621.96Skamil									\
19631.96SkamilATF_TC_BODY(test, tc)							\
19641.96Skamil{									\
19651.96Skamil									\
19661.96Skamil	traceme_vfork_exec(masked, ignored);				\
19671.96Skamil}
19681.96Skamil
19691.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_exec, false, false)
19701.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalmasked_exec, true, false)
19711.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalignored_exec, false, true)
19721.96Skamil
19731.43Skamil/// ----------------------------------------------------------------------------
19741.43Skamil
19751.1Skamil#if defined(TWAIT_HAVE_PID)
19761.51Skamilstatic void
19771.94Skamilunrelated_tracer_sees_crash(int sig, bool masked, bool ignored)
19781.59Skamil{
19791.94Skamil	const int sigval = SIGSTOP;
19801.59Skamil	struct msg_fds parent_tracee, parent_tracer;
19811.59Skamil	const int exitval = 10;
19821.59Skamil	pid_t tracee, tracer, wpid;
19831.59Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
19841.59Skamil#if defined(TWAIT_HAVE_STATUS)
19851.59Skamil	int status;
19861.59Skamil#endif
19871.94Skamil	struct sigaction sa;
19881.59Skamil	struct ptrace_siginfo info;
19891.94Skamil	sigset_t intmask;
19901.94Skamil	struct kinfo_proc2 kp;
19911.94Skamil	size_t len = sizeof(kp);
19921.94Skamil
19931.94Skamil	int name[6];
19941.94Skamil	const size_t namelen = __arraycount(name);
19951.94Skamil	ki_sigset_t kp_sigmask;
19961.94Skamil	ki_sigset_t kp_sigignore;
19971.61Skre
19981.71Skamil#ifndef PTRACE_ILLEGAL_ASM
19991.71Skamil	if (sig == SIGILL)
20001.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
20011.71Skamil#endif
20021.71Skamil
20031.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
20041.114Skamil		atf_tc_skip("FP exceptions are not supported");
20051.114Skamil
20061.59Skamil	memset(&info, 0, sizeof(info));
20071.59Skamil
20081.59Skamil	DPRINTF("Spawn tracee\n");
20091.59Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
20101.59Skamil	tracee = atf_utils_fork();
20111.59Skamil	if (tracee == 0) {
20121.59Skamil		// Wait for parent to let us crash
20131.59Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
20141.61Skre
20151.94Skamil		if (masked) {
20161.94Skamil			sigemptyset(&intmask);
20171.94Skamil			sigaddset(&intmask, sig);
20181.94Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
20191.94Skamil		}
20201.94Skamil
20211.94Skamil		if (ignored) {
20221.94Skamil			memset(&sa, 0, sizeof(sa));
20231.94Skamil			sa.sa_handler = SIG_IGN;
20241.94Skamil			sigemptyset(&sa.sa_mask);
20251.94Skamil			FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
20261.94Skamil		}
20271.94Skamil
20281.94Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
20291.94Skamil		FORKEE_ASSERT(raise(sigval) == 0);
20301.94Skamil
20311.59Skamil		DPRINTF("Before executing a trap\n");
20321.59Skamil		switch (sig) {
20331.59Skamil		case SIGTRAP:
20341.59Skamil			trigger_trap();
20351.59Skamil			break;
20361.59Skamil		case SIGSEGV:
20371.59Skamil			trigger_segv();
20381.59Skamil			break;
20391.59Skamil		case SIGILL:
20401.59Skamil			trigger_ill();
20411.59Skamil			break;
20421.59Skamil		case SIGFPE:
20431.59Skamil			trigger_fpe();
20441.59Skamil			break;
20451.59Skamil		case SIGBUS:
20461.59Skamil			trigger_bus();
20471.59Skamil			break;
20481.59Skamil		default:
20491.59Skamil			/* NOTREACHED */
20501.59Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
20511.59Skamil		}
20521.59Skamil
20531.59Skamil		/* NOTREACHED */
20541.59Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
20551.59Skamil	}
20561.59Skamil
20571.59Skamil	DPRINTF("Spawn debugger\n");
20581.59Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
20591.59Skamil	tracer = atf_utils_fork();
20601.59Skamil	if (tracer == 0) {
20611.59Skamil		/* Fork again and drop parent to reattach to PID 1 */
20621.59Skamil		tracer = atf_utils_fork();
20631.59Skamil		if (tracer != 0)
20641.61Skre			_exit(exitval);
20651.59Skamil
20661.59Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
20671.59Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
20681.59Skamil
20691.59Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
20701.59Skamil		FORKEE_REQUIRE_SUCCESS(
20711.59Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
20721.59Skamil
20731.59Skamil		forkee_status_stopped(status, SIGSTOP);
20741.59Skamil
20751.94Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
20761.94Skamil		    "traced process\n");
20771.94Skamil		SYSCALL_REQUIRE(
20781.94Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
20791.94Skamil
20801.94Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
20811.94Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
20821.94Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
20831.94Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
20841.94Skamil
20851.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
20861.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
20871.94Skamil
20881.59Skamil		/* Resume tracee with PT_CONTINUE */
20891.59Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
20901.59Skamil
20911.59Skamil		/* Inform parent that tracer has attached to tracee */
20921.59Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
20931.59Skamil
20941.59Skamil		/* Wait for parent to tell use that tracee should have exited */
20951.59Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
20961.59Skamil
20971.59Skamil		/* Wait for tracee and assert that it exited */
20981.59Skamil		FORKEE_REQUIRE_SUCCESS(
20991.59Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
21001.59Skamil
21011.94Skamil		forkee_status_stopped(status, sigval);
21021.94Skamil
21031.94Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
21041.94Skamil		    "traced process\n");
21051.94Skamil		SYSCALL_REQUIRE(
21061.94Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
21071.94Skamil
21081.94Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
21091.94Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
21101.94Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
21111.94Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
21121.94Skamil
21131.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
21141.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
21151.94Skamil
21161.94Skamil		name[0] = CTL_KERN,
21171.94Skamil		name[1] = KERN_PROC2,
21181.94Skamil		name[2] = KERN_PROC_PID;
21191.94Skamil		name[3] = tracee;
21201.94Skamil		name[4] = sizeof(kp);
21211.94Skamil		name[5] = 1;
21221.94Skamil
21231.94Skamil		FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
21241.94Skamil
21251.94Skamil		if (masked)
21261.94Skamil			kp_sigmask = kp.p_sigmask;
21271.94Skamil
21281.94Skamil		if (ignored)
21291.94Skamil			kp_sigignore = kp.p_sigignore;
21301.94Skamil
21311.94Skamil		/* Resume tracee with PT_CONTINUE */
21321.94Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
21331.94Skamil
21341.94Skamil		/* Wait for tracee and assert that it exited */
21351.94Skamil		FORKEE_REQUIRE_SUCCESS(
21361.94Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
21371.94Skamil
21381.93Skamil		forkee_status_stopped(status, sig);
21391.59Skamil
21401.59Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
21411.61Skre		    "traced process\n");
21421.61Skre		SYSCALL_REQUIRE(
21431.61Skre		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
21441.59Skamil
21451.59Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
21461.59Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
21471.61Skre		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
21481.61Skre		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
21491.59Skamil
21501.93Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sig);
21511.94Skamil
21521.94Skamil		FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
21531.94Skamil
21541.94Skamil		if (masked) {
21551.94Skamil			DPRINTF("kp_sigmask="
21561.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21571.94Skamil			    PRIx32 "\n",
21581.94Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
21591.94Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
21601.94Skamil
21611.94Skamil			DPRINTF("kp.p_sigmask="
21621.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21631.94Skamil			    PRIx32 "\n",
21641.94Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
21651.94Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
21661.94Skamil
21671.94Skamil			FORKEE_ASSERTX(!memcmp(&kp_sigmask, &kp.p_sigmask,
21681.94Skamil			    sizeof(kp_sigmask)));
21691.94Skamil		}
21701.94Skamil
21711.94Skamil		if (ignored) {
21721.94Skamil			DPRINTF("kp_sigignore="
21731.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21741.94Skamil			    PRIx32 "\n",
21751.94Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
21761.94Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
21771.94Skamil
21781.94Skamil			DPRINTF("kp.p_sigignore="
21791.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21801.94Skamil			    PRIx32 "\n",
21811.94Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
21821.94Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
21831.94Skamil
21841.94Skamil			FORKEE_ASSERTX(!memcmp(&kp_sigignore, &kp.p_sigignore,
21851.94Skamil			    sizeof(kp_sigignore)));
21861.94Skamil		}
21871.94Skamil
21881.59Skamil		switch (sig) {
21891.59Skamil		case SIGTRAP:
21901.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
21911.59Skamil			break;
21921.59Skamil		case SIGSEGV:
21931.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
21941.59Skamil			break;
21951.71Skamil		case SIGILL:
21961.113Skamil			FORKEE_ASSERT(info.psi_siginfo.si_code >= ILL_ILLOPC &&
21971.112Skamil			            info.psi_siginfo.si_code <= ILL_BADSTK);
21981.71Skamil			break;
21991.59Skamil		case SIGFPE:
22001.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
22011.59Skamil			break;
22021.59Skamil		case SIGBUS:
22031.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
22041.59Skamil			break;
22051.59Skamil		}
22061.59Skamil
22071.59Skamil		FORKEE_ASSERT(ptrace(PT_KILL, tracee, NULL, 0) != -1);
22081.59Skamil		DPRINTF("Before calling %s() for the tracee\n", TWAIT_FNAME);
22091.93Skamil		FORKEE_REQUIRE_SUCCESS(
22101.61Skre		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
22111.59Skamil
22121.93Skamil		forkee_status_signaled(status, SIGKILL, 0);
22131.59Skamil
22141.71Skamil		/* Inform parent that tracer is exiting normally */
22151.71Skamil		CHILD_TO_PARENT("tracer done", parent_tracer, msg);
22161.71Skamil
22171.59Skamil		DPRINTF("Before exiting of the tracer process\n");
22181.59Skamil		_exit(0 /* collect by initproc */);
22191.59Skamil	}
22201.59Skamil
22211.59Skamil	DPRINTF("Wait for the tracer process (direct child) to exit "
22221.59Skamil	    "calling %s()\n", TWAIT_FNAME);
22231.59Skamil	TWAIT_REQUIRE_SUCCESS(
22241.59Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
22251.59Skamil
22261.59Skamil	validate_status_exited(status, exitval);
22271.59Skamil
22281.59Skamil	DPRINTF("Wait for the non-exited tracee process with %s()\n",
22291.59Skamil	    TWAIT_FNAME);
22301.59Skamil	TWAIT_REQUIRE_SUCCESS(
22311.59Skamil	    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
22321.59Skamil
22331.59Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
22341.59Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
22351.59Skamil
22361.59Skamil	DPRINTF("Resume the tracee and let it crash\n");
22371.59Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
22381.59Skamil
22391.59Skamil	DPRINTF("Resume the tracer and let it detect crashed tracee\n");
22401.59Skamil	PARENT_TO_CHILD("Message 2", parent_tracer, msg);
22411.59Skamil
22421.59Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
22431.59Skamil	    TWAIT_FNAME);
22441.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
22451.59Skamil
22461.59Skamil	validate_status_signaled(status, SIGKILL, 0);
22471.59Skamil
22481.71Skamil	DPRINTF("Await normal exit of tracer\n");
22491.71Skamil	PARENT_FROM_CHILD("tracer done", parent_tracer, msg);
22501.71Skamil
22511.59Skamil	msg_close(&parent_tracer);
22521.59Skamil	msg_close(&parent_tracee);
22531.59Skamil}
22541.59Skamil
22551.61Skre#define UNRELATED_TRACER_SEES_CRASH(test, sig)				\
22561.61SkreATF_TC(test);								\
22571.61SkreATF_TC_HEAD(test, tc)							\
22581.61Skre{									\
22591.61Skre	atf_tc_set_md_var(tc, "descr",					\
22601.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
22611.94Skamil	    "the debuggee");						\
22621.61Skre}									\
22631.61Skre									\
22641.61SkreATF_TC_BODY(test, tc)							\
22651.61Skre{									\
22661.61Skre									\
22671.94Skamil	unrelated_tracer_sees_crash(sig, false, false);			\
22681.59Skamil}
22691.59Skamil
22701.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_trap, SIGTRAP)
22711.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_segv, SIGSEGV)
22721.71SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_ill, SIGILL)
22731.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_fpe, SIGFPE)
22741.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_bus, SIGBUS)
22751.94Skamil
22761.94Skamil#define UNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(test, sig)		\
22771.94SkamilATF_TC(test);								\
22781.94SkamilATF_TC_HEAD(test, tc)							\
22791.94Skamil{									\
22801.94Skamil	atf_tc_set_md_var(tc, "descr",					\
22811.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
22821.94Skamil	    "the debuggee with masked signal");				\
22831.94Skamil}									\
22841.94Skamil									\
22851.94SkamilATF_TC_BODY(test, tc)							\
22861.94Skamil{									\
22871.94Skamil									\
22881.94Skamil	unrelated_tracer_sees_crash(sig, true, false);			\
22891.94Skamil}
22901.94Skamil
22911.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22921.94Skamil    unrelated_tracer_sees_signalmasked_crash_trap, SIGTRAP)
22931.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22941.94Skamil    unrelated_tracer_sees_signalmasked_crash_segv, SIGSEGV)
22951.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22961.94Skamil    unrelated_tracer_sees_signalmasked_crash_ill, SIGILL)
22971.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22981.94Skamil    unrelated_tracer_sees_signalmasked_crash_fpe, SIGFPE)
22991.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
23001.94Skamil    unrelated_tracer_sees_signalmasked_crash_bus, SIGBUS)
23011.94Skamil
23021.94Skamil#define UNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(test, sig)		\
23031.94SkamilATF_TC(test);								\
23041.94SkamilATF_TC_HEAD(test, tc)							\
23051.94Skamil{									\
23061.94Skamil	atf_tc_set_md_var(tc, "descr",					\
23071.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
23081.94Skamil	    "the debuggee with signal ignored");			\
23091.94Skamil}									\
23101.94Skamil									\
23111.94SkamilATF_TC_BODY(test, tc)							\
23121.94Skamil{									\
23131.94Skamil									\
23141.94Skamil	unrelated_tracer_sees_crash(sig, false, true);			\
23151.94Skamil}
23161.94Skamil
23171.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23181.94Skamil    unrelated_tracer_sees_signalignored_crash_trap, SIGTRAP)
23191.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23201.94Skamil    unrelated_tracer_sees_signalignored_crash_segv, SIGSEGV)
23211.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23221.94Skamil    unrelated_tracer_sees_signalignored_crash_ill, SIGILL)
23231.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23241.94Skamil    unrelated_tracer_sees_signalignored_crash_fpe, SIGFPE)
23251.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23261.94Skamil    unrelated_tracer_sees_signalignored_crash_bus, SIGBUS)
23271.59Skamil#endif
23281.59Skamil
23291.59Skamil/// ----------------------------------------------------------------------------
23301.59Skamil
23311.59Skamil#if defined(TWAIT_HAVE_PID)
23321.59Skamilstatic void
23331.67Skamiltracer_sees_terminaton_before_the_parent_raw(bool notimeout, bool unrelated,
23341.67Skamil                                             bool stopped)
23351.1Skamil{
23361.51Skamil	/*
23371.51Skamil	 * notimeout - disable timeout in await zombie function
23381.51Skamil	 * unrelated - attach from unrelated tracer reparented to initproc
23391.67Skamil	 * stopped - attach to a stopped process
23401.51Skamil	 */
23411.1Skamil
23421.1Skamil	struct msg_fds parent_tracee, parent_tracer;
23431.1Skamil	const int exitval_tracee = 5;
23441.1Skamil	const int exitval_tracer = 10;
23451.1Skamil	pid_t tracee, tracer, wpid;
23461.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
23471.1Skamil#if defined(TWAIT_HAVE_STATUS)
23481.1Skamil	int status;
23491.1Skamil#endif
23501.1Skamil
23511.67Skamil	/*
23521.67Skamil	 * Only a subset of options are supported.
23531.67Skamil	 */
23541.67Skamil	ATF_REQUIRE((!notimeout && !unrelated && !stopped) ||
23551.67Skamil	            (!notimeout && unrelated && !stopped) ||
23561.67Skamil	            (notimeout && !unrelated && !stopped) ||
23571.67Skamil	            (!notimeout && unrelated && stopped));
23581.67Skamil
23591.13Schristos	DPRINTF("Spawn tracee\n");
23601.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
23611.1Skamil	tracee = atf_utils_fork();
23621.1Skamil	if (tracee == 0) {
23631.67Skamil		if (stopped) {
23641.67Skamil			DPRINTF("Stop self PID %d\n", getpid());
23651.67Skamil			raise(SIGSTOP);
23661.67Skamil		}
23671.67Skamil
23681.1Skamil		// Wait for parent to let us exit
23691.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
23701.1Skamil		_exit(exitval_tracee);
23711.1Skamil	}
23721.1Skamil
23731.13Schristos	DPRINTF("Spawn debugger\n");
23741.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
23751.1Skamil	tracer = atf_utils_fork();
23761.1Skamil	if (tracer == 0) {
23771.51Skamil		if(unrelated) {
23781.51Skamil			/* Fork again and drop parent to reattach to PID 1 */
23791.51Skamil			tracer = atf_utils_fork();
23801.51Skamil			if (tracer != 0)
23811.51Skamil				_exit(exitval_tracer);
23821.51Skamil		}
23831.51Skamil
23841.67Skamil		if (stopped) {
23851.67Skamil			DPRINTF("Await for a stopped parent PID %d\n", tracee);
23861.67Skamil			await_stopped(tracee);
23871.67Skamil		}
23881.67Skamil
23891.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
23901.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
23911.1Skamil
23921.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
23931.1Skamil		FORKEE_REQUIRE_SUCCESS(
23941.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
23951.1Skamil
23961.1Skamil		forkee_status_stopped(status, SIGSTOP);
23971.1Skamil
23981.1Skamil		/* Resume tracee with PT_CONTINUE */
23991.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
24001.1Skamil
24011.1Skamil		/* Inform parent that tracer has attached to tracee */
24021.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
24031.1Skamil
24041.1Skamil		/* Wait for parent to tell use that tracee should have exited */
24051.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
24061.1Skamil
24071.1Skamil		/* Wait for tracee and assert that it exited */
24081.1Skamil		FORKEE_REQUIRE_SUCCESS(
24091.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
24101.1Skamil
24111.1Skamil		forkee_status_exited(status, exitval_tracee);
24121.13Schristos		DPRINTF("Tracee %d exited with %d\n", tracee, exitval_tracee);
24131.1Skamil
24141.13Schristos		DPRINTF("Before exiting of the tracer process\n");
24151.51Skamil		_exit(unrelated ? 0 /* collect by initproc */ : exitval_tracer);
24161.51Skamil	}
24171.51Skamil
24181.51Skamil	if (unrelated) {
24191.51Skamil		DPRINTF("Wait for the tracer process (direct child) to exit "
24201.51Skamil		    "calling %s()\n", TWAIT_FNAME);
24211.51Skamil		TWAIT_REQUIRE_SUCCESS(
24221.51Skamil		    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
24231.51Skamil
24241.51Skamil		validate_status_exited(status, exitval_tracer);
24251.51Skamil
24261.51Skamil		DPRINTF("Wait for the non-exited tracee process with %s()\n",
24271.51Skamil		    TWAIT_FNAME);
24281.51Skamil		TWAIT_REQUIRE_SUCCESS(
24291.51Skamil		    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
24301.1Skamil	}
24311.1Skamil
24321.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
24331.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
24341.1Skamil
24351.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
24361.1Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
24371.1Skamil
24381.13Schristos	DPRINTF("Detect that tracee is zombie\n");
24391.51Skamil	if (notimeout)
24401.26Skamil		await_zombie_raw(tracee, 0);
24411.26Skamil	else
24421.26Skamil		await_zombie(tracee);
24431.1Skamil
24441.13Schristos	DPRINTF("Assert that there is no status about tracee %d - "
24451.1Skamil	    "Tracer must detect zombie first - calling %s()\n", tracee,
24461.1Skamil	    TWAIT_FNAME);
24471.1Skamil	TWAIT_REQUIRE_SUCCESS(
24481.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
24491.1Skamil
24501.51Skamil	if (unrelated) {
24511.51Skamil		DPRINTF("Resume the tracer and let it detect exited tracee\n");
24521.51Skamil		PARENT_TO_CHILD("Message 2", parent_tracer, msg);
24531.51Skamil	} else {
24541.51Skamil		DPRINTF("Tell the tracer child should have exited\n");
24551.51Skamil		PARENT_TO_CHILD("wait for tracee exit", parent_tracer,  msg);
24561.51Skamil		DPRINTF("Wait for tracer to finish its job and exit - calling "
24571.59Skamil			"%s()\n", TWAIT_FNAME);
24581.51Skamil
24591.51Skamil		DPRINTF("Wait from tracer child to complete waiting for "
24601.59Skamil			"tracee\n");
24611.51Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
24621.51Skamil		    tracer);
24631.1Skamil
24641.51Skamil		validate_status_exited(status, exitval_tracer);
24651.51Skamil	}
24661.1Skamil
24671.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
24681.1Skamil	    TWAIT_FNAME);
24691.51Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
24701.1Skamil
24711.1Skamil	validate_status_exited(status, exitval_tracee);
24721.1Skamil
24731.1Skamil	msg_close(&parent_tracer);
24741.1Skamil	msg_close(&parent_tracee);
24751.1Skamil}
24761.26Skamil
24771.51SkamilATF_TC(tracer_sees_terminaton_before_the_parent);
24781.51SkamilATF_TC_HEAD(tracer_sees_terminaton_before_the_parent, tc)
24791.51Skamil{
24801.51Skamil	atf_tc_set_md_var(tc, "descr",
24811.51Skamil	    "Assert that tracer sees process termination before the parent");
24821.51Skamil}
24831.51Skamil
24841.51SkamilATF_TC_BODY(tracer_sees_terminaton_before_the_parent, tc)
24851.26Skamil{
24861.26Skamil
24871.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, false, false);
24881.26Skamil}
24891.26Skamil
24901.51SkamilATF_TC(tracer_sysctl_lookup_without_duplicates);
24911.51SkamilATF_TC_HEAD(tracer_sysctl_lookup_without_duplicates, tc)
24921.1Skamil{
24931.164Skamil	atf_tc_set_md_var(tc, "timeout", "15");
24941.1Skamil	atf_tc_set_md_var(tc, "descr",
24951.51Skamil	    "Assert that await_zombie() in attach1 always finds a single "
24961.51Skamil	    "process and no other error is reported");
24971.1Skamil}
24981.1Skamil
24991.51SkamilATF_TC_BODY(tracer_sysctl_lookup_without_duplicates, tc)
25001.1Skamil{
25011.51Skamil	time_t start, end;
25021.51Skamil	double diff;
25031.51Skamil	unsigned long N = 0;
25041.1Skamil
25051.51Skamil	/*
25061.51Skamil	 * Reuse this test with tracer_sees_terminaton_before_the_parent_raw().
25071.51Skamil	 * This test body isn't specific to this race, however it's just good
25081.51Skamil	 * enough for this purposes, no need to invent a dedicated code flow.
25091.51Skamil	 */
25101.1Skamil
25111.51Skamil	start = time(NULL);
25121.51Skamil	while (true) {
25131.51Skamil		DPRINTF("Step: %lu\n", N);
25141.67Skamil		tracer_sees_terminaton_before_the_parent_raw(true, false,
25151.67Skamil		                                             false);
25161.51Skamil		end = time(NULL);
25171.51Skamil		diff = difftime(end, start);
25181.51Skamil		if (diff >= 5.0)
25191.51Skamil			break;
25201.51Skamil		++N;
25211.1Skamil	}
25221.51Skamil	DPRINTF("Iterations: %lu\n", N);
25231.51Skamil}
25241.1Skamil
25251.51SkamilATF_TC(unrelated_tracer_sees_terminaton_before_the_parent);
25261.51SkamilATF_TC_HEAD(unrelated_tracer_sees_terminaton_before_the_parent, tc)
25271.51Skamil{
25281.51Skamil	atf_tc_set_md_var(tc, "descr",
25291.51Skamil	    "Assert that tracer sees process termination before the parent");
25301.51Skamil}
25311.1Skamil
25321.51SkamilATF_TC_BODY(unrelated_tracer_sees_terminaton_before_the_parent, tc)
25331.51Skamil{
25341.1Skamil
25351.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, false);
25361.67Skamil}
25371.67Skamil
25381.67SkamilATF_TC(tracer_attach_to_unrelated_stopped_process);
25391.67SkamilATF_TC_HEAD(tracer_attach_to_unrelated_stopped_process, tc)
25401.67Skamil{
25411.67Skamil	atf_tc_set_md_var(tc, "descr",
25421.67Skamil	    "Assert that tracer can attach to an unrelated stopped process");
25431.67Skamil}
25441.67Skamil
25451.67SkamilATF_TC_BODY(tracer_attach_to_unrelated_stopped_process, tc)
25461.67Skamil{
25471.67Skamil
25481.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, true);
25491.1Skamil}
25501.1Skamil#endif
25511.1Skamil
25521.51Skamil/// ----------------------------------------------------------------------------
25531.51Skamil
25541.66Skamilstatic void
25551.66Skamilparent_attach_to_its_child(bool stopped)
25561.1Skamil{
25571.1Skamil	struct msg_fds parent_tracee;
25581.1Skamil	const int exitval_tracee = 5;
25591.1Skamil	pid_t tracee, wpid;
25601.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
25611.1Skamil#if defined(TWAIT_HAVE_STATUS)
25621.1Skamil	int status;
25631.1Skamil#endif
25641.1Skamil
25651.13Schristos	DPRINTF("Spawn tracee\n");
25661.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
25671.1Skamil	tracee = atf_utils_fork();
25681.1Skamil	if (tracee == 0) {
25691.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
25701.13Schristos		DPRINTF("Parent should now attach to tracee\n");
25711.1Skamil
25721.66Skamil		if (stopped) {
25731.66Skamil			DPRINTF("Stop self PID %d\n", getpid());
25741.66Skamil			SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
25751.66Skamil		}
25761.66Skamil
25771.1Skamil		CHILD_FROM_PARENT("Message 2", parent_tracee, msg);
25781.1Skamil		/* Wait for message from the parent */
25791.1Skamil		_exit(exitval_tracee);
25801.1Skamil	}
25811.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
25821.57Skamil
25831.66Skamil	if (stopped) {
25841.66Skamil		DPRINTF("Await for a stopped tracee PID %d\n", tracee);
25851.66Skamil		await_stopped(tracee);
25861.66Skamil	}
25871.66Skamil
25881.13Schristos	DPRINTF("Before calling PT_ATTACH for tracee %d\n", tracee);
25891.13Schristos	SYSCALL_REQUIRE(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
25901.1Skamil
25911.13Schristos	DPRINTF("Wait for the stopped tracee process with %s()\n",
25921.1Skamil	    TWAIT_FNAME);
25931.1Skamil	TWAIT_REQUIRE_SUCCESS(
25941.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
25951.1Skamil
25961.1Skamil	validate_status_stopped(status, SIGSTOP);
25971.1Skamil
25981.13Schristos	DPRINTF("Resume tracee with PT_CONTINUE\n");
25991.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
26001.1Skamil
26011.13Schristos	DPRINTF("Let the tracee exit now\n");
26021.1Skamil	PARENT_TO_CHILD("Message 2", parent_tracee, msg);
26031.1Skamil
26041.13Schristos	DPRINTF("Wait for tracee to exit with %s()\n", TWAIT_FNAME);
26051.1Skamil	TWAIT_REQUIRE_SUCCESS(
26061.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
26071.1Skamil
26081.1Skamil	validate_status_exited(status, exitval_tracee);
26091.1Skamil
26101.13Schristos	DPRINTF("Before calling %s() for tracee\n", TWAIT_FNAME);
26111.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
26121.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0));
26131.1Skamil
26141.1Skamil	msg_close(&parent_tracee);
26151.1Skamil}
26161.1Skamil
26171.66SkamilATF_TC(parent_attach_to_its_child);
26181.66SkamilATF_TC_HEAD(parent_attach_to_its_child, tc)
26191.66Skamil{
26201.66Skamil	atf_tc_set_md_var(tc, "descr",
26211.66Skamil	    "Assert that tracer parent can PT_ATTACH to its child");
26221.66Skamil}
26231.66Skamil
26241.66SkamilATF_TC_BODY(parent_attach_to_its_child, tc)
26251.66Skamil{
26261.66Skamil
26271.66Skamil	parent_attach_to_its_child(false);
26281.66Skamil}
26291.66Skamil
26301.66SkamilATF_TC(parent_attach_to_its_stopped_child);
26311.66SkamilATF_TC_HEAD(parent_attach_to_its_stopped_child, tc)
26321.66Skamil{
26331.66Skamil	atf_tc_set_md_var(tc, "descr",
26341.66Skamil	    "Assert that tracer parent can PT_ATTACH to its stopped child");
26351.66Skamil}
26361.66Skamil
26371.66SkamilATF_TC_BODY(parent_attach_to_its_stopped_child, tc)
26381.66Skamil{
26391.66Skamil
26401.66Skamil	parent_attach_to_its_child(true);
26411.66Skamil}
26421.66Skamil
26431.51Skamil/// ----------------------------------------------------------------------------
26441.51Skamil
26451.65Skamilstatic void
26461.65Skamilchild_attach_to_its_parent(bool stopped)
26471.1Skamil{
26481.1Skamil	struct msg_fds parent_tracee;
26491.1Skamil	const int exitval_tracer = 5;
26501.1Skamil	pid_t tracer, wpid;
26511.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
26521.1Skamil#if defined(TWAIT_HAVE_STATUS)
26531.1Skamil	int status;
26541.1Skamil#endif
26551.1Skamil
26561.13Schristos	DPRINTF("Spawn tracer\n");
26571.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
26581.1Skamil	tracer = atf_utils_fork();
26591.1Skamil	if (tracer == 0) {
26601.1Skamil		/* Wait for message from the parent */
26611.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
26621.1Skamil
26631.65Skamil		if (stopped) {
26641.65Skamil			DPRINTF("Await for a stopped parent PID %d\n",
26651.65Skamil			        getppid());
26661.65Skamil			await_stopped(getppid());
26671.65Skamil		}
26681.65Skamil
26691.13Schristos		DPRINTF("Attach to parent PID %d with PT_ATTACH from child\n",
26701.1Skamil		    getppid());
26711.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, getppid(), NULL, 0) != -1);
26721.1Skamil
26731.13Schristos		DPRINTF("Wait for the stopped parent process with %s()\n",
26741.1Skamil		    TWAIT_FNAME);
26751.1Skamil		FORKEE_REQUIRE_SUCCESS(
26761.1Skamil		    wpid = TWAIT_GENERIC(getppid(), &status, 0), getppid());
26771.1Skamil
26781.1Skamil		forkee_status_stopped(status, SIGSTOP);
26791.1Skamil
26801.13Schristos		DPRINTF("Resume parent with PT_DETACH\n");
26811.1Skamil		FORKEE_ASSERT(ptrace(PT_DETACH, getppid(), (void *)1, 0)
26821.1Skamil		    != -1);
26831.1Skamil
26841.1Skamil		/* Tell parent we are ready */
26851.1Skamil		CHILD_TO_PARENT("Message 1", parent_tracee, msg);
26861.1Skamil
26871.1Skamil		_exit(exitval_tracer);
26881.1Skamil	}
26891.1Skamil
26901.13Schristos	DPRINTF("Wait for the tracer to become ready\n");
26911.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
26921.65Skamil
26931.65Skamil	if (stopped) {
26941.65Skamil		DPRINTF("Stop self PID %d\n", getpid());
26951.65Skamil		SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
26961.65Skamil	}
26971.65Skamil
26981.13Schristos	DPRINTF("Allow the tracer to exit now\n");
26991.1Skamil	PARENT_FROM_CHILD("Message 1", parent_tracee, msg);
27001.1Skamil
27011.13Schristos	DPRINTF("Wait for tracer to exit with %s()\n", TWAIT_FNAME);
27021.1Skamil	TWAIT_REQUIRE_SUCCESS(
27031.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
27041.1Skamil
27051.1Skamil	validate_status_exited(status, exitval_tracer);
27061.1Skamil
27071.13Schristos	DPRINTF("Before calling %s() for tracer\n", TWAIT_FNAME);
27081.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
27091.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0));
27101.1Skamil
27111.1Skamil	msg_close(&parent_tracee);
27121.1Skamil}
27131.1Skamil
27141.65SkamilATF_TC(child_attach_to_its_parent);
27151.65SkamilATF_TC_HEAD(child_attach_to_its_parent, tc)
27161.65Skamil{
27171.65Skamil	atf_tc_set_md_var(tc, "descr",
27181.65Skamil	    "Assert that tracer child can PT_ATTACH to its parent");
27191.65Skamil}
27201.65Skamil
27211.65SkamilATF_TC_BODY(child_attach_to_its_parent, tc)
27221.65Skamil{
27231.65Skamil
27241.65Skamil	child_attach_to_its_parent(false);
27251.65Skamil}
27261.65Skamil
27271.65SkamilATF_TC(child_attach_to_its_stopped_parent);
27281.65SkamilATF_TC_HEAD(child_attach_to_its_stopped_parent, tc)
27291.65Skamil{
27301.65Skamil	atf_tc_set_md_var(tc, "descr",
27311.65Skamil	    "Assert that tracer child can PT_ATTACH to its stopped parent");
27321.65Skamil}
27331.65Skamil
27341.65SkamilATF_TC_BODY(child_attach_to_its_stopped_parent, tc)
27351.65Skamil{
27361.65Skamil	/*
27371.65Skamil	 * The ATF framework (atf-run) does not tolerate raise(SIGSTOP), as
27381.65Skamil	 * this causes a pipe (established from atf-run) to be broken.
27391.65Skamil	 * atf-run uses this mechanism to monitor whether a test is alive.
27401.65Skamil	 *
27411.65Skamil	 * As a workaround spawn this test as a subprocess.
27421.65Skamil	 */
27431.65Skamil
27441.65Skamil	const int exitval = 15;
27451.65Skamil	pid_t child, wpid;
27461.65Skamil#if defined(TWAIT_HAVE_STATUS)
27471.65Skamil	int status;
27481.65Skamil#endif
27491.65Skamil
27501.65Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
27511.65Skamil	if (child == 0) {
27521.65Skamil		child_attach_to_its_parent(true);
27531.65Skamil		_exit(exitval);
27541.65Skamil	} else {
27551.65Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
27561.65Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
27571.65Skamil
27581.65Skamil		validate_status_exited(status, exitval);
27591.65Skamil
27601.65Skamil		DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
27611.65Skamil		TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
27621.65Skamil	}
27631.65Skamil}
27641.65Skamil
27651.51Skamil/// ----------------------------------------------------------------------------
27661.51Skamil
27671.1Skamil#if defined(TWAIT_HAVE_PID)
27681.1Skamil
27691.51Skamilenum tracee_sees_its_original_parent_type {
27701.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
27711.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
27721.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS
27731.51Skamil};
27741.51Skamil
27751.51Skamilstatic void
27761.51Skamiltracee_sees_its_original_parent(enum tracee_sees_its_original_parent_type type)
27771.1Skamil{
27781.1Skamil	struct msg_fds parent_tracer, parent_tracee;
27791.1Skamil	const int exitval_tracee = 5;
27801.1Skamil	const int exitval_tracer = 10;
27811.1Skamil	pid_t parent, tracee, tracer, wpid;
27821.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
27831.1Skamil#if defined(TWAIT_HAVE_STATUS)
27841.1Skamil	int status;
27851.1Skamil#endif
27861.51Skamil	/* sysctl(3) - kinfo_proc2 */
27871.51Skamil	int name[CTL_MAXNAME];
27881.51Skamil	struct kinfo_proc2 kp;
27891.51Skamil	size_t len = sizeof(kp);
27901.51Skamil	unsigned int namelen;
27911.51Skamil
27921.51Skamil	/* procfs - status  */
27931.51Skamil	FILE *fp;
27941.51Skamil	struct stat st;
27951.51Skamil	const char *fname = "/proc/curproc/status";
27961.51Skamil	char s_executable[MAXPATHLEN];
27971.51Skamil	int s_pid, s_ppid;
27981.51Skamil	int rv;
27991.51Skamil
28001.51Skamil	if (type == TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS) {
28011.61Skre		SYSCALL_REQUIRE(
28021.61Skre		    (rv = stat(fname, &st)) == 0 || (errno == ENOENT));
28031.61Skre		if (rv != 0)
28041.51Skamil			atf_tc_skip("/proc/curproc/status not found");
28051.51Skamil	}
28061.1Skamil
28071.13Schristos	DPRINTF("Spawn tracee\n");
28081.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
28091.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
28101.1Skamil	tracee = atf_utils_fork();
28111.1Skamil	if (tracee == 0) {
28121.1Skamil		parent = getppid();
28131.1Skamil
28141.1Skamil		/* Emit message to the parent */
28151.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
28161.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
28171.1Skamil
28181.51Skamil		switch (type) {
28191.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID:
28201.51Skamil			FORKEE_ASSERT_EQ(parent, getppid());
28211.51Skamil			break;
28221.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2:
28231.51Skamil			namelen = 0;
28241.51Skamil			name[namelen++] = CTL_KERN;
28251.51Skamil			name[namelen++] = KERN_PROC2;
28261.51Skamil			name[namelen++] = KERN_PROC_PID;
28271.51Skamil			name[namelen++] = getpid();
28281.51Skamil			name[namelen++] = len;
28291.51Skamil			name[namelen++] = 1;
28301.51Skamil
28311.61Skre			FORKEE_ASSERT_EQ(
28321.61Skre			    sysctl(name, namelen, &kp, &len, NULL, 0), 0);
28331.51Skamil			FORKEE_ASSERT_EQ(parent, kp.p_ppid);
28341.51Skamil			break;
28351.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS:
28361.51Skamil			/*
28371.51Skamil			 * Format:
28381.51Skamil			 *  EXECUTABLE PID PPID ...
28391.51Skamil			 */
28401.51Skamil			FORKEE_ASSERT((fp = fopen(fname, "r")) != NULL);
28411.51Skamil			fscanf(fp, "%s %d %d", s_executable, &s_pid, &s_ppid);
28421.51Skamil			FORKEE_ASSERT_EQ(fclose(fp), 0);
28431.51Skamil			FORKEE_ASSERT_EQ(parent, s_ppid);
28441.51Skamil			break;
28451.51Skamil		}
28461.1Skamil
28471.1Skamil		_exit(exitval_tracee);
28481.1Skamil	}
28491.13Schristos	DPRINTF("Wait for child to record its parent identifier (pid)\n");
28501.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
28511.1Skamil
28521.13Schristos	DPRINTF("Spawn debugger\n");
28531.1Skamil	tracer = atf_utils_fork();
28541.1Skamil	if (tracer == 0) {
28551.1Skamil		/* No IPC to communicate with the child */
28561.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
28571.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
28581.1Skamil
28591.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
28601.1Skamil		FORKEE_REQUIRE_SUCCESS(
28611.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
28621.1Skamil
28631.1Skamil		forkee_status_stopped(status, SIGSTOP);
28641.1Skamil
28651.1Skamil		/* Resume tracee with PT_CONTINUE */
28661.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
28671.1Skamil
28681.1Skamil		/* Inform parent that tracer has attached to tracee */
28691.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
28701.1Skamil
28711.1Skamil		/* Wait for parent to tell use that tracee should have exited */
28721.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
28731.1Skamil
28741.1Skamil		/* Wait for tracee and assert that it exited */
28751.1Skamil		FORKEE_REQUIRE_SUCCESS(
28761.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
28771.1Skamil
28781.1Skamil		forkee_status_exited(status, exitval_tracee);
28791.1Skamil
28801.13Schristos		DPRINTF("Before exiting of the tracer process\n");
28811.1Skamil		_exit(exitval_tracer);
28821.1Skamil	}
28831.1Skamil
28841.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
28851.1Skamil	PARENT_FROM_CHILD("tracer ready",  parent_tracer, msg);
28861.1Skamil
28871.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
28881.1Skamil	PARENT_TO_CHILD("exit tracee",  parent_tracee, msg);
28891.1Skamil
28901.13Schristos	DPRINTF("Detect that tracee is zombie\n");
28911.1Skamil	await_zombie(tracee);
28921.1Skamil
28931.13Schristos	DPRINTF("Assert that there is no status about tracee - "
28941.1Skamil	    "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
28951.1Skamil	TWAIT_REQUIRE_SUCCESS(
28961.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
28971.1Skamil
28981.13Schristos	DPRINTF("Tell the tracer child should have exited\n");
28991.1Skamil	PARENT_TO_CHILD("wait for tracee exit",  parent_tracer, msg);
29001.1Skamil
29011.13Schristos	DPRINTF("Wait from tracer child to complete waiting for tracee\n");
29021.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
29031.1Skamil	    tracer);
29041.1Skamil
29051.1Skamil	validate_status_exited(status, exitval_tracer);
29061.1Skamil
29071.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
29081.1Skamil	    TWAIT_FNAME);
29091.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
29101.1Skamil	    tracee);
29111.1Skamil
29121.1Skamil	validate_status_exited(status, exitval_tracee);
29131.1Skamil
29141.1Skamil	msg_close(&parent_tracer);
29151.1Skamil	msg_close(&parent_tracee);
29161.1Skamil}
29171.1Skamil
29181.61Skre#define TRACEE_SEES_ITS_ORIGINAL_PARENT(test, type, descr)		\
29191.61SkreATF_TC(test);								\
29201.61SkreATF_TC_HEAD(test, tc)							\
29211.61Skre{									\
29221.61Skre	atf_tc_set_md_var(tc, "descr",					\
29231.61Skre	    "Assert that tracee sees its original parent when being traced " \
29241.61Skre	    "(check " descr ")");					\
29251.61Skre}									\
29261.61Skre									\
29271.61SkreATF_TC_BODY(test, tc)							\
29281.61Skre{									\
29291.61Skre									\
29301.61Skre	tracee_sees_its_original_parent(type);				\
29311.1Skamil}
29321.1Skamil
29331.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29341.51Skamil	tracee_sees_its_original_parent_getppid,
29351.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
29361.51Skamil	"getppid(2)");
29371.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29381.51Skamil	tracee_sees_its_original_parent_sysctl_kinfo_proc2,
29391.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
29401.51Skamil	"sysctl(3) and kinfo_proc2");
29411.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29421.51Skamil	tracee_sees_its_original_parent_procfs_status,
29431.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS,
29441.51Skamil	"the status file in procfs");
29451.1Skamil#endif
29461.1Skamil
29471.51Skamil/// ----------------------------------------------------------------------------
29481.1Skamil
29491.53Skamilstatic void
29501.53Skamileventmask_preserved(int event)
29511.1Skamil{
29521.1Skamil	const int exitval = 5;
29531.1Skamil	const int sigval = SIGSTOP;
29541.1Skamil	pid_t child, wpid;
29551.1Skamil#if defined(TWAIT_HAVE_STATUS)
29561.1Skamil	int status;
29571.1Skamil#endif
29581.1Skamil	ptrace_event_t set_event, get_event;
29591.1Skamil	const int len = sizeof(ptrace_event_t);
29601.1Skamil
29611.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
29621.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
29631.1Skamil	if (child == 0) {
29641.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
29651.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
29661.1Skamil
29671.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
29681.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
29691.1Skamil
29701.13Schristos		DPRINTF("Before exiting of the child process\n");
29711.1Skamil		_exit(exitval);
29721.1Skamil	}
29731.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
29741.1Skamil
29751.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29761.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
29771.1Skamil
29781.1Skamil	validate_status_stopped(status, sigval);
29791.1Skamil
29801.53Skamil	set_event.pe_set_event = event;
29811.61Skre	SYSCALL_REQUIRE(
29821.61Skre	    ptrace(PT_SET_EVENT_MASK, child, &set_event, len) != -1);
29831.61Skre	SYSCALL_REQUIRE(
29841.61Skre	    ptrace(PT_GET_EVENT_MASK, child, &get_event, len) != -1);
29851.125Skamil	DPRINTF("set_event=%#x get_event=%#x\n", set_event.pe_set_event,
29861.125Skamil	    get_event.pe_set_event);
29871.1Skamil	ATF_REQUIRE(memcmp(&set_event, &get_event, len) == 0);
29881.1Skamil
29891.13Schristos	DPRINTF("Before resuming the child process where it left off and "
29901.1Skamil	    "without signal to be sent\n");
29911.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
29921.1Skamil
29931.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29941.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
29951.1Skamil
29961.1Skamil	validate_status_exited(status, exitval);
29971.1Skamil
29981.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29991.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
30001.1Skamil}
30011.1Skamil
30021.61Skre#define EVENTMASK_PRESERVED(test, event)				\
30031.61SkreATF_TC(test);								\
30041.61SkreATF_TC_HEAD(test, tc)							\
30051.61Skre{									\
30061.61Skre	atf_tc_set_md_var(tc, "descr",					\
30071.61Skre	    "Verify that eventmask " #event " is preserved");		\
30081.61Skre}									\
30091.61Skre									\
30101.61SkreATF_TC_BODY(test, tc)							\
30111.61Skre{									\
30121.61Skre									\
30131.61Skre	eventmask_preserved(event);					\
30141.1Skamil}
30151.1Skamil
30161.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_empty, 0)
30171.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_fork, PTRACE_FORK)
30181.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_vfork, PTRACE_VFORK)
30191.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_vfork_done, PTRACE_VFORK_DONE)
30201.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_lwp_create, PTRACE_LWP_CREATE)
30211.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_lwp_exit, PTRACE_LWP_EXIT)
30221.125SkamilEVENTMASK_PRESERVED(eventmask_preserved_posix_spawn, PTRACE_POSIX_SPAWN)
30231.1Skamil
30241.53Skamil/// ----------------------------------------------------------------------------
30251.1Skamil
30261.28Skamilstatic void
30271.125Skamilfork_body(const char *fn, bool trackspawn, bool trackfork, bool trackvfork,
30281.105Skamil    bool trackvforkdone)
30291.1Skamil{
30301.1Skamil	const int exitval = 5;
30311.125Skamil	const int exitval2 = 0; /* This matched exit status from /bin/echo */
30321.1Skamil	const int sigval = SIGSTOP;
30331.31Skamil	pid_t child, child2 = 0, wpid;
30341.1Skamil#if defined(TWAIT_HAVE_STATUS)
30351.1Skamil	int status;
30361.1Skamil#endif
30371.1Skamil	ptrace_state_t state;
30381.1Skamil	const int slen = sizeof(state);
30391.1Skamil	ptrace_event_t event;
30401.1Skamil	const int elen = sizeof(event);
30411.1Skamil
30421.124Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
30431.124Skamil
30441.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
30451.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
30461.1Skamil	if (child == 0) {
30471.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
30481.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
30491.1Skamil
30501.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
30511.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
30521.1Skamil
30531.125Skamil		if (strcmp(fn, "spawn") == 0) {
30541.124Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
30551.124Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
30561.125Skamil		} else {
30571.125Skamil			if (strcmp(fn, "fork") == 0) {
30581.125Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
30591.125Skamil			} else if (strcmp(fn, "vfork") == 0) {
30601.125Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
30611.125Skamil			}
30621.1Skamil
30631.124Skamil			if (child2 == 0)
30641.124Skamil				_exit(exitval2);
30651.124Skamil		}
30661.1Skamil		FORKEE_REQUIRE_SUCCESS
30671.1Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
30681.1Skamil
30691.1Skamil		forkee_status_exited(status, exitval2);
30701.1Skamil
30711.13Schristos		DPRINTF("Before exiting of the child process\n");
30721.1Skamil		_exit(exitval);
30731.1Skamil	}
30741.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
30751.1Skamil
30761.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
30771.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
30781.1Skamil
30791.1Skamil	validate_status_stopped(status, sigval);
30801.1Skamil
30811.125Skamil	DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
30821.125Skamil	    trackspawn ? "|PTRACE_POSIX_SPAWN" : "",
30831.61Skre	    trackfork ? "|PTRACE_FORK" : "",
30841.61Skre	    trackvfork ? "|PTRACE_VFORK" : "",
30851.61Skre	    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", child);
30861.30Skamil	event.pe_set_event = 0;
30871.125Skamil	if (trackspawn)
30881.125Skamil		event.pe_set_event |= PTRACE_POSIX_SPAWN;
30891.30Skamil	if (trackfork)
30901.30Skamil		event.pe_set_event |= PTRACE_FORK;
30911.30Skamil	if (trackvfork)
30921.30Skamil		event.pe_set_event |= PTRACE_VFORK;
30931.30Skamil	if (trackvforkdone)
30941.30Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
30951.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
30961.1Skamil
30971.13Schristos	DPRINTF("Before resuming the child process where it left off and "
30981.1Skamil	    "without signal to be sent\n");
30991.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31001.1Skamil
31011.29Skamil#if defined(TWAIT_HAVE_PID)
31021.125Skamil	if ((trackspawn && strcmp(fn, "spawn") == 0) ||
31031.125Skamil	    (trackfork && strcmp(fn, "fork") == 0) ||
31041.125Skamil	    (trackvfork && strcmp(fn, "vfork") == 0)) {
31051.29Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
31061.61Skre		    child);
31071.29Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
31081.61Skre		    child);
31091.1Skamil
31101.29Skamil		validate_status_stopped(status, SIGTRAP);
31111.1Skamil
31121.61Skre		SYSCALL_REQUIRE(
31131.61Skre		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
31141.125Skamil		if (trackspawn && strcmp(fn, "spawn") == 0) {
31151.125Skamil			ATF_REQUIRE_EQ(
31161.125Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
31171.125Skamil			       PTRACE_POSIX_SPAWN);
31181.125Skamil		}
31191.125Skamil		if (trackfork && strcmp(fn, "fork") == 0) {
31201.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
31211.30Skamil			       PTRACE_FORK);
31221.30Skamil		}
31231.125Skamil		if (trackvfork && strcmp(fn, "vfork") == 0) {
31241.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
31251.30Skamil			       PTRACE_VFORK);
31261.30Skamil		}
31271.29Skamil
31281.29Skamil		child2 = state.pe_other_pid;
31291.30Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
31301.29Skamil
31311.29Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
31321.61Skre		    "%d\n", TWAIT_FNAME, child2, child);
31331.29Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
31341.29Skamil		    child2);
31351.1Skamil
31361.29Skamil		validate_status_stopped(status, SIGTRAP);
31371.1Skamil
31381.61Skre		SYSCALL_REQUIRE(
31391.61Skre		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
31401.125Skamil		if (trackspawn && strcmp(fn, "spawn") == 0) {
31411.125Skamil			ATF_REQUIRE_EQ(
31421.125Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
31431.125Skamil			       PTRACE_POSIX_SPAWN);
31441.125Skamil		}
31451.125Skamil		if (trackfork && strcmp(fn, "fork") == 0) {
31461.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
31471.30Skamil			       PTRACE_FORK);
31481.30Skamil		}
31491.125Skamil		if (trackvfork && strcmp(fn, "vfork") == 0) {
31501.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
31511.30Skamil			       PTRACE_VFORK);
31521.30Skamil		}
31531.30Skamil
31541.29Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
31551.29Skamil
31561.29Skamil		DPRINTF("Before resuming the forkee process where it left off "
31571.29Skamil		    "and without signal to be sent\n");
31581.61Skre		SYSCALL_REQUIRE(
31591.61Skre		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
31601.29Skamil
31611.29Skamil		DPRINTF("Before resuming the child process where it left off "
31621.61Skre		    "and without signal to be sent\n");
31631.29Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31641.30Skamil	}
31651.30Skamil#endif
31661.30Skamil
31671.125Skamil	if (trackvforkdone && strcmp(fn, "vfork") == 0) {
31681.30Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
31691.61Skre		    child);
31701.61Skre		TWAIT_REQUIRE_SUCCESS(
31711.61Skre		    wpid = TWAIT_GENERIC(child, &status, 0), child);
31721.30Skamil
31731.30Skamil		validate_status_stopped(status, SIGTRAP);
31741.30Skamil
31751.61Skre		SYSCALL_REQUIRE(
31761.61Skre		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
31771.30Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
31781.30Skamil
31791.30Skamil		child2 = state.pe_other_pid;
31801.30Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
31811.61Skre		    child2);
31821.30Skamil
31831.30Skamil		DPRINTF("Before resuming the child process where it left off "
31841.61Skre		    "and without signal to be sent\n");
31851.30Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31861.30Skamil	}
31871.29Skamil
31881.30Skamil#if defined(TWAIT_HAVE_PID)
31891.125Skamil	if ((trackspawn && strcmp(fn, "spawn") == 0) ||
31901.125Skamil	    (trackfork && strcmp(fn, "fork") == 0) ||
31911.125Skamil	    (trackvfork && strcmp(fn, "vfork") == 0)) {
31921.29Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
31931.61Skre		    "\n", TWAIT_FNAME);
31941.61Skre		TWAIT_REQUIRE_SUCCESS(
31951.61Skre		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
31961.29Skamil
31971.29Skamil		validate_status_exited(status, exitval2);
31981.29Skamil
31991.29Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
32001.61Skre		    "process\n", TWAIT_FNAME);
32011.29Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
32021.29Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
32031.29Skamil	}
32041.29Skamil#endif
32051.1Skamil
32061.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
32071.1Skamil	    "SIGCHLD\n", TWAIT_FNAME);
32081.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
32091.1Skamil
32101.1Skamil	validate_status_stopped(status, SIGCHLD);
32111.1Skamil
32121.13Schristos	DPRINTF("Before resuming the child process where it left off and "
32131.1Skamil	    "without signal to be sent\n");
32141.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
32151.1Skamil
32161.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
32171.1Skamil	    TWAIT_FNAME);
32181.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
32191.1Skamil
32201.1Skamil	validate_status_exited(status, exitval);
32211.1Skamil
32221.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
32231.1Skamil	    TWAIT_FNAME);
32241.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
32251.1Skamil}
32261.28Skamil
32271.125Skamil#define FORK_TEST(name,fun,tspawn,tfork,tvfork,tvforkdone)		\
32281.61SkreATF_TC(name);								\
32291.61SkreATF_TC_HEAD(name, tc)							\
32301.61Skre{									\
32311.125Skamil	atf_tc_set_md_var(tc, "descr", "Verify " fun "() "		\
32321.125Skamil	    "called with 0%s%s%s%s in EVENT_MASK",			\
32331.126Skamil	    tspawn ? "|PTRACE_POSIX_SPAWN" : "",			\
32341.105Skamil	    tfork ? "|PTRACE_FORK" : "",				\
32351.105Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
32361.105Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
32371.61Skre}									\
32381.61Skre									\
32391.61SkreATF_TC_BODY(name, tc)							\
32401.61Skre{									\
32411.61Skre									\
32421.125Skamil	fork_body(fun, tspawn, tfork, tvfork, tvforkdone);		\
32431.32Skamil}
32441.32Skamil
32451.125SkamilFORK_TEST(fork1, "fork", false, false, false, false)
32461.31Skamil#if defined(TWAIT_HAVE_PID)
32471.125SkamilFORK_TEST(fork2, "fork", false, true, false, false)
32481.125SkamilFORK_TEST(fork3, "fork", false, false, true, false)
32491.125SkamilFORK_TEST(fork4, "fork", false, true, true, false)
32501.31Skamil#endif
32511.125SkamilFORK_TEST(fork5, "fork", false, false, false, true)
32521.31Skamil#if defined(TWAIT_HAVE_PID)
32531.125SkamilFORK_TEST(fork6, "fork", false, true, false, true)
32541.125SkamilFORK_TEST(fork7, "fork", false, false, true, true)
32551.125SkamilFORK_TEST(fork8, "fork", false, true, true, true)
32561.125Skamil#endif
32571.125SkamilFORK_TEST(fork9, "fork", true, false, false, false)
32581.125Skamil#if defined(TWAIT_HAVE_PID)
32591.125SkamilFORK_TEST(fork10, "fork", true, true, false, false)
32601.125SkamilFORK_TEST(fork11, "fork", true, false, true, false)
32611.125SkamilFORK_TEST(fork12, "fork", true, true, true, false)
32621.125Skamil#endif
32631.125SkamilFORK_TEST(fork13, "fork", true, false, false, true)
32641.125Skamil#if defined(TWAIT_HAVE_PID)
32651.125SkamilFORK_TEST(fork14, "fork", true, true, false, true)
32661.125SkamilFORK_TEST(fork15, "fork", true, false, true, true)
32671.125SkamilFORK_TEST(fork16, "fork", true, true, true, true)
32681.31Skamil#endif
32691.1Skamil
32701.125SkamilFORK_TEST(vfork1, "vfork", false, false, false, false)
32711.31Skamil#if defined(TWAIT_HAVE_PID)
32721.125SkamilFORK_TEST(vfork2, "vfork", false, true, false, false)
32731.125SkamilFORK_TEST(vfork3, "vfork", false, false, true, false)
32741.125SkamilFORK_TEST(vfork4, "vfork", false, true, true, false)
32751.31Skamil#endif
32761.125SkamilFORK_TEST(vfork5, "vfork", false, false, false, true)
32771.31Skamil#if defined(TWAIT_HAVE_PID)
32781.125SkamilFORK_TEST(vfork6, "vfork", false, true, false, true)
32791.125SkamilFORK_TEST(vfork7, "vfork", false, false, true, true)
32801.125SkamilFORK_TEST(vfork8, "vfork", false, true, true, true)
32811.31Skamil#endif
32821.125SkamilFORK_TEST(vfork9, "vfork", true, false, false, false)
32831.125Skamil#if defined(TWAIT_HAVE_PID)
32841.125SkamilFORK_TEST(vfork10, "vfork", true, true, false, false)
32851.125SkamilFORK_TEST(vfork11, "vfork", true, false, true, false)
32861.125SkamilFORK_TEST(vfork12, "vfork", true, true, true, false)
32871.110Skamil#endif
32881.125SkamilFORK_TEST(vfork13, "vfork", true, false, false, true)
32891.124Skamil#if defined(TWAIT_HAVE_PID)
32901.125SkamilFORK_TEST(vfork14, "vfork", true, true, false, true)
32911.125SkamilFORK_TEST(vfork15, "vfork", true, false, true, true)
32921.125SkamilFORK_TEST(vfork16, "vfork", true, true, true, true)
32931.124Skamil#endif
32941.125Skamil
32951.125SkamilFORK_TEST(posix_spawn1, "spawn", false, false, false, false)
32961.125SkamilFORK_TEST(posix_spawn2, "spawn", false, true, false, false)
32971.125SkamilFORK_TEST(posix_spawn3, "spawn", false, false, true, false)
32981.125SkamilFORK_TEST(posix_spawn4, "spawn", false, true, true, false)
32991.125SkamilFORK_TEST(posix_spawn5, "spawn", false, false, false, true)
33001.125SkamilFORK_TEST(posix_spawn6, "spawn", false, true, false, true)
33011.125SkamilFORK_TEST(posix_spawn7, "spawn", false, false, true, true)
33021.125SkamilFORK_TEST(posix_spawn8, "spawn", false, true, true, true)
33031.124Skamil#if defined(TWAIT_HAVE_PID)
33041.125SkamilFORK_TEST(posix_spawn9, "spawn", true, false, false, false)
33051.125SkamilFORK_TEST(posix_spawn10, "spawn", true, true, false, false)
33061.125SkamilFORK_TEST(posix_spawn11, "spawn", true, false, true, false)
33071.125SkamilFORK_TEST(posix_spawn12, "spawn", true, true, true, false)
33081.125SkamilFORK_TEST(posix_spawn13, "spawn", true, false, false, true)
33091.125SkamilFORK_TEST(posix_spawn14, "spawn", true, true, false, true)
33101.125SkamilFORK_TEST(posix_spawn15, "spawn", true, false, true, true)
33111.125SkamilFORK_TEST(posix_spawn16, "spawn", true, true, true, true)
33121.124Skamil#endif
33131.124Skamil
33141.54Skamil/// ----------------------------------------------------------------------------
33151.31Skamil
33161.116Skamil#if defined(TWAIT_HAVE_PID)
33171.116Skamilstatic void
33181.149Skamilunrelated_tracer_fork_body(const char *fn, bool trackspawn, bool trackfork,
33191.149Skamil    bool trackvfork, bool trackvforkdone)
33201.149Skamil{
33211.149Skamil	const int sigval = SIGSTOP;
33221.149Skamil	struct msg_fds parent_tracee, parent_tracer;
33231.149Skamil	const int exitval = 10;
33241.149Skamil	const int exitval2 = 0; /* This matched exit status from /bin/echo */
33251.149Skamil	pid_t tracee, tracer, wpid;
33261.149Skamil	pid_t tracee2 = 0;
33271.149Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
33281.149Skamil#if defined(TWAIT_HAVE_STATUS)
33291.149Skamil	int status;
33301.149Skamil#endif
33311.149Skamil
33321.149Skamil	struct ptrace_siginfo info;
33331.149Skamil	ptrace_state_t state;
33341.149Skamil	const int slen = sizeof(state);
33351.149Skamil	ptrace_event_t event;
33361.149Skamil	const int elen = sizeof(event);
33371.149Skamil
33381.149Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
33391.149Skamil
33401.149Skamil	DPRINTF("Spawn tracee\n");
33411.149Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
33421.149Skamil	tracee = atf_utils_fork();
33431.149Skamil	if (tracee == 0) {
33441.149Skamil		// Wait for parent to let us crash
33451.149Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
33461.149Skamil
33471.149Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
33481.149Skamil		FORKEE_ASSERT(raise(sigval) == 0);
33491.149Skamil
33501.149Skamil		if (strcmp(fn, "spawn") == 0) {
33511.149Skamil			FORKEE_ASSERT_EQ(posix_spawn(&tracee2,
33521.149Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
33531.149Skamil		} else {
33541.149Skamil			if (strcmp(fn, "fork") == 0) {
33551.149Skamil				FORKEE_ASSERT((tracee2 = fork()) != -1);
33561.149Skamil			} else if (strcmp(fn, "vfork") == 0) {
33571.149Skamil				FORKEE_ASSERT((tracee2 = vfork()) != -1);
33581.149Skamil			}
33591.149Skamil
33601.149Skamil			if (tracee2 == 0)
33611.149Skamil				_exit(exitval2);
33621.149Skamil		}
33631.149Skamil		FORKEE_REQUIRE_SUCCESS
33641.149Skamil		    (wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
33651.149Skamil
33661.149Skamil		forkee_status_exited(status, exitval2);
33671.149Skamil
33681.149Skamil		DPRINTF("Before exiting of the child process\n");
33691.149Skamil		_exit(exitval);
33701.149Skamil	}
33711.149Skamil
33721.149Skamil	DPRINTF("Spawn debugger\n");
33731.149Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
33741.149Skamil	tracer = atf_utils_fork();
33751.149Skamil	if (tracer == 0) {
33761.149Skamil		/* Fork again and drop parent to reattach to PID 1 */
33771.149Skamil		tracer = atf_utils_fork();
33781.149Skamil		if (tracer != 0)
33791.149Skamil			_exit(exitval);
33801.149Skamil
33811.149Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
33821.149Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
33831.149Skamil
33841.149Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
33851.149Skamil		FORKEE_REQUIRE_SUCCESS(
33861.149Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
33871.149Skamil
33881.149Skamil		forkee_status_stopped(status, SIGSTOP);
33891.149Skamil
33901.149Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
33911.149Skamil		    "traced process\n");
33921.149Skamil		SYSCALL_REQUIRE(
33931.149Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
33941.149Skamil
33951.149Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
33961.149Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
33971.149Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
33981.149Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
33991.149Skamil
34001.149Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
34011.149Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
34021.149Skamil
34031.149Skamil		/* Resume tracee with PT_CONTINUE */
34041.149Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
34051.149Skamil
34061.149Skamil		/* Inform parent that tracer has attached to tracee */
34071.149Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
34081.149Skamil
34091.149Skamil		/* Wait for parent to tell use that tracee should have exited */
34101.149Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
34111.149Skamil
34121.149Skamil		/* Wait for tracee and assert that it exited */
34131.149Skamil		FORKEE_REQUIRE_SUCCESS(
34141.149Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
34151.149Skamil
34161.149Skamil		forkee_status_stopped(status, sigval);
34171.149Skamil
34181.149Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
34191.149Skamil		    "traced process\n");
34201.149Skamil		SYSCALL_REQUIRE(
34211.149Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
34221.149Skamil
34231.149Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
34241.149Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
34251.149Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
34261.149Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
34271.149Skamil
34281.149Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
34291.149Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
34301.149Skamil
34311.149Skamil		DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
34321.149Skamil		    trackspawn ? "|PTRACE_POSIX_SPAWN" : "",
34331.149Skamil		    trackfork ? "|PTRACE_FORK" : "",
34341.149Skamil		    trackvfork ? "|PTRACE_VFORK" : "",
34351.149Skamil		    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", tracee);
34361.149Skamil		event.pe_set_event = 0;
34371.149Skamil		if (trackspawn)
34381.149Skamil			event.pe_set_event |= PTRACE_POSIX_SPAWN;
34391.149Skamil		if (trackfork)
34401.149Skamil			event.pe_set_event |= PTRACE_FORK;
34411.149Skamil		if (trackvfork)
34421.149Skamil			event.pe_set_event |= PTRACE_VFORK;
34431.149Skamil		if (trackvforkdone)
34441.149Skamil			event.pe_set_event |= PTRACE_VFORK_DONE;
34451.149Skamil		SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, tracee, &event, elen)
34461.149Skamil		    != -1);
34471.149Skamil
34481.149Skamil		DPRINTF("Before resuming the child process where it left off "
34491.149Skamil		    "and without signal to be sent\n");
34501.149Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
34511.149Skamil
34521.149Skamil		if ((trackspawn && strcmp(fn, "spawn") == 0) ||
34531.149Skamil		    (trackfork && strcmp(fn, "fork") == 0) ||
34541.149Skamil		    (trackvfork && strcmp(fn, "vfork") == 0)) {
34551.149Skamil			DPRINTF("Before calling %s() for the tracee %d\n", TWAIT_FNAME,
34561.149Skamil			    tracee);
34571.149Skamil			TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0),
34581.149Skamil			    tracee);
34591.149Skamil
34601.149Skamil			validate_status_stopped(status, SIGTRAP);
34611.149Skamil
34621.149Skamil			SYSCALL_REQUIRE(
34631.149Skamil			    ptrace(PT_GET_PROCESS_STATE, tracee, &state, slen) != -1);
34641.149Skamil			if (trackspawn && strcmp(fn, "spawn") == 0) {
34651.149Skamil				ATF_REQUIRE_EQ(
34661.149Skamil				    state.pe_report_event & PTRACE_POSIX_SPAWN,
34671.149Skamil				       PTRACE_POSIX_SPAWN);
34681.149Skamil			}
34691.149Skamil			if (trackfork && strcmp(fn, "fork") == 0) {
34701.149Skamil				ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
34711.149Skamil				       PTRACE_FORK);
34721.149Skamil			}
34731.149Skamil			if (trackvfork && strcmp(fn, "vfork") == 0) {
34741.149Skamil				ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
34751.149Skamil				       PTRACE_VFORK);
34761.149Skamil			}
34771.149Skamil
34781.149Skamil			tracee2 = state.pe_other_pid;
34791.149Skamil			DPRINTF("Reported ptrace event with forkee %d\n", tracee2);
34801.149Skamil
34811.149Skamil			DPRINTF("Before calling %s() for the forkee %d of the tracee "
34821.149Skamil			    "%d\n", TWAIT_FNAME, tracee2, tracee);
34831.149Skamil			TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee2, &status, 0),
34841.149Skamil			    tracee2);
34851.149Skamil
34861.149Skamil			validate_status_stopped(status, SIGTRAP);
34871.149Skamil
34881.149Skamil			SYSCALL_REQUIRE(
34891.149Skamil			    ptrace(PT_GET_PROCESS_STATE, tracee2, &state, slen) != -1);
34901.149Skamil			if (trackspawn && strcmp(fn, "spawn") == 0) {
34911.149Skamil				ATF_REQUIRE_EQ(
34921.149Skamil				    state.pe_report_event & PTRACE_POSIX_SPAWN,
34931.149Skamil				       PTRACE_POSIX_SPAWN);
34941.149Skamil			}
34951.149Skamil			if (trackfork && strcmp(fn, "fork") == 0) {
34961.149Skamil				ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
34971.149Skamil				       PTRACE_FORK);
34981.149Skamil			}
34991.149Skamil			if (trackvfork && strcmp(fn, "vfork") == 0) {
35001.149Skamil				ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
35011.149Skamil				       PTRACE_VFORK);
35021.149Skamil			}
35031.149Skamil
35041.149Skamil			ATF_REQUIRE_EQ(state.pe_other_pid, tracee);
35051.149Skamil
35061.149Skamil			DPRINTF("Before resuming the forkee process where it left off "
35071.149Skamil			    "and without signal to be sent\n");
35081.149Skamil			SYSCALL_REQUIRE(
35091.149Skamil			    ptrace(PT_CONTINUE, tracee2, (void *)1, 0) != -1);
35101.149Skamil
35111.149Skamil			DPRINTF("Before resuming the tracee process where it left off "
35121.149Skamil			    "and without signal to be sent\n");
35131.149Skamil			SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
35141.149Skamil		}
35151.149Skamil
35161.149Skamil		if (trackvforkdone && strcmp(fn, "vfork") == 0) {
35171.149Skamil			DPRINTF("Before calling %s() for the tracee %d\n", TWAIT_FNAME,
35181.149Skamil			    tracee);
35191.149Skamil			TWAIT_REQUIRE_SUCCESS(
35201.149Skamil			    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
35211.149Skamil
35221.149Skamil			validate_status_stopped(status, SIGTRAP);
35231.149Skamil
35241.149Skamil			SYSCALL_REQUIRE(
35251.149Skamil			    ptrace(PT_GET_PROCESS_STATE, tracee, &state, slen) != -1);
35261.149Skamil			ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
35271.149Skamil
35281.149Skamil			tracee2 = state.pe_other_pid;
35291.149Skamil			DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
35301.149Skamil			    tracee2);
35311.149Skamil
35321.149Skamil			DPRINTF("Before resuming the tracee process where it left off "
35331.149Skamil			    "and without signal to be sent\n");
35341.149Skamil			SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
35351.149Skamil		}
35361.149Skamil
35371.149Skamil
35381.149Skamil		if ((trackspawn && strcmp(fn, "spawn") == 0) ||
35391.149Skamil		    (trackfork && strcmp(fn, "fork") == 0) ||
35401.149Skamil		    (trackvfork && strcmp(fn, "vfork") == 0)) {
35411.149Skamil			DPRINTF("Before calling %s() for the forkee - expected exited"
35421.149Skamil			    "\n", TWAIT_FNAME);
35431.149Skamil			TWAIT_REQUIRE_SUCCESS(
35441.149Skamil			    wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
35451.149Skamil
35461.149Skamil			validate_status_exited(status, exitval2);
35471.149Skamil
35481.149Skamil			DPRINTF("Before calling %s() for the forkee - expected no "
35491.149Skamil			    "process\n", TWAIT_FNAME);
35501.149Skamil			TWAIT_REQUIRE_FAILURE(ECHILD,
35511.149Skamil			    wpid = TWAIT_GENERIC(tracee2, &status, 0));
35521.149Skamil		}
35531.149Skamil
35541.149Skamil		DPRINTF("Before calling %s() for the tracee - expected stopped "
35551.149Skamil		    "SIGCHLD\n", TWAIT_FNAME);
35561.149Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
35571.149Skamil
35581.149Skamil		validate_status_stopped(status, SIGCHLD);
35591.149Skamil
35601.149Skamil		DPRINTF("Before resuming the tracee process where it left off and "
35611.149Skamil		    "without signal to be sent\n");
35621.149Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
35631.149Skamil
35641.149Skamil		DPRINTF("Before calling %s() for the tracee - expected exited\n",
35651.149Skamil		    TWAIT_FNAME);
35661.149Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
35671.149Skamil
35681.149Skamil		validate_status_exited(status, exitval);
35691.149Skamil
35701.149Skamil		/* Inform parent that tracer is exiting normally */
35711.149Skamil		CHILD_TO_PARENT("tracer done", parent_tracer, msg);
35721.149Skamil
35731.149Skamil		DPRINTF("Before exiting of the tracer process\n");
35741.149Skamil		_exit(0 /* collect by initproc */);
35751.149Skamil	}
35761.149Skamil
35771.149Skamil	DPRINTF("Wait for the tracer process (direct child) to exit "
35781.149Skamil	    "calling %s()\n", TWAIT_FNAME);
35791.149Skamil	TWAIT_REQUIRE_SUCCESS(
35801.149Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
35811.149Skamil
35821.149Skamil	validate_status_exited(status, exitval);
35831.149Skamil
35841.149Skamil	DPRINTF("Wait for the non-exited tracee process with %s()\n",
35851.149Skamil	    TWAIT_FNAME);
35861.149Skamil	TWAIT_REQUIRE_SUCCESS(
35871.149Skamil	    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
35881.149Skamil
35891.149Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
35901.149Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
35911.149Skamil
35921.149Skamil	DPRINTF("Resume the tracee and let it crash\n");
35931.149Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
35941.149Skamil
35951.149Skamil	DPRINTF("Resume the tracer and let it detect crashed tracee\n");
35961.149Skamil	PARENT_TO_CHILD("Message 2", parent_tracer, msg);
35971.149Skamil
35981.149Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
35991.149Skamil	    TWAIT_FNAME);
36001.149Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
36011.149Skamil
36021.149Skamil	validate_status_exited(status, exitval);
36031.149Skamil
36041.149Skamil	DPRINTF("Await normal exit of tracer\n");
36051.149Skamil	PARENT_FROM_CHILD("tracer done", parent_tracer, msg);
36061.149Skamil
36071.149Skamil	msg_close(&parent_tracer);
36081.149Skamil	msg_close(&parent_tracee);
36091.149Skamil}
36101.149Skamil
36111.149Skamil#define UNRELATED_TRACER_FORK_TEST(name,fun,tspawn,tfork,tvfork,tvforkdone)\
36121.149SkamilATF_TC(name);								\
36131.149SkamilATF_TC_HEAD(name, tc)							\
36141.149Skamil{									\
36151.149Skamil	atf_tc_set_md_var(tc, "descr", "Verify " fun "() "		\
36161.149Skamil	    "called with 0%s%s%s%s in EVENT_MASK",			\
36171.149Skamil	    tspawn ? "|PTRACE_POSIX_SPAWN" : "",			\
36181.149Skamil	    tfork ? "|PTRACE_FORK" : "",				\
36191.149Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
36201.149Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
36211.149Skamil}									\
36221.149Skamil									\
36231.149SkamilATF_TC_BODY(name, tc)							\
36241.149Skamil{									\
36251.149Skamil									\
36261.149Skamil	unrelated_tracer_fork_body(fun, tspawn, tfork, tvfork,		\
36271.149Skamil	    tvforkdone);						\
36281.149Skamil}
36291.149Skamil
36301.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork1, "fork", false, false, false, false)
36311.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork2, "fork", false, true, false, false)
36321.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork3, "fork", false, false, true, false)
36331.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork4, "fork", false, true, true, false)
36341.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork5, "fork", false, false, false, true)
36351.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork6, "fork", false, true, false, true)
36361.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork7, "fork", false, false, true, true)
36371.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork8, "fork", false, true, true, true)
36381.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork9, "fork", true, false, false, false)
36391.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork10, "fork", true, true, false, false)
36401.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork11, "fork", true, false, true, false)
36411.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork12, "fork", true, true, true, false)
36421.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork13, "fork", true, false, false, true)
36431.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork14, "fork", true, true, false, true)
36441.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork15, "fork", true, false, true, true)
36451.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork16, "fork", true, true, true, true)
36461.149Skamil
36471.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork1, "vfork", false, false, false, false)
36481.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork2, "vfork", false, true, false, false)
36491.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork3, "vfork", false, false, true, false)
36501.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork4, "vfork", false, true, true, false)
36511.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork5, "vfork", false, false, false, true)
36521.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork6, "vfork", false, true, false, true)
36531.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork7, "vfork", false, false, true, true)
36541.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork8, "vfork", false, true, true, true)
36551.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork9, "vfork", true, false, false, false)
36561.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork10, "vfork", true, true, false, false)
36571.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork11, "vfork", true, false, true, false)
36581.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork12, "vfork", true, true, true, false)
36591.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork13, "vfork", true, false, false, true)
36601.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork14, "vfork", true, true, false, true)
36611.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork15, "vfork", true, false, true, true)
36621.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork16, "vfork", true, true, true, true)
36631.149Skamil
36641.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn1, "spawn", false, false, false, false)
36651.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn2, "spawn", false, true, false, false)
36661.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn3, "spawn", false, false, true, false)
36671.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn4, "spawn", false, true, true, false)
36681.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn5, "spawn", false, false, false, true)
36691.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn6, "spawn", false, true, false, true)
36701.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn7, "spawn", false, false, true, true)
36711.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn8, "spawn", false, true, true, true)
36721.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn9, "spawn", true, false, false, false)
36731.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn10, "spawn", true, true, false, false)
36741.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn11, "spawn", true, false, true, false)
36751.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn12, "spawn", true, true, true, false)
36761.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn13, "spawn", true, false, false, true)
36771.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn14, "spawn", true, true, false, true)
36781.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn15, "spawn", true, false, true, true)
36791.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn16, "spawn", true, true, true, true)
36801.149Skamil#endif
36811.149Skamil
36821.149Skamil/// ----------------------------------------------------------------------------
36831.149Skamil
36841.149Skamil#if defined(TWAIT_HAVE_PID)
36851.149Skamilstatic void
36861.126Skamilfork_detach_forker_body(const char *fn, bool kill_process)
36871.116Skamil{
36881.116Skamil	const int exitval = 5;
36891.126Skamil	const int exitval2 = 0; /* Matches exit value from /bin/echo */
36901.116Skamil	const int sigval = SIGSTOP;
36911.116Skamil	pid_t child, child2 = 0, wpid;
36921.116Skamil#if defined(TWAIT_HAVE_STATUS)
36931.116Skamil	int status;
36941.116Skamil#endif
36951.116Skamil	ptrace_state_t state;
36961.116Skamil	const int slen = sizeof(state);
36971.116Skamil	ptrace_event_t event;
36981.116Skamil	const int elen = sizeof(event);
36991.116Skamil
37001.116Skamil	int op;
37011.116Skamil
37021.126Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
37031.116Skamil
37041.116Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
37051.116Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
37061.116Skamil	if (child == 0) {
37071.116Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
37081.116Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
37091.116Skamil
37101.116Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
37111.116Skamil		FORKEE_ASSERT(raise(sigval) == 0);
37121.116Skamil
37131.126Skamil		if (strcmp(fn, "spawn") == 0) {
37141.126Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
37151.126Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
37161.126Skamil		} else  {
37171.126Skamil			if (strcmp(fn, "fork") == 0) {
37181.126Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
37191.126Skamil			} else {
37201.126Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
37211.126Skamil			}
37221.116Skamil
37231.126Skamil			if (child2 == 0)
37241.126Skamil				_exit(exitval2);
37251.126Skamil		}
37261.116Skamil
37271.116Skamil		FORKEE_REQUIRE_SUCCESS
37281.116Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
37291.116Skamil
37301.116Skamil		forkee_status_exited(status, exitval2);
37311.116Skamil
37321.116Skamil		DPRINTF("Before exiting of the child process\n");
37331.116Skamil		_exit(exitval);
37341.116Skamil	}
37351.116Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
37361.116Skamil
37371.116Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
37381.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
37391.116Skamil
37401.116Skamil	validate_status_stopped(status, sigval);
37411.116Skamil
37421.116Skamil	DPRINTF("Set EVENT_MASK for the child %d\n", child);
37431.126Skamil	event.pe_set_event = PTRACE_POSIX_SPAWN | PTRACE_FORK | PTRACE_VFORK
37441.126Skamil		| PTRACE_VFORK_DONE;
37451.116Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
37461.116Skamil
37471.116Skamil	DPRINTF("Before resuming the child process where it left off and "
37481.116Skamil	    "without signal to be sent\n");
37491.116Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
37501.116Skamil
37511.116Skamil	DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME, child);
37521.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
37531.116Skamil
37541.116Skamil	validate_status_stopped(status, SIGTRAP);
37551.116Skamil
37561.116Skamil	SYSCALL_REQUIRE(
37571.116Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
37581.126Skamil
37591.126Skamil	if (strcmp(fn, "spawn") == 0)
37601.126Skamil		op = PTRACE_POSIX_SPAWN;
37611.126Skamil	else if (strcmp(fn, "fork") == 0)
37621.126Skamil		op = PTRACE_FORK;
37631.126Skamil	else
37641.126Skamil		op = PTRACE_VFORK;
37651.126Skamil
37661.116Skamil	ATF_REQUIRE_EQ(state.pe_report_event & op, op);
37671.116Skamil
37681.116Skamil	child2 = state.pe_other_pid;
37691.116Skamil	DPRINTF("Reported ptrace event with forkee %d\n", child2);
37701.116Skamil
37711.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
37721.126Skamil	    strcmp(fn, "vfork") == 0)
37731.116Skamil		op = kill_process ? PT_KILL : PT_DETACH;
37741.116Skamil	else
37751.116Skamil		op = PT_CONTINUE;
37761.116Skamil	SYSCALL_REQUIRE(ptrace(op, child, (void *)1, 0) != -1);
37771.116Skamil
37781.116Skamil	DPRINTF("Before calling %s() for the forkee %d of the child %d\n",
37791.116Skamil	    TWAIT_FNAME, child2, child);
37801.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0), child2);
37811.116Skamil
37821.116Skamil	validate_status_stopped(status, SIGTRAP);
37831.116Skamil
37841.116Skamil	SYSCALL_REQUIRE(
37851.116Skamil	    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
37861.126Skamil	if (strcmp(fn, "spawn") == 0)
37871.126Skamil		op = PTRACE_POSIX_SPAWN;
37881.126Skamil	else if (strcmp(fn, "fork") == 0)
37891.126Skamil		op = PTRACE_FORK;
37901.126Skamil	else
37911.126Skamil		op = PTRACE_VFORK;
37921.126Skamil
37931.116Skamil	ATF_REQUIRE_EQ(state.pe_report_event & op, op);
37941.116Skamil	ATF_REQUIRE_EQ(state.pe_other_pid, child);
37951.116Skamil
37961.116Skamil	DPRINTF("Before resuming the forkee process where it left off "
37971.116Skamil	    "and without signal to be sent\n");
37981.116Skamil 	SYSCALL_REQUIRE(
37991.116Skamil	    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
38001.116Skamil
38011.126Skamil	if (strcmp(fn, "vforkdone") == 0) {
38021.116Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
38031.116Skamil		    child);
38041.116Skamil		TWAIT_REQUIRE_SUCCESS(
38051.116Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
38061.116Skamil
38071.116Skamil		validate_status_stopped(status, SIGTRAP);
38081.116Skamil
38091.116Skamil		SYSCALL_REQUIRE(
38101.116Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
38111.116Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
38121.116Skamil
38131.116Skamil		child2 = state.pe_other_pid;
38141.116Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
38151.116Skamil		    child2);
38161.116Skamil
38171.116Skamil		op = kill_process ? PT_KILL : PT_DETACH;
38181.116Skamil		DPRINTF("Before resuming the child process where it left off "
38191.116Skamil		    "and without signal to be sent\n");
38201.116Skamil		SYSCALL_REQUIRE(ptrace(op, child, (void *)1, 0) != -1);
38211.116Skamil	}
38221.116Skamil
38231.116Skamil	DPRINTF("Before calling %s() for the forkee - expected exited\n",
38241.116Skamil	    TWAIT_FNAME);
38251.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0), child2);
38261.116Skamil
38271.116Skamil	validate_status_exited(status, exitval2);
38281.116Skamil
38291.116Skamil	DPRINTF("Before calling %s() for the forkee - expected no process\n",
38301.116Skamil	    TWAIT_FNAME);
38311.116Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child2, &status, 0));
38321.116Skamil
38331.116Skamil	DPRINTF("Before calling %s() for the forkee - expected exited\n",
38341.116Skamil	    TWAIT_FNAME);
38351.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
38361.116Skamil
38371.116Skamil	if (kill_process) {
38381.116Skamil		validate_status_signaled(status, SIGKILL, 0);
38391.116Skamil	} else {
38401.116Skamil		validate_status_exited(status, exitval);
38411.116Skamil	}
38421.116Skamil
38431.116Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
38441.116Skamil	    TWAIT_FNAME);
38451.116Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
38461.116Skamil}
38471.116Skamil
38481.126Skamil#define FORK_DETACH_FORKER(name,event,kprocess)				\
38491.116SkamilATF_TC(name);								\
38501.116SkamilATF_TC_HEAD(name, tc)							\
38511.116Skamil{									\
38521.126Skamil	atf_tc_set_md_var(tc, "descr", "Verify %s " event,		\
38531.126Skamil	    kprocess ? "killed" : "detached");				\
38541.116Skamil}									\
38551.116Skamil									\
38561.116SkamilATF_TC_BODY(name, tc)							\
38571.116Skamil{									\
38581.116Skamil									\
38591.126Skamil	fork_detach_forker_body(event, kprocess);			\
38601.116Skamil}
38611.116Skamil
38621.126SkamilFORK_DETACH_FORKER(posix_spawn_detach_spawner, "spawn", false)
38631.126SkamilFORK_DETACH_FORKER(fork_detach_forker, "fork", false)
38641.126SkamilFORK_DETACH_FORKER(vfork_detach_vforker, "vfork", false)
38651.126SkamilFORK_DETACH_FORKER(vfork_detach_vforkerdone, "vforkdone", false)
38661.126Skamil
38671.126SkamilFORK_DETACH_FORKER(posix_spawn_kill_spawner, "spawn", true)
38681.126SkamilFORK_DETACH_FORKER(fork_kill_forker, "fork", true)
38691.126SkamilFORK_DETACH_FORKER(vfork_kill_vforker, "vfork", true)
38701.126SkamilFORK_DETACH_FORKER(vfork_kill_vforkerdone, "vforkdone", true)
38711.116Skamil#endif
38721.116Skamil
38731.116Skamil/// ----------------------------------------------------------------------------
38741.116Skamil
38751.150Skamil#if defined(TWAIT_HAVE_PID)
38761.150Skamilstatic void
38771.150Skamilunrelated_tracer_fork_detach_forker_body(const char *fn, bool kill_process)
38781.150Skamil{
38791.150Skamil	const int sigval = SIGSTOP;
38801.150Skamil	struct msg_fds parent_tracee, parent_tracer;
38811.150Skamil	const int exitval = 10;
38821.150Skamil	const int exitval2 = 0; /* This matched exit status from /bin/echo */
38831.150Skamil	pid_t tracee, tracer, wpid;
38841.150Skamil	pid_t tracee2 = 0;
38851.150Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
38861.150Skamil#if defined(TWAIT_HAVE_STATUS)
38871.150Skamil	int status;
38881.150Skamil#endif
38891.150Skamil	int op;
38901.150Skamil
38911.150Skamil	struct ptrace_siginfo info;
38921.150Skamil	ptrace_state_t state;
38931.150Skamil	const int slen = sizeof(state);
38941.150Skamil	ptrace_event_t event;
38951.150Skamil	const int elen = sizeof(event);
38961.150Skamil
38971.150Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
38981.150Skamil
38991.150Skamil	DPRINTF("Spawn tracee\n");
39001.150Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
39011.150Skamil	tracee = atf_utils_fork();
39021.150Skamil	if (tracee == 0) {
39031.150Skamil		// Wait for parent to let us crash
39041.150Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
39051.150Skamil
39061.150Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
39071.150Skamil		FORKEE_ASSERT(raise(sigval) == 0);
39081.150Skamil
39091.150Skamil		if (strcmp(fn, "spawn") == 0) {
39101.150Skamil			FORKEE_ASSERT_EQ(posix_spawn(&tracee2,
39111.150Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
39121.150Skamil		} else  {
39131.150Skamil			if (strcmp(fn, "fork") == 0) {
39141.150Skamil				FORKEE_ASSERT((tracee2 = fork()) != -1);
39151.150Skamil			} else {
39161.150Skamil				FORKEE_ASSERT((tracee2 = vfork()) != -1);
39171.150Skamil			}
39181.150Skamil
39191.150Skamil			if (tracee2 == 0)
39201.150Skamil				_exit(exitval2);
39211.150Skamil		}
39221.150Skamil
39231.150Skamil		FORKEE_REQUIRE_SUCCESS
39241.150Skamil		    (wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
39251.150Skamil
39261.150Skamil		forkee_status_exited(status, exitval2);
39271.150Skamil
39281.150Skamil		DPRINTF("Before exiting of the child process\n");
39291.150Skamil		_exit(exitval);
39301.150Skamil	}
39311.150Skamil
39321.150Skamil	DPRINTF("Spawn debugger\n");
39331.150Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
39341.150Skamil	tracer = atf_utils_fork();
39351.150Skamil	if (tracer == 0) {
39361.150Skamil		/* Fork again and drop parent to reattach to PID 1 */
39371.150Skamil		tracer = atf_utils_fork();
39381.150Skamil		if (tracer != 0)
39391.150Skamil			_exit(exitval);
39401.150Skamil
39411.150Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
39421.150Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
39431.150Skamil
39441.150Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
39451.150Skamil		FORKEE_REQUIRE_SUCCESS(
39461.150Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
39471.150Skamil
39481.150Skamil		forkee_status_stopped(status, SIGSTOP);
39491.150Skamil
39501.150Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
39511.150Skamil		    "traced process\n");
39521.150Skamil		SYSCALL_REQUIRE(
39531.150Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
39541.150Skamil
39551.150Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
39561.150Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
39571.150Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
39581.150Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
39591.150Skamil
39601.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
39611.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
39621.150Skamil
39631.150Skamil		/* Resume tracee with PT_CONTINUE */
39641.150Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
39651.150Skamil
39661.150Skamil		/* Inform parent that tracer has attached to tracee */
39671.150Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
39681.150Skamil
39691.150Skamil		/* Wait for parent to tell use that tracee should have exited */
39701.150Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
39711.150Skamil
39721.150Skamil		/* Wait for tracee and assert that it exited */
39731.150Skamil		FORKEE_REQUIRE_SUCCESS(
39741.150Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
39751.150Skamil
39761.150Skamil		forkee_status_stopped(status, sigval);
39771.150Skamil
39781.150Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
39791.150Skamil		    "traced process\n");
39801.150Skamil		SYSCALL_REQUIRE(
39811.150Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
39821.150Skamil
39831.150Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
39841.150Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
39851.150Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
39861.150Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
39871.150Skamil
39881.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
39891.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
39901.150Skamil
39911.150Skamil		DPRINTF("Set EVENT_MASK for the child %d\n", tracee);
39921.150Skamil		event.pe_set_event = PTRACE_POSIX_SPAWN | PTRACE_FORK | PTRACE_VFORK
39931.150Skamil			| PTRACE_VFORK_DONE;
39941.150Skamil		SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, tracee, &event, elen) != -1);
39951.150Skamil
39961.150Skamil		DPRINTF("Before resuming the child process where it left off and "
39971.150Skamil		    "without signal to be sent\n");
39981.150Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
39991.150Skamil
40001.150Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME, tracee);
40011.150Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
40021.150Skamil
40031.150Skamil		validate_status_stopped(status, SIGTRAP);
40041.150Skamil
40051.150Skamil		SYSCALL_REQUIRE(
40061.150Skamil		    ptrace(PT_GET_PROCESS_STATE, tracee, &state, slen) != -1);
40071.150Skamil
40081.150Skamil		if (strcmp(fn, "spawn") == 0)
40091.150Skamil			op = PTRACE_POSIX_SPAWN;
40101.150Skamil		else if (strcmp(fn, "fork") == 0)
40111.150Skamil			op = PTRACE_FORK;
40121.150Skamil		else
40131.150Skamil			op = PTRACE_VFORK;
40141.150Skamil
40151.150Skamil		ATF_REQUIRE_EQ(state.pe_report_event & op, op);
40161.150Skamil
40171.150Skamil		tracee2 = state.pe_other_pid;
40181.150Skamil		DPRINTF("Reported ptrace event with forkee %d\n", tracee2);
40191.150Skamil		if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
40201.150Skamil		    strcmp(fn, "vfork") == 0)
40211.150Skamil			op = kill_process ? PT_KILL : PT_DETACH;
40221.150Skamil		else
40231.150Skamil			op = PT_CONTINUE;
40241.150Skamil		SYSCALL_REQUIRE(ptrace(op, tracee, (void *)1, 0) != -1);
40251.150Skamil
40261.150Skamil		DPRINTF("Before calling %s() for the forkee %d of the tracee %d\n",
40271.150Skamil		    TWAIT_FNAME, tracee2, tracee);
40281.150Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
40291.150Skamil
40301.150Skamil		validate_status_stopped(status, SIGTRAP);
40311.150Skamil
40321.150Skamil		SYSCALL_REQUIRE(
40331.150Skamil		    ptrace(PT_GET_PROCESS_STATE, tracee2, &state, slen) != -1);
40341.150Skamil		if (strcmp(fn, "spawn") == 0)
40351.150Skamil			op = PTRACE_POSIX_SPAWN;
40361.150Skamil		else if (strcmp(fn, "fork") == 0)
40371.150Skamil			op = PTRACE_FORK;
40381.150Skamil		else
40391.150Skamil			op = PTRACE_VFORK;
40401.150Skamil
40411.150Skamil		ATF_REQUIRE_EQ(state.pe_report_event & op, op);
40421.150Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, tracee);
40431.150Skamil
40441.150Skamil		DPRINTF("Before resuming the forkee process where it left off "
40451.150Skamil		    "and without signal to be sent\n");
40461.150Skamil		SYSCALL_REQUIRE(
40471.150Skamil		    ptrace(PT_CONTINUE, tracee2, (void *)1, 0) != -1);
40481.150Skamil
40491.150Skamil		if (strcmp(fn, "vforkdone") == 0) {
40501.150Skamil			DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
40511.150Skamil			    tracee);
40521.150Skamil			TWAIT_REQUIRE_SUCCESS(
40531.150Skamil			    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
40541.150Skamil
40551.150Skamil			validate_status_stopped(status, SIGTRAP);
40561.150Skamil
40571.150Skamil			SYSCALL_REQUIRE(
40581.150Skamil			    ptrace(PT_GET_PROCESS_STATE, tracee, &state, slen) != -1);
40591.150Skamil			ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
40601.150Skamil
40611.150Skamil			tracee2 = state.pe_other_pid;
40621.150Skamil			DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
40631.150Skamil			    tracee2);
40641.150Skamil
40651.150Skamil			op = kill_process ? PT_KILL : PT_DETACH;
40661.150Skamil			DPRINTF("Before resuming the child process where it left off "
40671.150Skamil			    "and without signal to be sent\n");
40681.150Skamil			SYSCALL_REQUIRE(ptrace(op, tracee, (void *)1, 0) != -1);
40691.150Skamil		}
40701.150Skamil
40711.150Skamil		DPRINTF("Before calling %s() for the forkee - expected exited\n",
40721.150Skamil		    TWAIT_FNAME);
40731.150Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
40741.150Skamil
40751.150Skamil		validate_status_exited(status, exitval2);
40761.150Skamil
40771.150Skamil		DPRINTF("Before calling %s() for the forkee - expected no process\n",
40781.150Skamil		    TWAIT_FNAME);
40791.150Skamil		TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(tracee2, &status, 0));
40801.150Skamil
40811.150Skamil		if (kill_process) {
40821.150Skamil			DPRINTF("Before calling %s() for the forkee - expected signaled\n",
40831.150Skamil			    TWAIT_FNAME);
40841.150Skamil			TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
40851.150Skamil
40861.150Skamil			validate_status_signaled(status, SIGKILL, 0);
40871.150Skamil		}
40881.150Skamil
40891.150Skamil		/* Inform parent that tracer is exiting normally */
40901.150Skamil		CHILD_TO_PARENT("tracer done", parent_tracer, msg);
40911.150Skamil
40921.150Skamil		DPRINTF("Before exiting of the tracer process\n");
40931.150Skamil		_exit(0 /* collect by initproc */);
40941.150Skamil	}
40951.150Skamil
40961.150Skamil	DPRINTF("Wait for the tracer process (direct child) to exit "
40971.150Skamil	    "calling %s()\n", TWAIT_FNAME);
40981.150Skamil	TWAIT_REQUIRE_SUCCESS(
40991.150Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
41001.150Skamil
41011.150Skamil	validate_status_exited(status, exitval);
41021.150Skamil
41031.150Skamil	DPRINTF("Wait for the non-exited tracee process with %s()\n",
41041.150Skamil	    TWAIT_FNAME);
41051.150Skamil	TWAIT_REQUIRE_SUCCESS(
41061.150Skamil	    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
41071.150Skamil
41081.150Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
41091.150Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
41101.150Skamil
41111.150Skamil	DPRINTF("Resume the tracee and let it crash\n");
41121.150Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
41131.150Skamil
41141.150Skamil	DPRINTF("Resume the tracer and let it detect crashed tracee\n");
41151.150Skamil	PARENT_TO_CHILD("Message 2", parent_tracer, msg);
41161.150Skamil
41171.150Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
41181.150Skamil	    TWAIT_FNAME);
41191.150Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
41201.150Skamil
41211.150Skamil	if (kill_process) {
41221.150Skamil		validate_status_signaled(status, SIGKILL, 0);
41231.150Skamil	} else {
41241.150Skamil		validate_status_exited(status, exitval);
41251.150Skamil	}
41261.150Skamil
41271.150Skamil	DPRINTF("Await normal exit of tracer\n");
41281.150Skamil	PARENT_FROM_CHILD("tracer done", parent_tracer, msg);
41291.150Skamil
41301.150Skamil	msg_close(&parent_tracer);
41311.150Skamil	msg_close(&parent_tracee);
41321.150Skamil}
41331.150Skamil
41341.150Skamil#define UNRELATED_TRACER_FORK_DETACH_FORKER(name,event,kprocess)	\
41351.150SkamilATF_TC(name);								\
41361.150SkamilATF_TC_HEAD(name, tc)							\
41371.150Skamil{									\
41381.150Skamil	atf_tc_set_md_var(tc, "descr", "Verify %s " event,		\
41391.150Skamil	    kprocess ? "killed" : "detached");				\
41401.150Skamil}									\
41411.150Skamil									\
41421.150SkamilATF_TC_BODY(name, tc)							\
41431.150Skamil{									\
41441.150Skamil									\
41451.150Skamil	unrelated_tracer_fork_detach_forker_body(event, kprocess);	\
41461.150Skamil}
41471.150Skamil
41481.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_posix_spawn_detach_spawner, "spawn", false)
41491.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_fork_detach_forker, "fork", false)
41501.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_vfork_detach_vforker, "vfork", false)
41511.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_vfork_detach_vforkerdone, "vforkdone", false)
41521.150Skamil
41531.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_posix_spawn_kill_spawner, "spawn", true)
41541.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_fork_kill_forker, "fork", true)
41551.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_vfork_kill_vforker, "vfork", true)
41561.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_vfork_kill_vforkerdone, "vforkdone", true)
41571.150Skamil#endif
41581.150Skamil
41591.150Skamil/// ----------------------------------------------------------------------------
41601.150Skamil
41611.108Skamilstatic void
41621.108Skamiltraceme_vfork_fork_body(pid_t (*fn)(void))
41631.108Skamil{
41641.108Skamil	const int exitval = 5;
41651.108Skamil	const int exitval2 = 15;
41661.108Skamil	pid_t child, child2 = 0, wpid;
41671.108Skamil#if defined(TWAIT_HAVE_STATUS)
41681.108Skamil	int status;
41691.108Skamil#endif
41701.108Skamil
41711.108Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
41721.108Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
41731.108Skamil	if (child == 0) {
41741.108Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
41751.108Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
41761.108Skamil
41771.108Skamil		FORKEE_ASSERT((child2 = (fn)()) != -1);
41781.108Skamil
41791.108Skamil		if (child2 == 0)
41801.108Skamil			_exit(exitval2);
41811.108Skamil
41821.108Skamil		FORKEE_REQUIRE_SUCCESS
41831.108Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
41841.108Skamil
41851.108Skamil		forkee_status_exited(status, exitval2);
41861.108Skamil
41871.108Skamil		DPRINTF("Before exiting of the child process\n");
41881.108Skamil		_exit(exitval);
41891.108Skamil	}
41901.108Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
41911.108Skamil
41921.108Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
41931.108Skamil	    TWAIT_FNAME);
41941.108Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
41951.108Skamil
41961.108Skamil	validate_status_exited(status, exitval);
41971.108Skamil
41981.108Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
41991.108Skamil	    TWAIT_FNAME);
42001.108Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
42011.108Skamil}
42021.108Skamil
42031.108Skamil#define TRACEME_VFORK_FORK_TEST(name,fun)				\
42041.108SkamilATF_TC(name);								\
42051.108SkamilATF_TC_HEAD(name, tc)							\
42061.108Skamil{									\
42071.108Skamil	atf_tc_set_md_var(tc, "descr", "Verify " #fun "(2) "		\
42081.108Skamil	    "called from vfork(2)ed child");				\
42091.108Skamil}									\
42101.108Skamil									\
42111.108SkamilATF_TC_BODY(name, tc)							\
42121.108Skamil{									\
42131.108Skamil									\
42141.108Skamil	traceme_vfork_fork_body(fun);					\
42151.108Skamil}
42161.108Skamil
42171.108SkamilTRACEME_VFORK_FORK_TEST(traceme_vfork_fork, fork)
42181.108SkamilTRACEME_VFORK_FORK_TEST(traceme_vfork_vfork, vfork)
42191.108Skamil
42201.108Skamil/// ----------------------------------------------------------------------------
42211.108Skamil
42221.54Skamilenum bytes_transfer_type {
42231.54Skamil	BYTES_TRANSFER_DATA,
42241.54Skamil	BYTES_TRANSFER_DATAIO,
42251.54Skamil	BYTES_TRANSFER_TEXT,
42261.54Skamil	BYTES_TRANSFER_TEXTIO,
42271.54Skamil	BYTES_TRANSFER_AUXV
42281.54Skamil};
42291.31Skamil
42301.54Skamilstatic int __used
42311.54Skamilbytes_transfer_dummy(int a, int b, int c, int d)
42321.54Skamil{
42331.54Skamil	int e, f, g, h;
42341.1Skamil
42351.54Skamil	a *= 4;
42361.54Skamil	b += 3;
42371.54Skamil	c -= 2;
42381.54Skamil	d /= 1;
42391.1Skamil
42401.54Skamil	e = strtol("10", NULL, 10);
42411.54Skamil	f = strtol("20", NULL, 10);
42421.54Skamil	g = strtol("30", NULL, 10);
42431.54Skamil	h = strtol("40", NULL, 10);
42441.1Skamil
42451.54Skamil	return (a + b * c - d) + (e * f - g / h);
42461.1Skamil}
42471.1Skamil
42481.54Skamilstatic void
42491.55Schristosbytes_transfer(int operation, size_t size, enum bytes_transfer_type type)
42501.1Skamil{
42511.1Skamil	const int exitval = 5;
42521.1Skamil	const int sigval = SIGSTOP;
42531.1Skamil	pid_t child, wpid;
42541.54Skamil	bool skip = false;
42551.1Skamil
42561.54Skamil	int lookup_me = 0;
42571.54Skamil	uint8_t lookup_me8 = 0;
42581.54Skamil	uint16_t lookup_me16 = 0;
42591.54Skamil	uint32_t lookup_me32 = 0;
42601.54Skamil	uint64_t lookup_me64 = 0;
42611.1Skamil
42621.54Skamil	int magic = 0x13579246;
42631.54Skamil	uint8_t magic8 = 0xab;
42641.54Skamil	uint16_t magic16 = 0x1234;
42651.54Skamil	uint32_t magic32 = 0x98765432;
42661.54Skamil	uint64_t magic64 = 0xabcdef0123456789;
42671.1Skamil
42681.54Skamil	struct ptrace_io_desc io;
42691.1Skamil#if defined(TWAIT_HAVE_STATUS)
42701.1Skamil	int status;
42711.1Skamil#endif
42721.60Skre	/* 513 is just enough, for the purposes of ATF it's good enough */
42731.60Skre	AuxInfo ai[513], *aip;
42741.55Schristos
42751.55Schristos	ATF_REQUIRE(size < sizeof(ai));
42761.1Skamil
42771.54Skamil	/* Prepare variables for .TEXT transfers */
42781.54Skamil	switch (type) {
42791.54Skamil	case BYTES_TRANSFER_TEXT:
42801.54Skamil		memcpy(&magic, bytes_transfer_dummy, sizeof(magic));
42811.54Skamil		break;
42821.54Skamil	case BYTES_TRANSFER_TEXTIO:
42831.54Skamil		switch (size) {
42841.54Skamil		case 8:
42851.54Skamil			memcpy(&magic8, bytes_transfer_dummy, sizeof(magic8));
42861.54Skamil			break;
42871.54Skamil		case 16:
42881.54Skamil			memcpy(&magic16, bytes_transfer_dummy, sizeof(magic16));
42891.54Skamil			break;
42901.54Skamil		case 32:
42911.54Skamil			memcpy(&magic32, bytes_transfer_dummy, sizeof(magic32));
42921.54Skamil			break;
42931.54Skamil		case 64:
42941.54Skamil			memcpy(&magic64, bytes_transfer_dummy, sizeof(magic64));
42951.54Skamil			break;
42961.54Skamil		}
42971.54Skamil		break;
42981.54Skamil	default:
42991.54Skamil		break;
43001.54Skamil	}
43011.1Skamil
43021.54Skamil	/* Prepare variables for PIOD and AUXV transfers */
43031.54Skamil	switch (type) {
43041.54Skamil	case BYTES_TRANSFER_TEXTIO:
43051.54Skamil	case BYTES_TRANSFER_DATAIO:
43061.54Skamil		io.piod_op = operation;
43071.54Skamil		switch (size) {
43081.54Skamil		case 8:
43091.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
43101.54Skamil			               (void *)bytes_transfer_dummy :
43111.54Skamil			               &lookup_me8;
43121.54Skamil			io.piod_addr = &lookup_me8;
43131.54Skamil			io.piod_len = sizeof(lookup_me8);
43141.54Skamil			break;
43151.54Skamil		case 16:
43161.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
43171.54Skamil			               (void *)bytes_transfer_dummy :
43181.54Skamil			               &lookup_me16;
43191.54Skamil			io.piod_addr = &lookup_me16;
43201.54Skamil			io.piod_len = sizeof(lookup_me16);
43211.54Skamil			break;
43221.54Skamil		case 32:
43231.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
43241.54Skamil			               (void *)bytes_transfer_dummy :
43251.54Skamil			               &lookup_me32;
43261.54Skamil			io.piod_addr = &lookup_me32;
43271.54Skamil			io.piod_len = sizeof(lookup_me32);
43281.54Skamil			break;
43291.54Skamil		case 64:
43301.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
43311.54Skamil			               (void *)bytes_transfer_dummy :
43321.54Skamil			               &lookup_me64;
43331.54Skamil			io.piod_addr = &lookup_me64;
43341.54Skamil			io.piod_len = sizeof(lookup_me64);
43351.54Skamil			break;
43361.54Skamil		default:
43371.54Skamil			break;
43381.54Skamil		}
43391.54Skamil		break;
43401.54Skamil	case BYTES_TRANSFER_AUXV:
43411.54Skamil		io.piod_op = operation;
43421.54Skamil		io.piod_offs = 0;
43431.54Skamil		io.piod_addr = ai;
43441.54Skamil		io.piod_len = size;
43451.54Skamil		break;
43461.54Skamil	default:
43471.54Skamil		break;
43481.1Skamil	}
43491.1Skamil
43501.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
43511.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
43521.1Skamil	if (child == 0) {
43531.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
43541.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
43551.1Skamil
43561.54Skamil		switch (type) {
43571.54Skamil		case BYTES_TRANSFER_DATA:
43581.54Skamil			switch (operation) {
43591.54Skamil			case PT_READ_D:
43601.54Skamil			case PT_READ_I:
43611.54Skamil				lookup_me = magic;
43621.54Skamil				break;
43631.54Skamil			default:
43641.54Skamil				break;
43651.54Skamil			}
43661.54Skamil			break;
43671.54Skamil		case BYTES_TRANSFER_DATAIO:
43681.54Skamil			switch (operation) {
43691.54Skamil			case PIOD_READ_D:
43701.54Skamil			case PIOD_READ_I:
43711.54Skamil				switch (size) {
43721.54Skamil				case 8:
43731.54Skamil					lookup_me8 = magic8;
43741.54Skamil					break;
43751.54Skamil				case 16:
43761.54Skamil					lookup_me16 = magic16;
43771.54Skamil					break;
43781.54Skamil				case 32:
43791.54Skamil					lookup_me32 = magic32;
43801.54Skamil					break;
43811.54Skamil				case 64:
43821.54Skamil					lookup_me64 = magic64;
43831.54Skamil					break;
43841.54Skamil				default:
43851.54Skamil					break;
43861.54Skamil				}
43871.54Skamil				break;
43881.54Skamil			default:
43891.54Skamil				break;
43901.54Skamil			}
43911.54Skamil		default:
43921.54Skamil			break;
43931.54Skamil		}
43941.54Skamil
43951.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
43961.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
43971.1Skamil
43981.54Skamil		/* Handle PIOD and PT separately as operation values overlap */
43991.54Skamil		switch (type) {
44001.54Skamil		case BYTES_TRANSFER_DATA:
44011.54Skamil			switch (operation) {
44021.54Skamil			case PT_WRITE_D:
44031.54Skamil			case PT_WRITE_I:
44041.54Skamil				FORKEE_ASSERT_EQ(lookup_me, magic);
44051.54Skamil				break;
44061.54Skamil			default:
44071.54Skamil				break;
44081.54Skamil			}
44091.54Skamil			break;
44101.54Skamil		case BYTES_TRANSFER_DATAIO:
44111.54Skamil			switch (operation) {
44121.54Skamil			case PIOD_WRITE_D:
44131.54Skamil			case PIOD_WRITE_I:
44141.54Skamil				switch (size) {
44151.54Skamil				case 8:
44161.54Skamil					FORKEE_ASSERT_EQ(lookup_me8, magic8);
44171.54Skamil					break;
44181.54Skamil				case 16:
44191.54Skamil					FORKEE_ASSERT_EQ(lookup_me16, magic16);
44201.54Skamil					break;
44211.54Skamil				case 32:
44221.54Skamil					FORKEE_ASSERT_EQ(lookup_me32, magic32);
44231.54Skamil					break;
44241.54Skamil				case 64:
44251.54Skamil					FORKEE_ASSERT_EQ(lookup_me64, magic64);
44261.54Skamil					break;
44271.54Skamil				default:
44281.54Skamil					break;
44291.54Skamil				}
44301.54Skamil				break;
44311.54Skamil			default:
44321.54Skamil				break;
44331.54Skamil			}
44341.54Skamil			break;
44351.54Skamil		case BYTES_TRANSFER_TEXT:
44361.54Skamil			FORKEE_ASSERT(memcmp(&magic, bytes_transfer_dummy,
44371.54Skamil			                     sizeof(magic)) == 0);
44381.54Skamil			break;
44391.54Skamil		case BYTES_TRANSFER_TEXTIO:
44401.54Skamil			switch (size) {
44411.54Skamil			case 8:
44421.54Skamil				FORKEE_ASSERT(memcmp(&magic8,
44431.54Skamil				                     bytes_transfer_dummy,
44441.54Skamil				                     sizeof(magic8)) == 0);
44451.54Skamil				break;
44461.54Skamil			case 16:
44471.54Skamil				FORKEE_ASSERT(memcmp(&magic16,
44481.54Skamil				                     bytes_transfer_dummy,
44491.54Skamil				                     sizeof(magic16)) == 0);
44501.54Skamil				break;
44511.54Skamil			case 32:
44521.54Skamil				FORKEE_ASSERT(memcmp(&magic32,
44531.54Skamil				                     bytes_transfer_dummy,
44541.54Skamil				                     sizeof(magic32)) == 0);
44551.54Skamil				break;
44561.54Skamil			case 64:
44571.54Skamil				FORKEE_ASSERT(memcmp(&magic64,
44581.54Skamil				                     bytes_transfer_dummy,
44591.54Skamil				                     sizeof(magic64)) == 0);
44601.54Skamil				break;
44611.54Skamil			}
44621.54Skamil			break;
44631.54Skamil		default:
44641.54Skamil			break;
44651.54Skamil		}
44661.54Skamil
44671.13Schristos		DPRINTF("Before exiting of the child process\n");
44681.1Skamil		_exit(exitval);
44691.1Skamil	}
44701.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
44711.1Skamil
44721.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
44731.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
44741.1Skamil
44751.1Skamil	validate_status_stopped(status, sigval);
44761.1Skamil
44771.54Skamil	/* Check PaX MPROTECT */
44781.54Skamil	if (!can_we_write_to_text(child)) {
44791.54Skamil		switch (type) {
44801.54Skamil		case BYTES_TRANSFER_TEXTIO:
44811.54Skamil			switch (operation) {
44821.54Skamil			case PIOD_WRITE_D:
44831.54Skamil			case PIOD_WRITE_I:
44841.54Skamil				skip = true;
44851.54Skamil				break;
44861.54Skamil			default:
44871.54Skamil				break;
44881.54Skamil			}
44891.54Skamil			break;
44901.54Skamil		case BYTES_TRANSFER_TEXT:
44911.54Skamil			switch (operation) {
44921.54Skamil			case PT_WRITE_D:
44931.54Skamil			case PT_WRITE_I:
44941.54Skamil				skip = true;
44951.54Skamil				break;
44961.54Skamil			default:
44971.54Skamil				break;
44981.54Skamil			}
44991.54Skamil			break;
45001.54Skamil		default:
45011.54Skamil			break;
45021.54Skamil		}
45031.54Skamil	}
45041.1Skamil
45051.54Skamil	/* Bailout cleanly killing the child process */
45061.54Skamil	if (skip) {
45071.54Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
45081.54Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
45091.54Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
45101.54Skamil		                      child);
45111.1Skamil
45121.54Skamil		validate_status_signaled(status, SIGKILL, 0);
45131.1Skamil
45141.54Skamil		atf_tc_skip("PaX MPROTECT setup prevents writes to .text");
45151.54Skamil	}
45161.1Skamil
45171.54Skamil	DPRINTF("Calling operation to transfer bytes between child=%d and "
45181.54Skamil	       "parent=%d\n", child, getpid());
45191.1Skamil
45201.54Skamil	switch (type) {
45211.54Skamil	case BYTES_TRANSFER_TEXTIO:
45221.54Skamil	case BYTES_TRANSFER_DATAIO:
45231.54Skamil	case BYTES_TRANSFER_AUXV:
45241.54Skamil		switch (operation) {
45251.54Skamil		case PIOD_WRITE_D:
45261.54Skamil		case PIOD_WRITE_I:
45271.54Skamil			switch (size) {
45281.54Skamil			case 8:
45291.54Skamil				lookup_me8 = magic8;
45301.54Skamil				break;
45311.54Skamil			case 16:
45321.54Skamil				lookup_me16 = magic16;
45331.54Skamil				break;
45341.54Skamil			case 32:
45351.54Skamil				lookup_me32 = magic32;
45361.54Skamil				break;
45371.54Skamil			case 64:
45381.54Skamil				lookup_me64 = magic64;
45391.54Skamil				break;
45401.54Skamil			default:
45411.54Skamil				break;
45421.54Skamil			}
45431.54Skamil			break;
45441.54Skamil		default:
45451.54Skamil			break;
45461.54Skamil		}
45471.54Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
45481.54Skamil		switch (operation) {
45491.54Skamil		case PIOD_READ_D:
45501.54Skamil		case PIOD_READ_I:
45511.54Skamil			switch (size) {
45521.54Skamil			case 8:
45531.54Skamil				ATF_REQUIRE_EQ(lookup_me8, magic8);
45541.54Skamil				break;
45551.54Skamil			case 16:
45561.54Skamil				ATF_REQUIRE_EQ(lookup_me16, magic16);
45571.54Skamil				break;
45581.54Skamil			case 32:
45591.54Skamil				ATF_REQUIRE_EQ(lookup_me32, magic32);
45601.54Skamil				break;
45611.54Skamil			case 64:
45621.54Skamil				ATF_REQUIRE_EQ(lookup_me64, magic64);
45631.54Skamil				break;
45641.54Skamil			default:
45651.54Skamil				break;
45661.54Skamil			}
45671.54Skamil			break;
45681.54Skamil		case PIOD_READ_AUXV:
45691.54Skamil			DPRINTF("Asserting that AUXV length (%zu) is > 0\n",
45701.54Skamil			        io.piod_len);
45711.54Skamil			ATF_REQUIRE(io.piod_len > 0);
45721.54Skamil			for (aip = ai; aip->a_type != AT_NULL; aip++)
45731.54Skamil				DPRINTF("a_type=%#llx a_v=%#llx\n",
45741.54Skamil				    (long long int)aip->a_type,
45751.54Skamil				    (long long int)aip->a_v);
45761.54Skamil			break;
45771.54Skamil		default:
45781.54Skamil			break;
45791.54Skamil		}
45801.54Skamil		break;
45811.54Skamil	case BYTES_TRANSFER_TEXT:
45821.54Skamil		switch (operation) {
45831.54Skamil		case PT_READ_D:
45841.54Skamil		case PT_READ_I:
45851.54Skamil			errno = 0;
45861.54Skamil			lookup_me = ptrace(operation, child,
45871.54Skamil			                   bytes_transfer_dummy, 0);
45881.54Skamil			ATF_REQUIRE_EQ(lookup_me, magic);
45891.54Skamil			SYSCALL_REQUIRE_ERRNO(errno, 0);
45901.54Skamil			break;
45911.54Skamil		case PT_WRITE_D:
45921.54Skamil		case PT_WRITE_I:
45931.54Skamil			SYSCALL_REQUIRE(ptrace(operation, child,
45941.54Skamil			                       bytes_transfer_dummy, magic)
45951.54Skamil			                != -1);
45961.54Skamil			break;
45971.54Skamil		default:
45981.54Skamil			break;
45991.54Skamil		}
46001.54Skamil		break;
46011.54Skamil	case BYTES_TRANSFER_DATA:
46021.54Skamil		switch (operation) {
46031.54Skamil		case PT_READ_D:
46041.54Skamil		case PT_READ_I:
46051.54Skamil			errno = 0;
46061.54Skamil			lookup_me = ptrace(operation, child, &lookup_me, 0);
46071.54Skamil			ATF_REQUIRE_EQ(lookup_me, magic);
46081.54Skamil			SYSCALL_REQUIRE_ERRNO(errno, 0);
46091.54Skamil			break;
46101.54Skamil		case PT_WRITE_D:
46111.54Skamil		case PT_WRITE_I:
46121.54Skamil			lookup_me = magic;
46131.54Skamil			SYSCALL_REQUIRE(ptrace(operation, child, &lookup_me,
46141.54Skamil			                       magic) != -1);
46151.54Skamil			break;
46161.54Skamil		default:
46171.54Skamil			break;
46181.54Skamil		}
46191.54Skamil		break;
46201.54Skamil	default:
46211.54Skamil		break;
46221.54Skamil	}
46231.1Skamil
46241.13Schristos	DPRINTF("Before resuming the child process where it left off and "
46251.1Skamil	    "without signal to be sent\n");
46261.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
46271.1Skamil
46281.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46291.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
46301.1Skamil
46311.1Skamil	validate_status_exited(status, exitval);
46321.1Skamil
46331.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46341.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
46351.1Skamil}
46361.1Skamil
46371.61Skre#define BYTES_TRANSFER(test, operation, size, type)			\
46381.61SkreATF_TC(test);								\
46391.61SkreATF_TC_HEAD(test, tc)							\
46401.61Skre{									\
46411.61Skre	atf_tc_set_md_var(tc, "descr",					\
46421.61Skre	    "Verify bytes transfer operation" #operation " and size " #size \
46431.61Skre	    " of type " #type);						\
46441.61Skre}									\
46451.61Skre									\
46461.61SkreATF_TC_BODY(test, tc)							\
46471.61Skre{									\
46481.61Skre									\
46491.61Skre	bytes_transfer(operation, size, BYTES_TRANSFER_##type);		\
46501.1Skamil}
46511.1Skamil
46521.54Skamil// DATA
46531.1Skamil
46541.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_8, PIOD_READ_D, 8, DATAIO)
46551.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_16, PIOD_READ_D, 16, DATAIO)
46561.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_32, PIOD_READ_D, 32, DATAIO)
46571.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_64, PIOD_READ_D, 64, DATAIO)
46581.54Skamil
46591.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_8, PIOD_READ_I, 8, DATAIO)
46601.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_16, PIOD_READ_I, 16, DATAIO)
46611.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_32, PIOD_READ_I, 32, DATAIO)
46621.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_64, PIOD_READ_I, 64, DATAIO)
46631.54Skamil
46641.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_8, PIOD_WRITE_D, 8, DATAIO)
46651.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_16, PIOD_WRITE_D, 16, DATAIO)
46661.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_32, PIOD_WRITE_D, 32, DATAIO)
46671.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_64, PIOD_WRITE_D, 64, DATAIO)
46681.54Skamil
46691.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_8, PIOD_WRITE_I, 8, DATAIO)
46701.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_16, PIOD_WRITE_I, 16, DATAIO)
46711.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_32, PIOD_WRITE_I, 32, DATAIO)
46721.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_64, PIOD_WRITE_I, 64, DATAIO)
46731.54Skamil
46741.54SkamilBYTES_TRANSFER(bytes_transfer_read_d, PT_READ_D, 32, DATA)
46751.54SkamilBYTES_TRANSFER(bytes_transfer_read_i, PT_READ_I, 32, DATA)
46761.54SkamilBYTES_TRANSFER(bytes_transfer_write_d, PT_WRITE_D, 32, DATA)
46771.54SkamilBYTES_TRANSFER(bytes_transfer_write_i, PT_WRITE_I, 32, DATA)
46781.54Skamil
46791.54Skamil// TEXT
46801.54Skamil
46811.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_8_text, PIOD_READ_D, 8, TEXTIO)
46821.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_16_text, PIOD_READ_D, 16, TEXTIO)
46831.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_32_text, PIOD_READ_D, 32, TEXTIO)
46841.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_64_text, PIOD_READ_D, 64, TEXTIO)
46851.54Skamil
46861.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_8_text, PIOD_READ_I, 8, TEXTIO)
46871.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_16_text, PIOD_READ_I, 16, TEXTIO)
46881.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_32_text, PIOD_READ_I, 32, TEXTIO)
46891.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_64_text, PIOD_READ_I, 64, TEXTIO)
46901.54Skamil
46911.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_8_text, PIOD_WRITE_D, 8, TEXTIO)
46921.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_16_text, PIOD_WRITE_D, 16, TEXTIO)
46931.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_32_text, PIOD_WRITE_D, 32, TEXTIO)
46941.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_64_text, PIOD_WRITE_D, 64, TEXTIO)
46951.54Skamil
46961.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_8_text, PIOD_WRITE_I, 8, TEXTIO)
46971.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_16_text, PIOD_WRITE_I, 16, TEXTIO)
46981.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_32_text, PIOD_WRITE_I, 32, TEXTIO)
46991.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_64_text, PIOD_WRITE_I, 64, TEXTIO)
47001.54Skamil
47011.54SkamilBYTES_TRANSFER(bytes_transfer_read_d_text, PT_READ_D, 32, TEXT)
47021.54SkamilBYTES_TRANSFER(bytes_transfer_read_i_text, PT_READ_I, 32, TEXT)
47031.54SkamilBYTES_TRANSFER(bytes_transfer_write_d_text, PT_WRITE_D, 32, TEXT)
47041.54SkamilBYTES_TRANSFER(bytes_transfer_write_i_text, PT_WRITE_I, 32, TEXT)
47051.1Skamil
47061.54Skamil// AUXV
47071.1Skamil
47081.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_auxv, PIOD_READ_AUXV, 4096, AUXV)
47091.1Skamil
47101.54Skamil/// ----------------------------------------------------------------------------
47111.1Skamil
47121.101Skamilstatic void
47131.101Skamilbytes_transfer_alignment(const char *operation)
47141.101Skamil{
47151.101Skamil	const int exitval = 5;
47161.101Skamil	const int sigval = SIGSTOP;
47171.101Skamil	pid_t child, wpid;
47181.101Skamil#if defined(TWAIT_HAVE_STATUS)
47191.101Skamil	int status;
47201.101Skamil#endif
47211.101Skamil	char *buffer;
47221.101Skamil	int vector;
47231.101Skamil	size_t len;
47241.101Skamil	size_t i;
47251.101Skamil	int op;
47261.101Skamil
47271.101Skamil	struct ptrace_io_desc io;
47281.101Skamil	struct ptrace_siginfo info;
47291.101Skamil
47301.101Skamil	memset(&io, 0, sizeof(io));
47311.101Skamil	memset(&info, 0, sizeof(info));
47321.101Skamil
47331.101Skamil	/* Testing misaligned byte transfer crossing page boundaries */
47341.101Skamil	len = sysconf(_SC_PAGESIZE) * 2;
47351.101Skamil	buffer = malloc(len);
47361.101Skamil	ATF_REQUIRE(buffer != NULL);
47371.101Skamil
47381.101Skamil	/* Initialize the buffer with random data */
47391.101Skamil	for (i = 0; i < len; i++)
47401.101Skamil		buffer[i] = i & 0xff;
47411.101Skamil
47421.101Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
47431.101Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
47441.101Skamil	if (child == 0) {
47451.101Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
47461.101Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
47471.101Skamil
47481.101Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
47491.101Skamil		FORKEE_ASSERT(raise(sigval) == 0);
47501.101Skamil
47511.101Skamil		DPRINTF("Before exiting of the child process\n");
47521.101Skamil		_exit(exitval);
47531.101Skamil	}
47541.101Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
47551.101Skamil
47561.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
47571.101Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
47581.101Skamil
47591.101Skamil	validate_status_stopped(status, sigval);
47601.101Skamil
47611.101Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
47621.101Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info))
47631.101Skamil		!= -1);
47641.101Skamil
47651.101Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
47661.101Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
47671.101Skamil		"si_errno=%#x\n",
47681.101Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
47691.101Skamil		info.psi_siginfo.si_errno);
47701.101Skamil
47711.101Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
47721.101Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
47731.101Skamil
47741.101Skamil	if (strcmp(operation, "PT_READ_I") == 0 ||
47751.101Skamil	    strcmp(operation, "PT_READ_D") == 0) {
47761.101Skamil		if (strcmp(operation, "PT_READ_I"))
47771.101Skamil			op = PT_READ_I;
47781.101Skamil		else
47791.101Skamil			op = PT_READ_D;
47801.101Skamil
47811.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
47821.101Skamil			errno = 0;
47831.101Skamil			vector = ptrace(op, child, buffer + i, 0);
47841.101Skamil			ATF_REQUIRE_EQ(errno, 0);
47851.101Skamil			ATF_REQUIRE(!memcmp(&vector, buffer + i, sizeof(int)));
47861.101Skamil		}
47871.101Skamil	} else if (strcmp(operation, "PT_WRITE_I") == 0 ||
47881.101Skamil	           strcmp(operation, "PT_WRITE_D") == 0) {
47891.101Skamil		if (strcmp(operation, "PT_WRITE_I"))
47901.101Skamil			op = PT_WRITE_I;
47911.101Skamil		else
47921.101Skamil			op = PT_WRITE_D;
47931.101Skamil
47941.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
47951.101Skamil			memcpy(&vector, buffer + i, sizeof(int));
47961.101Skamil			SYSCALL_REQUIRE(ptrace(op, child, buffer + 1, vector)
47971.101Skamil			    != -1);
47981.101Skamil		}
47991.101Skamil	} else if (strcmp(operation, "PIOD_READ_I") == 0 ||
48001.101Skamil	           strcmp(operation, "PIOD_READ_D") == 0) {
48011.101Skamil		if (strcmp(operation, "PIOD_READ_I"))
48021.101Skamil			op = PIOD_READ_I;
48031.101Skamil		else
48041.101Skamil			op = PIOD_READ_D;
48051.101Skamil
48061.101Skamil		io.piod_op = op;
48071.101Skamil		io.piod_addr = &vector;
48081.101Skamil		io.piod_len = sizeof(int);
48091.101Skamil
48101.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
48111.101Skamil			io.piod_offs = buffer + i;
48121.101Skamil
48131.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
48141.101Skamil			                != -1);
48151.101Skamil			ATF_REQUIRE(!memcmp(&vector, buffer + i, sizeof(int)));
48161.101Skamil		}
48171.101Skamil	} else if (strcmp(operation, "PIOD_WRITE_I") == 0 ||
48181.101Skamil	           strcmp(operation, "PIOD_WRITE_D") == 0) {
48191.101Skamil		if (strcmp(operation, "PIOD_WRITE_I"))
48201.101Skamil			op = PIOD_WRITE_I;
48211.101Skamil		else
48221.101Skamil			op = PIOD_WRITE_D;
48231.101Skamil
48241.101Skamil		io.piod_op = op;
48251.101Skamil		io.piod_addr = &vector;
48261.101Skamil		io.piod_len = sizeof(int);
48271.101Skamil
48281.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
48291.101Skamil			io.piod_offs = buffer + i;
48301.101Skamil
48311.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
48321.101Skamil			                != -1);
48331.101Skamil		}
48341.101Skamil	} else if (strcmp(operation, "PIOD_READ_AUXV") == 0) {
48351.101Skamil		io.piod_op = PIOD_READ_AUXV;
48361.101Skamil		io.piod_addr = &vector;
48371.101Skamil		io.piod_len = sizeof(int);
48381.101Skamil
48391.101Skamil		errno = 0;
48401.101Skamil		i = 0;
48411.101Skamil		/* Read the whole AUXV vector, it has no clear length */
48421.120Skamil		while (io.piod_len > 0) {
48431.101Skamil			io.piod_offs = (void *)(intptr_t)i;
48441.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
48451.120Skamil			                != -1 || (io.piod_len == 0 && i > 0));
48461.101Skamil			++i;
48471.101Skamil		}
48481.101Skamil	}
48491.101Skamil
48501.101Skamil	DPRINTF("Before resuming the child process where it left off "
48511.101Skamil	    "and without signal to be sent\n");
48521.101Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
48531.101Skamil
48541.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48551.101Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
48561.101Skamil	    child);
48571.101Skamil
48581.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48591.101Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
48601.101Skamil}
48611.101Skamil
48621.101Skamil#define BYTES_TRANSFER_ALIGNMENT(test, operation)			\
48631.101SkamilATF_TC(test);								\
48641.101SkamilATF_TC_HEAD(test, tc)							\
48651.101Skamil{									\
48661.101Skamil	atf_tc_set_md_var(tc, "descr",					\
48671.101Skamil	    "Verify bytes transfer for potentially misaligned "		\
48681.101Skamil	    "operation " operation);					\
48691.101Skamil}									\
48701.101Skamil									\
48711.101SkamilATF_TC_BODY(test, tc)							\
48721.101Skamil{									\
48731.101Skamil									\
48741.101Skamil	bytes_transfer_alignment(operation);				\
48751.101Skamil}
48761.101Skamil
48771.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_read_i, "PT_READ_I")
48781.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_read_d, "PT_READ_D")
48791.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_write_i, "PT_WRITE_I")
48801.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_write_d, "PT_WRITE_D")
48811.101Skamil
48821.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_i, "PIOD_READ_I")
48831.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_d, "PIOD_READ_D")
48841.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_write_i, "PIOD_WRITE_I")
48851.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_write_d, "PIOD_WRITE_D")
48861.101Skamil
48871.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_auxv, "PIOD_READ_AUXV")
48881.101Skamil
48891.101Skamil/// ----------------------------------------------------------------------------
48901.101Skamil
48911.115Skamilstatic void
48921.115Skamilbytes_transfer_eof(const char *operation)
48931.115Skamil{
48941.115Skamil	const int exitval = 5;
48951.115Skamil	const int sigval = SIGSTOP;
48961.115Skamil	pid_t child, wpid;
48971.115Skamil#if defined(TWAIT_HAVE_STATUS)
48981.115Skamil	int status;
48991.115Skamil#endif
49001.115Skamil	FILE *fp;
49011.115Skamil	char *p;
49021.115Skamil	int vector;
49031.115Skamil	int op;
49041.115Skamil
49051.115Skamil	struct ptrace_io_desc io;
49061.115Skamil	struct ptrace_siginfo info;
49071.115Skamil
49081.115Skamil	memset(&io, 0, sizeof(io));
49091.115Skamil	memset(&info, 0, sizeof(info));
49101.115Skamil
49111.115Skamil	vector = 0;
49121.115Skamil
49131.115Skamil	fp = tmpfile();
49141.115Skamil	ATF_REQUIRE(fp != NULL);
49151.115Skamil
49161.115Skamil	p = mmap(0, 1, PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(fp), 0);
49171.115Skamil	ATF_REQUIRE(p != MAP_FAILED);
49181.115Skamil
49191.115Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
49201.115Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
49211.115Skamil	if (child == 0) {
49221.115Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
49231.115Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
49241.115Skamil
49251.115Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
49261.115Skamil		FORKEE_ASSERT(raise(sigval) == 0);
49271.115Skamil
49281.115Skamil		DPRINTF("Before exiting of the child process\n");
49291.115Skamil		_exit(exitval);
49301.115Skamil	}
49311.115Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
49321.115Skamil
49331.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
49341.115Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
49351.115Skamil
49361.115Skamil	validate_status_stopped(status, sigval);
49371.115Skamil
49381.115Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
49391.115Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info))
49401.115Skamil		!= -1);
49411.115Skamil
49421.115Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
49431.115Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
49441.115Skamil		"si_errno=%#x\n",
49451.115Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
49461.115Skamil		info.psi_siginfo.si_errno);
49471.115Skamil
49481.115Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
49491.115Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
49501.115Skamil
49511.115Skamil	if (strcmp(operation, "PT_READ_I") == 0 ||
49521.115Skamil	    strcmp(operation, "PT_READ_D") == 0) {
49531.115Skamil		if (strcmp(operation, "PT_READ_I"))
49541.115Skamil			op = PT_READ_I;
49551.115Skamil		else
49561.115Skamil			op = PT_READ_D;
49571.115Skamil
49581.115Skamil		errno = 0;
49591.115Skamil		SYSCALL_REQUIRE(ptrace(op, child, p, 0) == -1);
49601.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
49611.115Skamil	} else if (strcmp(operation, "PT_WRITE_I") == 0 ||
49621.115Skamil	           strcmp(operation, "PT_WRITE_D") == 0) {
49631.115Skamil		if (strcmp(operation, "PT_WRITE_I"))
49641.115Skamil			op = PT_WRITE_I;
49651.115Skamil		else
49661.115Skamil			op = PT_WRITE_D;
49671.115Skamil
49681.115Skamil		errno = 0;
49691.115Skamil		SYSCALL_REQUIRE(ptrace(op, child, p, vector) == -1);
49701.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
49711.115Skamil	} else if (strcmp(operation, "PIOD_READ_I") == 0 ||
49721.115Skamil	           strcmp(operation, "PIOD_READ_D") == 0) {
49731.115Skamil		if (strcmp(operation, "PIOD_READ_I"))
49741.115Skamil			op = PIOD_READ_I;
49751.115Skamil		else
49761.115Skamil			op = PIOD_READ_D;
49771.115Skamil
49781.115Skamil		io.piod_op = op;
49791.115Skamil		io.piod_addr = &vector;
49801.115Skamil		io.piod_len = sizeof(int);
49811.115Skamil		io.piod_offs = p;
49821.115Skamil
49831.115Skamil		errno = 0;
49841.115Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io)) == -1);
49851.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
49861.115Skamil	} else if (strcmp(operation, "PIOD_WRITE_I") == 0 ||
49871.115Skamil	           strcmp(operation, "PIOD_WRITE_D") == 0) {
49881.115Skamil		if (strcmp(operation, "PIOD_WRITE_I"))
49891.115Skamil			op = PIOD_WRITE_I;
49901.115Skamil		else
49911.115Skamil			op = PIOD_WRITE_D;
49921.115Skamil
49931.115Skamil		io.piod_op = op;
49941.115Skamil		io.piod_addr = &vector;
49951.115Skamil		io.piod_len = sizeof(int);
49961.115Skamil		io.piod_offs = p;
49971.115Skamil
49981.115Skamil		errno = 0;
49991.115Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io)) == -1);
50001.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
50011.115Skamil	}
50021.115Skamil
50031.115Skamil	DPRINTF("Before resuming the child process where it left off "
50041.115Skamil	    "and without signal to be sent\n");
50051.115Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
50061.115Skamil
50071.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
50081.115Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
50091.115Skamil	    child);
50101.115Skamil
50111.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
50121.115Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
50131.115Skamil}
50141.115Skamil
50151.115Skamil#define BYTES_TRANSFER_EOF(test, operation)				\
50161.115SkamilATF_TC(test);								\
50171.115SkamilATF_TC_HEAD(test, tc)							\
50181.115Skamil{									\
50191.115Skamil	atf_tc_set_md_var(tc, "descr",					\
50201.115Skamil	    "Verify bytes EOF byte transfer for the " operation		\
50211.115Skamil	    " operation");						\
50221.115Skamil}									\
50231.115Skamil									\
50241.115SkamilATF_TC_BODY(test, tc)							\
50251.115Skamil{									\
50261.115Skamil									\
50271.115Skamil	bytes_transfer_eof(operation);					\
50281.115Skamil}
50291.115Skamil
50301.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_read_i, "PT_READ_I")
50311.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_read_d, "PT_READ_D")
50321.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_write_i, "PT_WRITE_I")
50331.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_write_d, "PT_WRITE_D")
50341.115Skamil
50351.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_read_i, "PIOD_READ_I")
50361.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_read_d, "PIOD_READ_D")
50371.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_i, "PIOD_WRITE_I")
50381.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_d, "PIOD_WRITE_D")
50391.115Skamil
50401.115Skamil/// ----------------------------------------------------------------------------
50411.115Skamil
50421.76Sscole#if defined(HAVE_GPREGS) || defined(HAVE_FPREGS)
50431.72Skamilstatic void
50441.72Skamilaccess_regs(const char *regset, const char *aux)
50451.1Skamil{
50461.1Skamil	const int exitval = 5;
50471.1Skamil	const int sigval = SIGSTOP;
50481.1Skamil	pid_t child, wpid;
50491.1Skamil#if defined(TWAIT_HAVE_STATUS)
50501.1Skamil	int status;
50511.1Skamil#endif
50521.72Skamil#if defined(HAVE_GPREGS)
50531.72Skamil	struct reg gpr;
50541.76Sscole	register_t rgstr;
50551.1Skamil#endif
50561.72Skamil#if defined(HAVE_FPREGS)
50571.72Skamil	struct fpreg fpr;
50581.1Skamil#endif
50591.76Sscole
50601.72Skamil#if !defined(HAVE_GPREGS)
50611.72Skamil	if (strcmp(regset, "regs") == 0)
50621.72Skamil		atf_tc_fail("Impossible test scenario!");
50631.1Skamil#endif
50641.1Skamil
50651.72Skamil#if !defined(HAVE_FPREGS)
50661.72Skamil	if (strcmp(regset, "fpregs") == 0)
50671.72Skamil		atf_tc_fail("Impossible test scenario!");
50681.1Skamil#endif
50691.1Skamil
50701.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
50711.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
50721.1Skamil	if (child == 0) {
50731.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
50741.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
50751.1Skamil
50761.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
50771.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
50781.1Skamil
50791.13Schristos		DPRINTF("Before exiting of the child process\n");
50801.1Skamil		_exit(exitval);
50811.1Skamil	}
50821.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
50831.1Skamil
50841.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
50851.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
50861.1Skamil
50871.1Skamil	validate_status_stopped(status, sigval);
50881.1Skamil
50891.1Skamil#if defined(HAVE_GPREGS)
50901.72Skamil	if (strcmp(regset, "regs") == 0) {
50911.72Skamil		DPRINTF("Call GETREGS for the child process\n");
50921.72Skamil		SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1);
50931.72Skamil
50941.72Skamil		if (strcmp(aux, "none") == 0) {
50951.72Skamil			DPRINTF("Retrieved registers\n");
50961.72Skamil		} else if (strcmp(aux, "pc") == 0) {
50971.72Skamil			rgstr = PTRACE_REG_PC(&gpr);
50981.72Skamil			DPRINTF("Retrieved %" PRIxREGISTER "\n", rgstr);
50991.147Skamil		} else if (strstr(aux, "set_pc") != NULL) {
51001.72Skamil			rgstr = PTRACE_REG_PC(&gpr);
51011.147Skamil			DPRINTF("Retrieved PC %" PRIxREGISTER "\n", rgstr);
51021.147Skamil			if (strstr(aux, "0x1") != NULL) {
51031.147Skamil				rgstr |= 0x1;
51041.147Skamil			} else if (strstr(aux, "0x3") != NULL) {
51051.147Skamil				rgstr |= 0x3;
51061.147Skamil			} else if (strstr(aux, "0x7") != NULL) {
51071.147Skamil				rgstr |= 0x7;
51081.147Skamil			}
51091.147Skamil			DPRINTF("Set PC %" PRIxREGISTER "\n", rgstr);
51101.72Skamil			PTRACE_REG_SET_PC(&gpr, rgstr);
51111.147Skamil			if (strcmp(aux, "set_pc") != 0) {
51121.147Skamil				/* This call can fail with EINVAL or similar. */
51131.147Skamil				ptrace(PT_SETREGS, child, &gpr, 0);
51141.147Skamil			}
51151.72Skamil		} else if (strcmp(aux, "sp") == 0) {
51161.72Skamil			rgstr = PTRACE_REG_SP(&gpr);
51171.72Skamil			DPRINTF("Retrieved %" PRIxREGISTER "\n", rgstr);
51181.72Skamil		} else if (strcmp(aux, "intrv") == 0) {
51191.72Skamil			rgstr = PTRACE_REG_INTRV(&gpr);
51201.72Skamil			DPRINTF("Retrieved %" PRIxREGISTER "\n", rgstr);
51211.72Skamil		} else if (strcmp(aux, "setregs") == 0) {
51221.72Skamil			DPRINTF("Call SETREGS for the child process\n");
51231.72Skamil			SYSCALL_REQUIRE(
51241.147Skamil			    ptrace(PT_SETREGS, child, &gpr, 0) != -1);
51251.72Skamil		}
51261.72Skamil	}
51271.1Skamil#endif
51281.1Skamil
51291.72Skamil#if defined(HAVE_FPREGS)
51301.72Skamil	if (strcmp(regset, "fpregs") == 0) {
51311.72Skamil		DPRINTF("Call GETFPREGS for the child process\n");
51321.72Skamil		SYSCALL_REQUIRE(ptrace(PT_GETFPREGS, child, &fpr, 0) != -1);
51331.72Skamil
51341.72Skamil		if (strcmp(aux, "getfpregs") == 0) {
51351.72Skamil			DPRINTF("Retrieved FP registers\n");
51361.72Skamil		} else if (strcmp(aux, "setfpregs") == 0) {
51371.72Skamil			DPRINTF("Call SETFPREGS for the child\n");
51381.72Skamil			SYSCALL_REQUIRE(
51391.72Skamil			    ptrace(PT_SETFPREGS, child, &fpr, 0) != -1);
51401.72Skamil		}
51411.1Skamil	}
51421.1Skamil#endif
51431.1Skamil
51441.13Schristos	DPRINTF("Before resuming the child process where it left off and "
51451.1Skamil	    "without signal to be sent\n");
51461.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
51471.1Skamil
51481.147Skamil	if (strstr(aux, "unaligned") != NULL) {
51491.147Skamil		DPRINTF("Before resuming the child process where it left off "
51501.147Skamil		    "and without signal to be sent\n");
51511.147Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
51521.147Skamil
51531.147Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
51541.147Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
51551.147Skamil		    child);
51561.147Skamil
51571.147Skamil		validate_status_signaled(status, SIGKILL, 0);
51581.147Skamil
51591.147Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
51601.147Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
51611.147Skamil		    wpid = TWAIT_GENERIC(child, &status, 0));
51621.147Skamil	} else {
51631.147Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
51641.147Skamil		TWAIT_REQUIRE_SUCCESS(
51651.147Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
51661.1Skamil
51671.147Skamil		validate_status_exited(status, exitval);
51681.1Skamil
51691.147Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
51701.147Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
51711.147Skamil		    wpid = TWAIT_GENERIC(child, &status, 0));
51721.147Skamil	}
51731.1Skamil}
51741.1Skamil
51751.72Skamil#define ACCESS_REGS(test, regset, aux)					\
51761.72SkamilATF_TC(test);								\
51771.72SkamilATF_TC_HEAD(test, tc)							\
51781.72Skamil{									\
51791.72Skamil        atf_tc_set_md_var(tc, "descr",					\
51801.72Skamil            "Verify " regset " with auxiliary operation: " aux);	\
51811.72Skamil}									\
51821.72Skamil									\
51831.72SkamilATF_TC_BODY(test, tc)							\
51841.72Skamil{									\
51851.72Skamil									\
51861.72Skamil        access_regs(regset, aux);					\
51871.1Skamil}
51881.1Skamil#endif
51891.1Skamil
51901.72Skamil#if defined(HAVE_GPREGS)
51911.72SkamilACCESS_REGS(access_regs1, "regs", "none")
51921.72SkamilACCESS_REGS(access_regs2, "regs", "pc")
51931.72SkamilACCESS_REGS(access_regs3, "regs", "set_pc")
51941.72SkamilACCESS_REGS(access_regs4, "regs", "sp")
51951.72SkamilACCESS_REGS(access_regs5, "regs", "intrv")
51961.72SkamilACCESS_REGS(access_regs6, "regs", "setregs")
51971.147SkamilACCESS_REGS(access_regs_set_unaligned_pc_0x1, "regs", "set_pc+unaligned+0x1")
51981.147SkamilACCESS_REGS(access_regs_set_unaligned_pc_0x3, "regs", "set_pc+unaligned+0x3")
51991.147SkamilACCESS_REGS(access_regs_set_unaligned_pc_0x7, "regs", "set_pc+unaligned+0x7")
52001.1Skamil#endif
52011.1Skamil#if defined(HAVE_FPREGS)
52021.72SkamilACCESS_REGS(access_fpregs1, "fpregs", "getfpregs")
52031.72SkamilACCESS_REGS(access_fpregs2, "fpregs", "setfpregs")
52041.1Skamil#endif
52051.1Skamil
52061.72Skamil/// ----------------------------------------------------------------------------
52071.1Skamil
52081.1Skamil#if defined(PT_STEP)
52091.1Skamilstatic void
52101.95Skamilptrace_step(int N, int setstep, bool masked, bool ignored)
52111.1Skamil{
52121.1Skamil	const int exitval = 5;
52131.1Skamil	const int sigval = SIGSTOP;
52141.1Skamil	pid_t child, wpid;
52151.1Skamil#if defined(TWAIT_HAVE_STATUS)
52161.1Skamil	int status;
52171.1Skamil#endif
52181.1Skamil	int happy;
52191.95Skamil	struct sigaction sa;
52201.81Skamil	struct ptrace_siginfo info;
52211.95Skamil	sigset_t intmask;
52221.95Skamil	struct kinfo_proc2 kp;
52231.95Skamil	size_t len = sizeof(kp);
52241.95Skamil
52251.95Skamil	int name[6];
52261.95Skamil	const size_t namelen = __arraycount(name);
52271.95Skamil	ki_sigset_t kp_sigmask;
52281.95Skamil	ki_sigset_t kp_sigignore;
52291.1Skamil
52301.1Skamil#if defined(__arm__)
52311.1Skamil	/* PT_STEP not supported on arm 32-bit */
52321.1Skamil	atf_tc_expect_fail("PR kern/52119");
52331.1Skamil#endif
52341.1Skamil
52351.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
52361.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
52371.1Skamil	if (child == 0) {
52381.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
52391.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
52401.1Skamil
52411.95Skamil		if (masked) {
52421.95Skamil			sigemptyset(&intmask);
52431.95Skamil			sigaddset(&intmask, SIGTRAP);
52441.95Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
52451.95Skamil		}
52461.95Skamil
52471.95Skamil		if (ignored) {
52481.95Skamil			memset(&sa, 0, sizeof(sa));
52491.95Skamil			sa.sa_handler = SIG_IGN;
52501.95Skamil			sigemptyset(&sa.sa_mask);
52511.95Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
52521.95Skamil		}
52531.95Skamil
52541.1Skamil		happy = check_happy(999);
52551.1Skamil
52561.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
52571.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
52581.1Skamil
52591.1Skamil		FORKEE_ASSERT_EQ(happy, check_happy(999));
52601.1Skamil
52611.13Schristos		DPRINTF("Before exiting of the child process\n");
52621.1Skamil		_exit(exitval);
52631.1Skamil	}
52641.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
52651.1Skamil
52661.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
52671.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
52681.1Skamil
52691.1Skamil	validate_status_stopped(status, sigval);
52701.1Skamil
52711.81Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
52721.81Skamil	SYSCALL_REQUIRE(
52731.81Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
52741.81Skamil
52751.81Skamil	DPRINTF("Before checking siginfo_t\n");
52761.81Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
52771.81Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
52781.81Skamil
52791.95Skamil	name[0] = CTL_KERN,
52801.95Skamil	name[1] = KERN_PROC2,
52811.95Skamil	name[2] = KERN_PROC_PID;
52821.95Skamil	name[3] = child;
52831.95Skamil	name[4] = sizeof(kp);
52841.95Skamil	name[5] = 1;
52851.95Skamil
52861.95Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
52871.95Skamil
52881.95Skamil	if (masked)
52891.95Skamil		kp_sigmask = kp.p_sigmask;
52901.95Skamil
52911.95Skamil	if (ignored)
52921.95Skamil		kp_sigignore = kp.p_sigignore;
52931.95Skamil
52941.1Skamil	while (N --> 0) {
52951.2Skamil		if (setstep) {
52961.13Schristos			DPRINTF("Before resuming the child process where it "
52971.2Skamil			    "left off and without signal to be sent (use "
52981.9Skamil			    "PT_SETSTEP and PT_CONTINUE)\n");
52991.13Schristos			SYSCALL_REQUIRE(ptrace(PT_SETSTEP, child, 0, 0) != -1);
53001.13Schristos			SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0)
53011.2Skamil			    != -1);
53021.2Skamil		} else {
53031.13Schristos			DPRINTF("Before resuming the child process where it "
53041.2Skamil			    "left off and without signal to be sent (use "
53051.2Skamil			    "PT_STEP)\n");
53061.13Schristos			SYSCALL_REQUIRE(ptrace(PT_STEP, child, (void *)1, 0)
53071.2Skamil			    != -1);
53081.2Skamil		}
53091.1Skamil
53101.13Schristos		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
53111.1Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
53121.1Skamil		    child);
53131.1Skamil
53141.1Skamil		validate_status_stopped(status, SIGTRAP);
53151.2Skamil
53161.81Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
53171.81Skamil		SYSCALL_REQUIRE(
53181.81Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
53191.81Skamil
53201.81Skamil		DPRINTF("Before checking siginfo_t\n");
53211.81Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
53221.81Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_TRACE);
53231.81Skamil
53241.2Skamil		if (setstep) {
53251.13Schristos			SYSCALL_REQUIRE(ptrace(PT_CLEARSTEP, child, 0, 0) != -1);
53261.2Skamil		}
53271.95Skamil
53281.95Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
53291.95Skamil
53301.95Skamil		if (masked) {
53311.95Skamil			DPRINTF("kp_sigmask="
53321.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
53331.95Skamil			    PRIx32 "\n",
53341.95Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
53351.95Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
53361.95Skamil
53371.95Skamil			DPRINTF("kp.p_sigmask="
53381.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
53391.95Skamil			    PRIx32 "\n",
53401.95Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
53411.95Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
53421.95Skamil
53431.95Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
53441.95Skamil			    sizeof(kp_sigmask)));
53451.95Skamil		}
53461.95Skamil
53471.95Skamil		if (ignored) {
53481.95Skamil			DPRINTF("kp_sigignore="
53491.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
53501.95Skamil			    PRIx32 "\n",
53511.95Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
53521.95Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
53531.95Skamil
53541.95Skamil			DPRINTF("kp.p_sigignore="
53551.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
53561.95Skamil			    PRIx32 "\n",
53571.95Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
53581.95Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
53591.95Skamil
53601.95Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
53611.95Skamil			    sizeof(kp_sigignore)));
53621.95Skamil		}
53631.1Skamil	}
53641.1Skamil
53651.13Schristos	DPRINTF("Before resuming the child process where it left off and "
53661.1Skamil	    "without signal to be sent\n");
53671.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
53681.1Skamil
53691.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
53701.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
53711.1Skamil
53721.1Skamil	validate_status_exited(status, exitval);
53731.1Skamil
53741.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
53751.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
53761.1Skamil}
53771.1Skamil
53781.73Skamil#define PTRACE_STEP(test, N, setstep)					\
53791.73SkamilATF_TC(test);								\
53801.73SkamilATF_TC_HEAD(test, tc)							\
53811.73Skamil{									\
53821.73Skamil        atf_tc_set_md_var(tc, "descr",					\
53831.74Skamil            "Verify " #N " (PT_SETSTEP set to: " #setstep ")");		\
53841.73Skamil}									\
53851.73Skamil									\
53861.73SkamilATF_TC_BODY(test, tc)							\
53871.73Skamil{									\
53881.73Skamil									\
53891.95Skamil        ptrace_step(N, setstep, false, false);				\
53901.1Skamil}
53911.1Skamil
53921.73SkamilPTRACE_STEP(step1, 1, 0)
53931.73SkamilPTRACE_STEP(step2, 2, 0)
53941.73SkamilPTRACE_STEP(step3, 3, 0)
53951.73SkamilPTRACE_STEP(step4, 4, 0)
53961.73SkamilPTRACE_STEP(setstep1, 1, 1)
53971.73SkamilPTRACE_STEP(setstep2, 2, 1)
53981.73SkamilPTRACE_STEP(setstep3, 3, 1)
53991.73SkamilPTRACE_STEP(setstep4, 4, 1)
54001.95Skamil
54011.95SkamilATF_TC(step_signalmasked);
54021.95SkamilATF_TC_HEAD(step_signalmasked, tc)
54031.95Skamil{
54041.95Skamil	atf_tc_set_md_var(tc, "descr", "Verify PT_STEP with masked SIGTRAP");
54051.95Skamil}
54061.95Skamil
54071.95SkamilATF_TC_BODY(step_signalmasked, tc)
54081.95Skamil{
54091.95Skamil
54101.95Skamil	ptrace_step(1, 0, true, false);
54111.95Skamil}
54121.95Skamil
54131.95SkamilATF_TC(step_signalignored);
54141.95SkamilATF_TC_HEAD(step_signalignored, tc)
54151.95Skamil{
54161.95Skamil	atf_tc_set_md_var(tc, "descr", "Verify PT_STEP with ignored SIGTRAP");
54171.95Skamil}
54181.95Skamil
54191.95SkamilATF_TC_BODY(step_signalignored, tc)
54201.95Skamil{
54211.95Skamil
54221.95Skamil	ptrace_step(1, 0, false, true);
54231.95Skamil}
54241.1Skamil#endif
54251.1Skamil
54261.73Skamil/// ----------------------------------------------------------------------------
54271.1Skamil
54281.75Skamilstatic void
54291.75Skamilptrace_kill(const char *type)
54301.1Skamil{
54311.75Skamil	const int sigval = SIGSTOP;
54321.1Skamil	pid_t child, wpid;
54331.1Skamil#if defined(TWAIT_HAVE_STATUS)
54341.1Skamil	int status;
54351.1Skamil#endif
54361.1Skamil
54371.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
54381.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
54391.1Skamil	if (child == 0) {
54401.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
54411.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
54421.1Skamil
54431.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
54441.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
54451.1Skamil
54461.1Skamil		/* NOTREACHED */
54471.1Skamil		FORKEE_ASSERTX(0 &&
54481.1Skamil		    "Child should be terminated by a signal from its parent");
54491.1Skamil	}
54501.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
54511.1Skamil
54521.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
54531.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
54541.1Skamil
54551.1Skamil	validate_status_stopped(status, sigval);
54561.1Skamil
54571.75Skamil	DPRINTF("Before killing the child process with %s\n", type);
54581.75Skamil	if (strcmp(type, "ptrace(PT_KILL)") == 0) {
54591.75Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void*)1, 0) != -1);
54601.75Skamil	} else if (strcmp(type, "kill(SIGKILL)") == 0) {
54611.75Skamil		kill(child, SIGKILL);
54621.75Skamil	} else if (strcmp(type, "killpg(SIGKILL)") == 0) {
54631.75Skamil		setpgid(child, 0);
54641.75Skamil		killpg(getpgid(child), SIGKILL);
54651.75Skamil	}
54661.1Skamil
54671.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
54681.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
54691.1Skamil
54701.75Skamil	validate_status_signaled(status, SIGKILL, 0);
54711.1Skamil
54721.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
54731.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
54741.1Skamil}
54751.1Skamil
54761.75Skamil#define PTRACE_KILL(test, type)						\
54771.75SkamilATF_TC(test);								\
54781.75SkamilATF_TC_HEAD(test, tc)							\
54791.75Skamil{									\
54801.75Skamil        atf_tc_set_md_var(tc, "descr",					\
54811.75Skamil            "Verify killing the child with " type);			\
54821.75Skamil}									\
54831.75Skamil									\
54841.75SkamilATF_TC_BODY(test, tc)							\
54851.75Skamil{									\
54861.75Skamil									\
54871.75Skamil        ptrace_kill(type);						\
54881.1Skamil}
54891.1Skamil
54901.75Skamil// PT_CONTINUE with SIGKILL is covered by traceme_sendsignal_simple1
54911.75SkamilPTRACE_KILL(kill1, "ptrace(PT_KILL)")
54921.75SkamilPTRACE_KILL(kill2, "kill(SIGKILL)")
54931.75SkamilPTRACE_KILL(kill3, "killpg(SIGKILL)")
54941.1Skamil
54951.75Skamil/// ----------------------------------------------------------------------------
54961.1Skamil
54971.143Skamilstatic int lwpinfo_thread_sigmask[] = {SIGXCPU, SIGPIPE, SIGALRM, SIGURG};
54981.143Skamil
54991.143Skamilstatic pthread_mutex_t lwpinfo_thread_mtx = PTHREAD_MUTEX_INITIALIZER;
55001.143Skamilstatic pthread_cond_t lwpinfo_thread_cnd = PTHREAD_COND_INITIALIZER;
55011.143Skamilstatic volatile size_t lwpinfo_thread_done;
55021.143Skamil
55031.143Skamilstatic void *
55041.143Skamillwpinfo_thread(void *arg)
55051.143Skamil{
55061.143Skamil	sigset_t s;
55071.143Skamil	volatile void **tcb;
55081.143Skamil
55091.143Skamil	tcb = (volatile void **)arg;
55101.143Skamil
55111.145Skamil	*tcb = _lwp_getprivate();
55121.143Skamil	DPRINTF("Storing tcb[] = %p from thread %d\n", *tcb, _lwp_self());
55131.143Skamil
55141.143Skamil	pthread_setname_np(pthread_self(), "thread %d",
55151.143Skamil	    (void *)(intptr_t)_lwp_self());
55161.143Skamil
55171.143Skamil	sigemptyset(&s);
55181.143Skamil	pthread_mutex_lock(&lwpinfo_thread_mtx);
55191.143Skamil	sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
55201.143Skamil	lwpinfo_thread_done++;
55211.143Skamil	pthread_sigmask(SIG_BLOCK, &s, NULL);
55221.143Skamil	pthread_cond_signal(&lwpinfo_thread_cnd);
55231.143Skamil	pthread_mutex_unlock(&lwpinfo_thread_mtx);
55241.143Skamil
55251.143Skamil	return infinite_thread(NULL);
55261.143Skamil}
55271.143Skamil
55281.77Skamilstatic void
55291.143Skamiltraceme_lwpinfo(const size_t threads, const char *iter)
55301.1Skamil{
55311.1Skamil	const int sigval = SIGSTOP;
55321.77Skamil	const int sigval2 = SIGINT;
55331.1Skamil	pid_t child, wpid;
55341.1Skamil#if defined(TWAIT_HAVE_STATUS)
55351.1Skamil	int status;
55361.1Skamil#endif
55371.77Skamil	struct ptrace_lwpinfo lwp = {0, 0};
55381.143Skamil	struct ptrace_lwpstatus lwpstatus = {0};
55391.77Skamil	struct ptrace_siginfo info;
55401.143Skamil	void *private;
55411.143Skamil	char *name;
55421.143Skamil	char namebuf[PL_LNAMELEN];
55431.143Skamil	volatile void *tcb[4];
55441.143Skamil	bool found;
55451.143Skamil	sigset_t s;
55461.77Skamil
55471.77Skamil	/* Maximum number of supported threads in this test */
55481.143Skamil	pthread_t t[__arraycount(tcb) - 1];
55491.143Skamil	size_t n, m;
55501.143Skamil	int rv;
55511.143Skamil	size_t bytes_read;
55521.143Skamil
55531.143Skamil	struct ptrace_io_desc io;
55541.143Skamil	sigset_t sigmask;
55551.77Skamil
55561.143Skamil	ATF_REQUIRE(__arraycount(t) >= threads);
55571.143Skamil	memset(tcb, 0, sizeof(tcb));
55581.1Skamil
55591.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
55601.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
55611.1Skamil	if (child == 0) {
55621.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
55631.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
55641.1Skamil
55651.145Skamil		tcb[0] = _lwp_getprivate();
55661.143Skamil		DPRINTF("Storing tcb[0] = %p\n", tcb[0]);
55671.143Skamil
55681.143Skamil		pthread_setname_np(pthread_self(), "thread %d",
55691.143Skamil		    (void *)(intptr_t)_lwp_self());
55701.143Skamil
55711.143Skamil		sigemptyset(&s);
55721.143Skamil		sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
55731.143Skamil		pthread_sigmask(SIG_BLOCK, &s, NULL);
55741.143Skamil
55751.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
55761.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
55771.1Skamil
55781.77Skamil		for (n = 0; n < threads; n++) {
55791.143Skamil			rv = pthread_create(&t[n], NULL, lwpinfo_thread,
55801.143Skamil			    &tcb[n + 1]);
55811.77Skamil			FORKEE_ASSERT(rv == 0);
55821.77Skamil		}
55831.77Skamil
55841.143Skamil		pthread_mutex_lock(&lwpinfo_thread_mtx);
55851.143Skamil		while (lwpinfo_thread_done < threads) {
55861.143Skamil			pthread_cond_wait(&lwpinfo_thread_cnd,
55871.143Skamil			    &lwpinfo_thread_mtx);
55881.143Skamil		}
55891.143Skamil		pthread_mutex_unlock(&lwpinfo_thread_mtx);
55901.143Skamil
55911.77Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval2));
55921.77Skamil		FORKEE_ASSERT(raise(sigval2) == 0);
55931.77Skamil
55941.77Skamil		/* NOTREACHED */
55951.77Skamil		FORKEE_ASSERTX(0 && "Not reached");
55961.1Skamil	}
55971.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
55981.1Skamil
55991.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
56001.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
56011.1Skamil
56021.1Skamil	validate_status_stopped(status, sigval);
56031.1Skamil
56041.77Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
56051.77Skamil	SYSCALL_REQUIRE(
56061.77Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
56071.77Skamil
56081.77Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
56091.77Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
56101.77Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
56111.77Skamil	    info.psi_siginfo.si_errno);
56121.77Skamil
56131.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
56141.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
56151.77Skamil
56161.143Skamil	if (strstr(iter, "LWPINFO") != NULL) {
56171.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
56181.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
56191.143Skamil		    != -1);
56201.1Skamil
56211.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
56221.143Skamil		ATF_REQUIRE(lwp.pl_lwpid > 0);
56231.1Skamil
56241.143Skamil		DPRINTF("Assert that lwp thread %d received event "
56251.143Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
56261.143Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
56271.143Skamil
56281.143Skamil		if (strstr(iter, "LWPSTATUS") != NULL) {
56291.143Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPSTATUS "
56301.143Skamil			    "for child\n");
56311.143Skamil			lwpstatus.pl_lwpid = lwp.pl_lwpid;
56321.143Skamil			SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child, &lwpstatus,
56331.143Skamil			    sizeof(lwpstatus)) != -1);
56341.143Skamil		}
56351.1Skamil
56361.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
56371.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
56381.143Skamil		    != -1);
56391.1Skamil
56401.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
56411.143Skamil		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
56421.143Skamil	} else {
56431.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
56441.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
56451.143Skamil		    sizeof(lwpstatus)) != -1);
56461.143Skamil
56471.143Skamil		DPRINTF("Assert that there exists a single thread only %d\n", lwpstatus.pl_lwpid);
56481.143Skamil		ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
56491.143Skamil
56501.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
56511.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
56521.143Skamil		    sizeof(lwpstatus)) != -1);
56531.143Skamil
56541.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
56551.143Skamil		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
56561.143Skamil	}
56571.1Skamil
56581.13Schristos	DPRINTF("Before resuming the child process where it left off and "
56591.1Skamil	    "without signal to be sent\n");
56601.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
56611.1Skamil
56621.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
56631.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
56641.1Skamil
56651.77Skamil	validate_status_stopped(status, sigval2);
56661.77Skamil
56671.77Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
56681.77Skamil	SYSCALL_REQUIRE(
56691.77Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
56701.77Skamil
56711.77Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
56721.77Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
56731.77Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
56741.77Skamil	    info.psi_siginfo.si_errno);
56751.77Skamil
56761.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval2);
56771.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
56781.77Skamil
56791.77Skamil	memset(&lwp, 0, sizeof(lwp));
56801.143Skamil	memset(&lwpstatus, 0, sizeof(lwpstatus));
56811.143Skamil
56821.143Skamil	memset(&io, 0, sizeof(io));
56831.143Skamil
56841.143Skamil	bytes_read = 0;
56851.143Skamil	io.piod_op = PIOD_READ_D;
56861.143Skamil	io.piod_len = sizeof(tcb);
56871.143Skamil
56881.143Skamil	do {
56891.143Skamil		io.piod_addr = (char *)&tcb + bytes_read;
56901.143Skamil		io.piod_offs = io.piod_addr;
56911.143Skamil
56921.143Skamil		rv = ptrace(PT_IO, child, &io, sizeof(io));
56931.143Skamil		ATF_REQUIRE(rv != -1 && io.piod_len != 0);
56941.143Skamil
56951.143Skamil		bytes_read += io.piod_len;
56961.143Skamil		io.piod_len = sizeof(tcb) - bytes_read;
56971.143Skamil	} while (bytes_read < sizeof(tcb));
56981.77Skamil
56991.77Skamil	for (n = 0; n <= threads; n++) {
57001.143Skamil		if (strstr(iter, "LWPINFO") != NULL) {
57011.143Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
57021.143Skamil			    "child\n");
57031.143Skamil			SYSCALL_REQUIRE(
57041.143Skamil			    ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
57051.143Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
57061.143Skamil
57071.143Skamil			DPRINTF("Assert that the thread exists\n");
57081.143Skamil			ATF_REQUIRE(lwp.pl_lwpid > 0);
57091.143Skamil
57101.143Skamil			DPRINTF("Assert that lwp thread %d received expected "
57111.143Skamil			    "event\n", lwp.pl_lwpid);
57121.143Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
57131.143Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
57141.143Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
57151.143Skamil
57161.143Skamil			if (strstr(iter, "LWPSTATUS") != NULL) {
57171.143Skamil				DPRINTF("Before calling ptrace(2) with "
57181.143Skamil				    "PT_LWPSTATUS for child\n");
57191.143Skamil				lwpstatus.pl_lwpid = lwp.pl_lwpid;
57201.143Skamil				SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child,
57211.143Skamil				    &lwpstatus, sizeof(lwpstatus)) != -1);
57221.143Skamil
57231.143Skamil				goto check_lwpstatus;
57241.143Skamil			}
57251.143Skamil		} else {
57261.143Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for "
57271.143Skamil			    "child\n");
57281.143Skamil			SYSCALL_REQUIRE(
57291.143Skamil			    ptrace(PT_LWPNEXT, child, &lwpstatus,
57301.143Skamil			    sizeof(lwpstatus)) != -1);
57311.143Skamil			DPRINTF("LWP=%d\n", lwpstatus.pl_lwpid);
57321.143Skamil
57331.143Skamil			DPRINTF("Assert that the thread exists\n");
57341.143Skamil			ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
57351.143Skamil
57361.143Skamil		check_lwpstatus:
57371.143Skamil
57381.143Skamil			if (strstr(iter, "pl_sigmask") != NULL) {
57391.143Skamil				sigmask = lwpstatus.pl_sigmask;
57401.143Skamil
57411.143Skamil				DPRINTF("Retrieved sigmask: "
57421.143Skamil				    "%02x%02x%02x%02x\n",
57431.143Skamil				    sigmask.__bits[0], sigmask.__bits[1],
57441.143Skamil				    sigmask.__bits[2], sigmask.__bits[3]);
57451.143Skamil
57461.143Skamil				found = false;
57471.143Skamil				for (m = 0;
57481.143Skamil				     m < __arraycount(lwpinfo_thread_sigmask);
57491.143Skamil				     m++) {
57501.143Skamil					if (sigismember(&sigmask,
57511.143Skamil					    lwpinfo_thread_sigmask[m])) {
57521.143Skamil						found = true;
57531.143Skamil						lwpinfo_thread_sigmask[m] = 0;
57541.143Skamil						break;
57551.143Skamil					}
57561.143Skamil				}
57571.143Skamil				ATF_REQUIRE(found == true);
57581.143Skamil			} else if (strstr(iter, "pl_name") != NULL) {
57591.143Skamil				name = lwpstatus.pl_name;
57601.143Skamil
57611.143Skamil				DPRINTF("Retrieved thread name: "
57621.143Skamil				    "%s\n", name);
57631.143Skamil
57641.143Skamil				snprintf(namebuf, sizeof namebuf, "thread %d",
57651.143Skamil				    lwpstatus.pl_lwpid);
57661.143Skamil
57671.143Skamil				ATF_REQUIRE(strcmp(name, namebuf) == 0);
57681.143Skamil			} else if (strstr(iter, "pl_private") != NULL) {
57691.143Skamil				private = lwpstatus.pl_private;
57701.143Skamil
57711.143Skamil				DPRINTF("Retrieved thread private pointer: "
57721.143Skamil				    "%p\n", private);
57731.143Skamil
57741.143Skamil				found = false;
57751.143Skamil				for (m = 0; m < __arraycount(tcb); m++) {
57761.143Skamil					DPRINTF("Comparing %p and %p\n",
57771.143Skamil					    private, tcb[m]);
57781.143Skamil					if (private == tcb[m]) {
57791.143Skamil						found = true;
57801.143Skamil						break;
57811.143Skamil					}
57821.143Skamil				}
57831.143Skamil				ATF_REQUIRE(found == true);
57841.143Skamil			}
57851.143Skamil		}
57861.143Skamil	}
57871.143Skamil
57881.143Skamil	if (strstr(iter, "LWPINFO") != NULL) {
57891.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
57901.143Skamil		    "child\n");
57911.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
57921.143Skamil		    != -1);
57931.77Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
57941.77Skamil
57951.143Skamil		DPRINTF("Assert that there are no more threads\n");
57961.143Skamil		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
57971.143Skamil	} else {
57981.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
57991.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
58001.143Skamil		    sizeof(lwpstatus)) != -1);
58011.77Skamil
58021.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
58031.143Skamil		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
58041.143Skamil	}
58051.77Skamil
58061.77Skamil	DPRINTF("Before resuming the child process where it left off and "
58071.77Skamil	    "without signal to be sent\n");
58081.77Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, SIGKILL) != -1);
58091.77Skamil
58101.77Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
58111.77Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
58121.77Skamil
58131.77Skamil	validate_status_signaled(status, SIGKILL, 0);
58141.1Skamil
58151.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
58161.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
58171.1Skamil}
58181.1Skamil
58191.143Skamil#define TRACEME_LWPINFO(test, threads, iter)				\
58201.77SkamilATF_TC(test);								\
58211.77SkamilATF_TC_HEAD(test, tc)							\
58221.77Skamil{									\
58231.77Skamil	atf_tc_set_md_var(tc, "descr",					\
58241.143Skamil	    "Verify " iter " with the child with " #threads		\
58251.77Skamil	    " spawned extra threads");					\
58261.77Skamil}									\
58271.77Skamil									\
58281.77SkamilATF_TC_BODY(test, tc)							\
58291.77Skamil{									\
58301.77Skamil									\
58311.143Skamil	traceme_lwpinfo(threads, iter);					\
58321.1Skamil}
58331.1Skamil
58341.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0, 0, "LWPINFO")
58351.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1, 1, "LWPINFO")
58361.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2, 2, "LWPINFO")
58371.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3, 3, "LWPINFO")
58381.143Skamil
58391.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus, 0, "LWPINFO+LWPSTATUS")
58401.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus, 1, "LWPINFO+LWPSTATUS")
58411.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus, 2, "LWPINFO+LWPSTATUS")
58421.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus, 3, "LWPINFO+LWPSTATUS")
58431.143Skamil
58441.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_sigmask, 0,
58451.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
58461.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_sigmask, 1,
58471.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
58481.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_sigmask, 2,
58491.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
58501.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_sigmask, 3,
58511.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
58521.143Skamil
58531.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_name, 0,
58541.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
58551.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_name, 1,
58561.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
58571.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_name, 2,
58581.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
58591.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_name, 3,
58601.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
58611.143Skamil
58621.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_private, 0,
58631.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
58641.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_private, 1,
58651.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
58661.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_private, 2,
58671.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
58681.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_private, 3,
58691.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
58701.143Skamil
58711.143SkamilTRACEME_LWPINFO(traceme_lwpnext0, 0, "LWPNEXT")
58721.143SkamilTRACEME_LWPINFO(traceme_lwpnext1, 1, "LWPNEXT")
58731.143SkamilTRACEME_LWPINFO(traceme_lwpnext2, 2, "LWPNEXT")
58741.143SkamilTRACEME_LWPINFO(traceme_lwpnext3, 3, "LWPNEXT")
58751.143Skamil
58761.143SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_sigmask, 0, "LWPNEXT+pl_sigmask")
58771.143SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_sigmask, 1, "LWPNEXT+pl_sigmask")
58781.143SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_sigmask, 2, "LWPNEXT+pl_sigmask")
58791.143SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_sigmask, 3, "LWPNEXT+pl_sigmask")
58801.143Skamil
58811.143SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_name, 0, "LWPNEXT+pl_name")
58821.143SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_name, 1, "LWPNEXT+pl_name")
58831.143SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_name, 2, "LWPNEXT+pl_name")
58841.143SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_name, 3, "LWPNEXT+pl_name")
58851.143Skamil
58861.143SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_private, 0, "LWPNEXT+pl_private")
58871.143SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_private, 1, "LWPNEXT+pl_private")
58881.143SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_private, 2, "LWPNEXT+pl_private")
58891.143SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_private, 3, "LWPNEXT+pl_private")
58901.77Skamil
58911.77Skamil/// ----------------------------------------------------------------------------
58921.77Skamil
58931.77Skamil#if defined(TWAIT_HAVE_PID)
58941.77Skamilstatic void
58951.77Skamilattach_lwpinfo(const int threads)
58961.1Skamil{
58971.77Skamil	const int sigval = SIGINT;
58981.1Skamil	struct msg_fds parent_tracee, parent_tracer;
58991.1Skamil	const int exitval_tracer = 10;
59001.1Skamil	pid_t tracee, tracer, wpid;
59011.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
59021.1Skamil#if defined(TWAIT_HAVE_STATUS)
59031.1Skamil	int status;
59041.1Skamil#endif
59051.77Skamil	struct ptrace_lwpinfo lwp = {0, 0};
59061.77Skamil	struct ptrace_siginfo info;
59071.77Skamil
59081.77Skamil	/* Maximum number of supported threads in this test */
59091.77Skamil	pthread_t t[3];
59101.77Skamil	int n, rv;
59111.1Skamil
59121.13Schristos	DPRINTF("Spawn tracee\n");
59131.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
59141.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
59151.1Skamil	tracee = atf_utils_fork();
59161.1Skamil	if (tracee == 0) {
59171.1Skamil		/* Wait for message from the parent */
59181.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
59191.1Skamil
59201.77Skamil		CHILD_FROM_PARENT("spawn threads", parent_tracee, msg);
59211.77Skamil
59221.77Skamil		for (n = 0; n < threads; n++) {
59231.77Skamil			rv = pthread_create(&t[n], NULL, infinite_thread, NULL);
59241.77Skamil			FORKEE_ASSERT(rv == 0);
59251.77Skamil		}
59261.77Skamil
59271.77Skamil		CHILD_TO_PARENT("tracee exit", parent_tracee, msg);
59281.77Skamil
59291.77Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
59301.77Skamil		FORKEE_ASSERT(raise(sigval) == 0);
59311.77Skamil
59321.77Skamil		/* NOTREACHED */
59331.77Skamil		FORKEE_ASSERTX(0 && "Not reached");
59341.1Skamil	}
59351.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
59361.1Skamil
59371.13Schristos	DPRINTF("Spawn debugger\n");
59381.1Skamil	tracer = atf_utils_fork();
59391.1Skamil	if (tracer == 0) {
59401.1Skamil		/* No IPC to communicate with the child */
59411.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
59421.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
59431.1Skamil
59441.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
59451.1Skamil		FORKEE_REQUIRE_SUCCESS(
59461.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
59471.1Skamil
59481.1Skamil		forkee_status_stopped(status, SIGSTOP);
59491.1Skamil
59501.77Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
59511.77Skamil		    "tracee");
59521.77Skamil		FORKEE_ASSERT(
59531.77Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
59541.77Skamil
59551.77Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
59561.77Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
59571.77Skamil		    "si_errno=%#x\n",
59581.77Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
59591.77Skamil		    info.psi_siginfo.si_errno);
59601.77Skamil
59611.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
59621.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
59631.77Skamil
59641.13Schristos		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
59651.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
59661.1Skamil		    != -1);
59671.1Skamil
59681.13Schristos		DPRINTF("Assert that there exists a thread\n");
59691.77Skamil		FORKEE_ASSERTX(lwp.pl_lwpid > 0);
59701.1Skamil
59711.13Schristos		DPRINTF("Assert that lwp thread %d received event "
59721.77Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
59731.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
59741.1Skamil
59751.77Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
59761.77Skamil		    "tracee\n");
59771.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
59781.1Skamil		    != -1);
59791.1Skamil
59801.77Skamil		DPRINTF("Assert that there are no more lwp threads in "
59811.77Skamil		    "tracee\n");
59821.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
59831.1Skamil
59841.1Skamil		/* Resume tracee with PT_CONTINUE */
59851.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
59861.1Skamil
59871.1Skamil		/* Inform parent that tracer has attached to tracee */
59881.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
59891.77Skamil
59901.1Skamil		/* Wait for parent */
59911.1Skamil		CHILD_FROM_PARENT("tracer wait", parent_tracer, msg);
59921.1Skamil
59931.77Skamil		/* Wait for tracee and assert that it raised a signal */
59941.77Skamil		FORKEE_REQUIRE_SUCCESS(
59951.77Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
59961.77Skamil
59971.77Skamil		forkee_status_stopped(status, SIGINT);
59981.77Skamil
59991.77Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
60001.77Skamil		    "child");
60011.77Skamil		FORKEE_ASSERT(
60021.77Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
60031.77Skamil
60041.77Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
60051.77Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
60061.77Skamil		    "si_errno=%#x\n",
60071.77Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
60081.77Skamil		    info.psi_siginfo.si_errno);
60091.77Skamil
60101.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
60111.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
60121.77Skamil
60131.77Skamil		memset(&lwp, 0, sizeof(lwp));
60141.77Skamil
60151.77Skamil		for (n = 0; n <= threads; n++) {
60161.77Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
60171.77Skamil			    "child\n");
60181.77Skamil			FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp,
60191.77Skamil			    sizeof(lwp)) != -1);
60201.77Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
60211.77Skamil
60221.77Skamil			DPRINTF("Assert that the thread exists\n");
60231.77Skamil			FORKEE_ASSERT(lwp.pl_lwpid > 0);
60241.77Skamil
60251.77Skamil			DPRINTF("Assert that lwp thread %d received expected "
60261.77Skamil			    "event\n", lwp.pl_lwpid);
60271.77Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
60281.77Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
60291.77Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
60301.77Skamil		}
60311.77Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
60321.77Skamil		    "tracee\n");
60331.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
60341.77Skamil		    != -1);
60351.77Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
60361.77Skamil
60371.77Skamil		DPRINTF("Assert that there are no more threads\n");
60381.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
60391.77Skamil
60401.77Skamil		DPRINTF("Before resuming the child process where it left off "
60411.77Skamil		    "and without signal to be sent\n");
60421.77Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, SIGKILL)
60431.77Skamil		    != -1);
60441.77Skamil
60451.1Skamil		/* Wait for tracee and assert that it exited */
60461.1Skamil		FORKEE_REQUIRE_SUCCESS(
60471.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
60481.1Skamil
60491.77Skamil		forkee_status_signaled(status, SIGKILL, 0);
60501.1Skamil
60511.13Schristos		DPRINTF("Before exiting of the tracer process\n");
60521.1Skamil		_exit(exitval_tracer);
60531.1Skamil	}
60541.1Skamil
60551.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
60561.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
60571.1Skamil
60581.77Skamil	DPRINTF("Resume the tracee and spawn threads\n");
60591.77Skamil	PARENT_TO_CHILD("spawn threads", parent_tracee, msg);
60601.77Skamil
60611.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
60621.77Skamil	PARENT_FROM_CHILD("tracee exit", parent_tracee, msg);
60631.1Skamil
60641.77Skamil	DPRINTF("Resume the tracer and let it detect multiple threads\n");
60651.1Skamil	PARENT_TO_CHILD("tracer wait", parent_tracer, msg);
60661.1Skamil
60671.13Schristos	DPRINTF("Wait for tracer to finish its job and exit - calling %s()\n",
60681.1Skamil	    TWAIT_FNAME);
60691.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
60701.1Skamil	    tracer);
60711.1Skamil
60721.1Skamil	validate_status_exited(status, exitval_tracer);
60731.1Skamil
60741.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
60751.1Skamil	    TWAIT_FNAME);
60761.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
60771.1Skamil	    tracee);
60781.1Skamil
60791.77Skamil	validate_status_signaled(status, SIGKILL, 0);
60801.1Skamil
60811.1Skamil	msg_close(&parent_tracer);
60821.1Skamil	msg_close(&parent_tracee);
60831.1Skamil}
60841.77Skamil
60851.77Skamil#define ATTACH_LWPINFO(test, threads)					\
60861.77SkamilATF_TC(test);								\
60871.77SkamilATF_TC_HEAD(test, tc)							\
60881.77Skamil{									\
60891.77Skamil	atf_tc_set_md_var(tc, "descr",					\
60901.77Skamil	    "Verify LWPINFO with the child with " #threads		\
60911.77Skamil	    " spawned extra threads (tracer is not the original "	\
60921.77Skamil	    "parent)");							\
60931.77Skamil}									\
60941.77Skamil									\
60951.77SkamilATF_TC_BODY(test, tc)							\
60961.77Skamil{									\
60971.77Skamil									\
60981.77Skamil	attach_lwpinfo(threads);					\
60991.77Skamil}
61001.77Skamil
61011.77SkamilATTACH_LWPINFO(attach_lwpinfo0, 0)
61021.77SkamilATTACH_LWPINFO(attach_lwpinfo1, 1)
61031.77SkamilATTACH_LWPINFO(attach_lwpinfo2, 2)
61041.77SkamilATTACH_LWPINFO(attach_lwpinfo3, 3)
61051.1Skamil#endif
61061.1Skamil
61071.77Skamil/// ----------------------------------------------------------------------------
61081.77Skamil
61091.1Skamilstatic void
61101.79Skamilptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c), int *signal_caught)
61111.1Skamil{
61121.1Skamil	const int exitval = 5;
61131.1Skamil	const int sigval = SIGINT;
61141.1Skamil	const int sigfaked = SIGTRAP;
61151.1Skamil	const int sicodefaked = TRAP_BRKPT;
61161.1Skamil	pid_t child, wpid;
61171.1Skamil	struct sigaction sa;
61181.1Skamil#if defined(TWAIT_HAVE_STATUS)
61191.1Skamil	int status;
61201.1Skamil#endif
61211.1Skamil	struct ptrace_siginfo info;
61221.1Skamil	memset(&info, 0, sizeof(info));
61231.1Skamil
61241.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
61251.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
61261.1Skamil	if (child == 0) {
61271.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
61281.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
61291.1Skamil
61301.79Skamil		sa.sa_sigaction = sah;
61311.1Skamil		sa.sa_flags = SA_SIGINFO;
61321.1Skamil		sigemptyset(&sa.sa_mask);
61331.1Skamil
61341.79Skamil		FORKEE_ASSERT(sigaction(faked ? sigfaked : sigval, &sa, NULL)
61351.79Skamil		    != -1);
61361.1Skamil
61371.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
61381.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
61391.1Skamil
61401.79Skamil		FORKEE_ASSERT_EQ(*signal_caught, 1);
61411.1Skamil
61421.13Schristos		DPRINTF("Before exiting of the child process\n");
61431.1Skamil		_exit(exitval);
61441.1Skamil	}
61451.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
61461.1Skamil
61471.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
61481.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
61491.1Skamil
61501.1Skamil	validate_status_stopped(status, sigval);
61511.1Skamil
61521.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
61531.61Skre	SYSCALL_REQUIRE(
61541.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
61551.1Skamil
61561.13Schristos	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
61571.13Schristos	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
61581.1Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
61591.1Skamil	    info.psi_siginfo.si_errno);
61601.1Skamil
61611.79Skamil	if (faked) {
61621.79Skamil		DPRINTF("Before setting new faked signal to signo=%d "
61631.79Skamil		    "si_code=%d\n", sigfaked, sicodefaked);
61641.79Skamil		info.psi_siginfo.si_signo = sigfaked;
61651.79Skamil		info.psi_siginfo.si_code = sicodefaked;
61661.79Skamil	}
61671.1Skamil
61681.13Schristos	DPRINTF("Before calling ptrace(2) with PT_SET_SIGINFO for child\n");
61691.61Skre	SYSCALL_REQUIRE(
61701.61Skre	    ptrace(PT_SET_SIGINFO, child, &info, sizeof(info)) != -1);
61711.1Skamil
61721.79Skamil	if (faked) {
61731.79Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
61741.79Skamil		    "child\n");
61751.79Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
61761.79Skamil		    sizeof(info)) != -1);
61771.1Skamil
61781.79Skamil		DPRINTF("Before checking siginfo_t\n");
61791.79Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigfaked);
61801.79Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, sicodefaked);
61811.79Skamil	}
61821.1Skamil
61831.13Schristos	DPRINTF("Before resuming the child process where it left off and "
61841.1Skamil	    "without signal to be sent\n");
61851.79Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
61861.79Skamil	    faked ? sigfaked : sigval) != -1);
61871.1Skamil
61881.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
61891.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
61901.1Skamil
61911.1Skamil	validate_status_exited(status, exitval);
61921.1Skamil
61931.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
61941.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
61951.1Skamil}
61961.1Skamil
61971.79Skamil#define PTRACE_SIGINFO(test, faked)					\
61981.79SkamilATF_TC(test);								\
61991.79SkamilATF_TC_HEAD(test, tc)							\
62001.79Skamil{									\
62011.79Skamil	atf_tc_set_md_var(tc, "descr",					\
62021.79Skamil	    "Verify basic PT_GET_SIGINFO and PT_SET_SIGINFO calls"	\
62031.79Skamil	    "with%s setting signal to new value", faked ? "" : "out");	\
62041.79Skamil}									\
62051.79Skamil									\
62061.79Skamilstatic int test##_caught = 0;						\
62071.79Skamil									\
62081.79Skamilstatic void								\
62091.79Skamiltest##_sighandler(int sig, siginfo_t *info, void *ctx)			\
62101.79Skamil{									\
62111.79Skamil	if (faked) {							\
62121.79Skamil		FORKEE_ASSERT_EQ(sig, SIGTRAP);				\
62131.79Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGTRAP);		\
62141.79Skamil		FORKEE_ASSERT_EQ(info->si_code, TRAP_BRKPT);		\
62151.79Skamil	} else {							\
62161.79Skamil		FORKEE_ASSERT_EQ(sig, SIGINT);				\
62171.79Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGINT);		\
62181.79Skamil		FORKEE_ASSERT_EQ(info->si_code, SI_LWP);		\
62191.79Skamil	}								\
62201.79Skamil									\
62211.79Skamil	++ test##_caught;						\
62221.79Skamil}									\
62231.79Skamil									\
62241.79SkamilATF_TC_BODY(test, tc)							\
62251.79Skamil{									\
62261.79Skamil									\
62271.79Skamil	ptrace_siginfo(faked, test##_sighandler, & test##_caught); 	\
62281.79Skamil}
62291.79Skamil
62301.79SkamilPTRACE_SIGINFO(siginfo_set_unmodified, false)
62311.79SkamilPTRACE_SIGINFO(siginfo_set_faked, true)
62321.79Skamil
62331.79Skamil/// ----------------------------------------------------------------------------
62341.79Skamil
62351.97Skamilstatic void
62361.97Skamiltraceme_exec(bool masked, bool ignored)
62371.1Skamil{
62381.1Skamil	const int sigval = SIGTRAP;
62391.1Skamil	pid_t child, wpid;
62401.1Skamil#if defined(TWAIT_HAVE_STATUS)
62411.1Skamil	int status;
62421.1Skamil#endif
62431.97Skamil	struct sigaction sa;
62441.97Skamil	struct ptrace_siginfo info;
62451.97Skamil	sigset_t intmask;
62461.97Skamil	struct kinfo_proc2 kp;
62471.97Skamil	size_t len = sizeof(kp);
62481.97Skamil
62491.97Skamil	int name[6];
62501.97Skamil	const size_t namelen = __arraycount(name);
62511.97Skamil	ki_sigset_t kp_sigmask;
62521.97Skamil	ki_sigset_t kp_sigignore;
62531.1Skamil
62541.1Skamil	memset(&info, 0, sizeof(info));
62551.1Skamil
62561.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
62571.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
62581.1Skamil	if (child == 0) {
62591.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
62601.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
62611.1Skamil
62621.97Skamil		if (masked) {
62631.97Skamil			sigemptyset(&intmask);
62641.97Skamil			sigaddset(&intmask, sigval);
62651.97Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
62661.97Skamil		}
62671.97Skamil
62681.97Skamil		if (ignored) {
62691.97Skamil			memset(&sa, 0, sizeof(sa));
62701.97Skamil			sa.sa_handler = SIG_IGN;
62711.97Skamil			sigemptyset(&sa.sa_mask);
62721.97Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
62731.97Skamil		}
62741.97Skamil
62751.13Schristos		DPRINTF("Before calling execve(2) from child\n");
62761.1Skamil		execlp("/bin/echo", "/bin/echo", NULL);
62771.1Skamil
62781.1Skamil		FORKEE_ASSERT(0 && "Not reached");
62791.1Skamil	}
62801.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
62811.1Skamil
62821.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
62831.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
62841.1Skamil
62851.1Skamil	validate_status_stopped(status, sigval);
62861.1Skamil
62871.97Skamil	name[0] = CTL_KERN,
62881.97Skamil	name[1] = KERN_PROC2,
62891.97Skamil	name[2] = KERN_PROC_PID;
62901.97Skamil	name[3] = getpid();
62911.97Skamil	name[4] = sizeof(kp);
62921.97Skamil	name[5] = 1;
62931.97Skamil
62941.97Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
62951.97Skamil
62961.97Skamil	if (masked)
62971.97Skamil		kp_sigmask = kp.p_sigmask;
62981.97Skamil
62991.97Skamil	if (ignored)
63001.97Skamil		kp_sigignore = kp.p_sigignore;
63011.97Skamil
63021.97Skamil	name[3] = getpid();
63031.97Skamil
63041.97Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
63051.97Skamil
63061.97Skamil	if (masked) {
63071.97Skamil		DPRINTF("kp_sigmask="
63081.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
63091.97Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
63101.97Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
63111.97Skamil
63121.97Skamil		DPRINTF("kp.p_sigmask="
63131.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
63141.97Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
63151.97Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
63161.97Skamil
63171.97Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
63181.97Skamil		    sizeof(kp_sigmask)));
63191.97Skamil	}
63201.97Skamil
63211.97Skamil	if (ignored) {
63221.97Skamil		DPRINTF("kp_sigignore="
63231.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
63241.97Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
63251.97Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
63261.97Skamil
63271.97Skamil		DPRINTF("kp.p_sigignore="
63281.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
63291.97Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
63301.97Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
63311.97Skamil
63321.97Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
63331.97Skamil		    sizeof(kp_sigignore)));
63341.97Skamil	}
63351.97Skamil
63361.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
63371.61Skre	SYSCALL_REQUIRE(
63381.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
63391.1Skamil
63401.13Schristos	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
63411.13Schristos	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
63421.1Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
63431.1Skamil	    info.psi_siginfo.si_errno);
63441.1Skamil
63451.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
63461.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
63471.1Skamil
63481.13Schristos	DPRINTF("Before resuming the child process where it left off and "
63491.1Skamil	    "without signal to be sent\n");
63501.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
63511.1Skamil
63521.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
63531.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
63541.1Skamil
63551.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
63561.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
63571.1Skamil}
63581.1Skamil
63591.97Skamil#define TRACEME_EXEC(test, masked, ignored)				\
63601.97SkamilATF_TC(test);								\
63611.97SkamilATF_TC_HEAD(test, tc)							\
63621.97Skamil{									\
63631.97Skamil       atf_tc_set_md_var(tc, "descr",					\
63641.97Skamil           "Detect SIGTRAP TRAP_EXEC from "				\
63651.97Skamil           "child%s%s", masked ? " with masked signal" : "",		\
63661.97Skamil           masked ? " with ignored signal" : "");			\
63671.97Skamil}									\
63681.97Skamil									\
63691.97SkamilATF_TC_BODY(test, tc)							\
63701.97Skamil{									\
63711.97Skamil									\
63721.97Skamil       traceme_exec(masked, ignored);					\
63731.97Skamil}
63741.97Skamil
63751.97SkamilTRACEME_EXEC(traceme_exec, false, false)
63761.97SkamilTRACEME_EXEC(traceme_signalmasked_exec, true, false)
63771.97SkamilTRACEME_EXEC(traceme_signalignored_exec, false, true)
63781.97Skamil
63791.82Skamil/// ----------------------------------------------------------------------------
63801.82Skamil
63811.135Skamil#define TRACE_THREADS_NUM 100
63821.135Skamil
63831.83Skamilstatic volatile int done;
63841.137Skamilpthread_mutex_t trace_threads_mtx = PTHREAD_MUTEX_INITIALIZER;
63851.1Skamil
63861.83Skamilstatic void *
63871.83Skamiltrace_threads_cb(void *arg __unused)
63881.1Skamil{
63891.1Skamil
63901.137Skamil	pthread_mutex_lock(&trace_threads_mtx);
63911.83Skamil	done++;
63921.137Skamil	pthread_mutex_unlock(&trace_threads_mtx);
63931.83Skamil
63941.135Skamil	while (done < TRACE_THREADS_NUM)
63951.135Skamil		sched_yield();
63961.83Skamil
63971.83Skamil	return NULL;
63981.1Skamil}
63991.1Skamil
64001.83Skamilstatic void
64011.153Skamiltrace_threads(bool trace_create, bool trace_exit, bool masked)
64021.1Skamil{
64031.1Skamil	const int sigval = SIGSTOP;
64041.1Skamil	pid_t child, wpid;
64051.1Skamil#if defined(TWAIT_HAVE_STATUS)
64061.1Skamil	int status;
64071.1Skamil#endif
64081.1Skamil	ptrace_state_t state;
64091.1Skamil	const int slen = sizeof(state);
64101.1Skamil	ptrace_event_t event;
64111.1Skamil	const int elen = sizeof(event);
64121.83Skamil	struct ptrace_siginfo info;
64131.83Skamil
64141.153Skamil	sigset_t intmask;
64151.153Skamil
64161.135Skamil	pthread_t t[TRACE_THREADS_NUM];
64171.83Skamil	int rv;
64181.83Skamil	size_t n;
64191.1Skamil	lwpid_t lid;
64201.83Skamil
64211.83Skamil	/* Track created and exited threads */
64221.141Skamil	struct lwp_event_count traced_lwps[__arraycount(t)] = {{0, 0}};
64231.83Skamil
64241.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
64251.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
64261.1Skamil	if (child == 0) {
64271.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
64281.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
64291.1Skamil
64301.153Skamil		if (masked) {
64311.153Skamil			sigemptyset(&intmask);
64321.153Skamil			sigaddset(&intmask, SIGTRAP);
64331.153Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
64341.153Skamil		}
64351.153Skamil
64361.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
64371.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
64381.1Skamil
64391.83Skamil		for (n = 0; n < __arraycount(t); n++) {
64401.83Skamil			rv = pthread_create(&t[n], NULL, trace_threads_cb,
64411.83Skamil			    NULL);
64421.83Skamil			FORKEE_ASSERT(rv == 0);
64431.83Skamil		}
64441.1Skamil
64451.83Skamil		for (n = 0; n < __arraycount(t); n++) {
64461.83Skamil			rv = pthread_join(t[n], NULL);
64471.83Skamil			FORKEE_ASSERT(rv == 0);
64481.83Skamil		}
64491.1Skamil
64501.83Skamil		/*
64511.83Skamil		 * There is race between _exit() and pthread_join() detaching
64521.83Skamil		 * a thread. For simplicity kill the process after detecting
64531.83Skamil		 * LWP events.
64541.83Skamil		 */
64551.83Skamil		while (true)
64561.83Skamil			continue;
64571.1Skamil
64581.83Skamil		FORKEE_ASSERT(0 && "Not reached");
64591.1Skamil	}
64601.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
64611.1Skamil
64621.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
64631.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64641.1Skamil
64651.1Skamil	validate_status_stopped(status, sigval);
64661.1Skamil
64671.83Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
64681.83Skamil	SYSCALL_REQUIRE(
64691.83Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
64701.1Skamil
64711.83Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
64721.83Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
64731.83Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
64741.83Skamil	    info.psi_siginfo.si_errno);
64751.1Skamil
64761.83Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
64771.83Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
64781.1Skamil
64791.83Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
64801.83Skamil	memset(&event, 0, sizeof(event));
64811.83Skamil	if (trace_create)
64821.83Skamil		event.pe_set_event |= PTRACE_LWP_CREATE;
64831.83Skamil	if (trace_exit)
64841.83Skamil		event.pe_set_event |= PTRACE_LWP_EXIT;
64851.83Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
64861.1Skamil
64871.13Schristos	DPRINTF("Before resuming the child process where it left off and "
64881.1Skamil	    "without signal to be sent\n");
64891.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
64901.1Skamil
64911.83Skamil	for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
64921.83Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
64931.83Skamil		    "SIGTRAP\n", TWAIT_FNAME);
64941.83Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
64951.83Skamil		    child);
64961.1Skamil
64971.83Skamil		validate_status_stopped(status, SIGTRAP);
64981.1Skamil
64991.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
65001.83Skamil		    "child\n");
65011.83Skamil		SYSCALL_REQUIRE(
65021.83Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
65031.1Skamil
65041.83Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
65051.83Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
65061.83Skamil		    "si_errno=%#x\n",
65071.83Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
65081.83Skamil		    info.psi_siginfo.si_errno);
65091.1Skamil
65101.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
65111.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
65121.1Skamil
65131.83Skamil		SYSCALL_REQUIRE(
65141.83Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
65151.1Skamil
65161.83Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
65171.83Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
65181.1Skamil
65191.83Skamil		lid = state.pe_lwp;
65201.83Skamil		DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
65211.1Skamil
65221.141Skamil		*FIND_EVENT_COUNT(traced_lwps, lid) += 1;
65231.1Skamil
65241.83Skamil		DPRINTF("Before resuming the child process where it left off "
65251.83Skamil		    "and without signal to be sent\n");
65261.83Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
65271.83Skamil	}
65281.1Skamil
65291.83Skamil	for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
65301.83Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
65311.83Skamil		    "SIGTRAP\n", TWAIT_FNAME);
65321.83Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
65331.83Skamil		    child);
65341.1Skamil
65351.83Skamil		validate_status_stopped(status, SIGTRAP);
65361.1Skamil
65371.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
65381.83Skamil		    "child\n");
65391.83Skamil		SYSCALL_REQUIRE(
65401.83Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
65411.1Skamil
65421.83Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
65431.83Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
65441.83Skamil		    "si_errno=%#x\n",
65451.83Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
65461.83Skamil		    info.psi_siginfo.si_errno);
65471.1Skamil
65481.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
65491.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
65501.1Skamil
65511.83Skamil		SYSCALL_REQUIRE(
65521.83Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
65531.1Skamil
65541.83Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
65551.83Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
65561.1Skamil
65571.83Skamil		lid = state.pe_lwp;
65581.83Skamil		DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
65591.1Skamil
65601.83Skamil		if (trace_create) {
65611.141Skamil			int *count = FIND_EVENT_COUNT(traced_lwps, lid);
65621.141Skamil			ATF_REQUIRE_EQ(*count, 1);
65631.141Skamil			*count = 0;
65641.83Skamil		}
65651.1Skamil
65661.83Skamil		DPRINTF("Before resuming the child process where it left off "
65671.83Skamil		    "and without signal to be sent\n");
65681.83Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
65691.83Skamil	}
65701.1Skamil
65711.83Skamil	kill(child, SIGKILL);
65721.1Skamil
65731.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
65741.1Skamil	    TWAIT_FNAME);
65751.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
65761.1Skamil
65771.83Skamil	validate_status_signaled(status, SIGKILL, 0);
65781.1Skamil
65791.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
65801.1Skamil	    TWAIT_FNAME);
65811.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
65821.1Skamil}
65831.1Skamil
65841.153Skamil#define TRACE_THREADS(test, trace_create, trace_exit, mask)		\
65851.83SkamilATF_TC(test);								\
65861.83SkamilATF_TC_HEAD(test, tc)							\
65871.83Skamil{									\
65881.83Skamil        atf_tc_set_md_var(tc, "descr",					\
65891.83Skamil            "Verify spawning threads with%s tracing LWP create and"	\
65901.83Skamil	    "with%s tracing LWP exit", trace_create ? "" : "out",	\
65911.83Skamil	    trace_exit ? "" : "out");					\
65921.83Skamil}									\
65931.83Skamil									\
65941.83SkamilATF_TC_BODY(test, tc)							\
65951.83Skamil{									\
65961.83Skamil									\
65971.153Skamil        trace_threads(trace_create, trace_exit, mask);			\
65981.83Skamil}
65991.83Skamil
66001.153SkamilTRACE_THREADS(trace_thread_nolwpevents, false, false, false)
66011.153SkamilTRACE_THREADS(trace_thread_lwpexit, false, true, false)
66021.153SkamilTRACE_THREADS(trace_thread_lwpcreate, true, false, false)
66031.153SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true, false)
66041.153Skamil
66051.153SkamilTRACE_THREADS(trace_thread_lwpexit_masked_sigtrap, false, true, true)
66061.153SkamilTRACE_THREADS(trace_thread_lwpcreate_masked_sigtrap, true, false, true)
66071.153SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit_masked_sigtrap, true, true, true)
66081.83Skamil
66091.83Skamil/// ----------------------------------------------------------------------------
66101.83Skamil
66111.84SkamilATF_TC(signal_mask_unrelated);
66121.84SkamilATF_TC_HEAD(signal_mask_unrelated, tc)
66131.1Skamil{
66141.1Skamil	atf_tc_set_md_var(tc, "descr",
66151.1Skamil	    "Verify that masking single unrelated signal does not stop tracer "
66161.1Skamil	    "from catching other signals");
66171.1Skamil}
66181.1Skamil
66191.84SkamilATF_TC_BODY(signal_mask_unrelated, tc)
66201.1Skamil{
66211.1Skamil	const int exitval = 5;
66221.1Skamil	const int sigval = SIGSTOP;
66231.1Skamil	const int sigmasked = SIGTRAP;
66241.1Skamil	const int signotmasked = SIGINT;
66251.1Skamil	pid_t child, wpid;
66261.1Skamil#if defined(TWAIT_HAVE_STATUS)
66271.1Skamil	int status;
66281.1Skamil#endif
66291.1Skamil	sigset_t intmask;
66301.1Skamil
66311.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
66321.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
66331.1Skamil	if (child == 0) {
66341.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
66351.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
66361.1Skamil
66371.1Skamil		sigemptyset(&intmask);
66381.1Skamil		sigaddset(&intmask, sigmasked);
66391.1Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
66401.1Skamil
66411.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
66421.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
66431.1Skamil
66441.13Schristos		DPRINTF("Before raising %s from child\n",
66451.1Skamil		    strsignal(signotmasked));
66461.1Skamil		FORKEE_ASSERT(raise(signotmasked) == 0);
66471.1Skamil
66481.13Schristos		DPRINTF("Before exiting of the child process\n");
66491.1Skamil		_exit(exitval);
66501.1Skamil	}
66511.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
66521.1Skamil
66531.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
66541.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66551.1Skamil
66561.1Skamil	validate_status_stopped(status, sigval);
66571.1Skamil
66581.13Schristos	DPRINTF("Before resuming the child process where it left off and "
66591.1Skamil	    "without signal to be sent\n");
66601.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
66611.1Skamil
66621.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
66631.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66641.1Skamil
66651.1Skamil	validate_status_stopped(status, signotmasked);
66661.1Skamil
66671.13Schristos	DPRINTF("Before resuming the child process where it left off and "
66681.1Skamil	    "without signal to be sent\n");
66691.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
66701.1Skamil
66711.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
66721.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66731.1Skamil
66741.1Skamil	validate_status_exited(status, exitval);
66751.1Skamil
66761.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
66771.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
66781.1Skamil}
66791.1Skamil
66801.84Skamil/// ----------------------------------------------------------------------------
66811.84Skamil
66821.1Skamil#if defined(TWAIT_HAVE_PID)
66831.99Skamilstatic void
66841.126Skamilfork2_body(const char *fn, bool masked, bool ignored)
66851.1Skamil{
66861.1Skamil	const int exitval = 5;
66871.126Skamil	const int exitval2 = 0; /* Match exit status from /bin/echo */
66881.1Skamil	const int sigval = SIGSTOP;
66891.99Skamil	pid_t child, child2 = 0, wpid;
66901.1Skamil#if defined(TWAIT_HAVE_STATUS)
66911.1Skamil	int status;
66921.1Skamil#endif
66931.1Skamil	ptrace_state_t state;
66941.1Skamil	const int slen = sizeof(state);
66951.1Skamil	ptrace_event_t event;
66961.1Skamil	const int elen = sizeof(event);
66971.99Skamil	struct sigaction sa;
66981.99Skamil	struct ptrace_siginfo info;
66991.99Skamil	sigset_t intmask;
67001.99Skamil	struct kinfo_proc2 kp;
67011.99Skamil	size_t len = sizeof(kp);
67021.99Skamil
67031.99Skamil	int name[6];
67041.99Skamil	const size_t namelen = __arraycount(name);
67051.99Skamil	ki_sigset_t kp_sigmask;
67061.99Skamil	ki_sigset_t kp_sigignore;
67071.1Skamil
67081.126Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
67091.14Schristos
67101.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
67111.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
67121.1Skamil	if (child == 0) {
67131.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
67141.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
67151.1Skamil
67161.99Skamil		if (masked) {
67171.99Skamil			sigemptyset(&intmask);
67181.99Skamil			sigaddset(&intmask, SIGTRAP);
67191.99Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
67201.99Skamil		}
67211.99Skamil
67221.99Skamil		if (ignored) {
67231.99Skamil			memset(&sa, 0, sizeof(sa));
67241.99Skamil			sa.sa_handler = SIG_IGN;
67251.99Skamil			sigemptyset(&sa.sa_mask);
67261.99Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
67271.99Skamil		}
67281.1Skamil
67291.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
67301.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
67311.1Skamil
67321.126Skamil		if (strcmp(fn, "spawn") == 0) {
67331.126Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
67341.126Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
67351.126Skamil		} else  {
67361.126Skamil			if (strcmp(fn, "fork") == 0) {
67371.126Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
67381.126Skamil			} else {
67391.126Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
67401.126Skamil			}
67411.126Skamil			if (child2 == 0)
67421.126Skamil				_exit(exitval2);
67431.126Skamil		}
67441.1Skamil
67451.1Skamil		FORKEE_REQUIRE_SUCCESS
67461.99Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
67471.1Skamil
67481.1Skamil		forkee_status_exited(status, exitval2);
67491.1Skamil
67501.13Schristos		DPRINTF("Before exiting of the child process\n");
67511.1Skamil		_exit(exitval);
67521.1Skamil	}
67531.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
67541.1Skamil
67551.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
67561.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
67571.1Skamil
67581.1Skamil	validate_status_stopped(status, sigval);
67591.1Skamil
67601.99Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
67611.99Skamil	SYSCALL_REQUIRE(
67621.99Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
67631.99Skamil
67641.99Skamil	DPRINTF("Before checking siginfo_t\n");
67651.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
67661.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
67671.1Skamil
67681.99Skamil	name[0] = CTL_KERN,
67691.99Skamil	name[1] = KERN_PROC2,
67701.99Skamil	name[2] = KERN_PROC_PID;
67711.99Skamil	name[3] = child;
67721.99Skamil	name[4] = sizeof(kp);
67731.99Skamil	name[5] = 1;
67741.1Skamil
67751.99Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
67761.1Skamil
67771.99Skamil	if (masked)
67781.99Skamil		kp_sigmask = kp.p_sigmask;
67791.1Skamil
67801.99Skamil	if (ignored)
67811.99Skamil		kp_sigignore = kp.p_sigignore;
67821.1Skamil
67831.126Skamil	DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
67841.126Skamil	    strcmp(fn, "spawn") == 0 ? "|PTRACE_POSIX_SPAWN" : "",
67851.126Skamil	    strcmp(fn, "fork") == 0 ? "|PTRACE_FORK" : "",
67861.126Skamil	    strcmp(fn, "vfork") == 0 ? "|PTRACE_VFORK" : "",
67871.126Skamil	    strcmp(fn, "vforkdone") == 0 ? "|PTRACE_VFORK_DONE" : "", child);
67881.99Skamil	event.pe_set_event = 0;
67891.126Skamil	if (strcmp(fn, "spawn") == 0)
67901.126Skamil		event.pe_set_event |= PTRACE_POSIX_SPAWN;
67911.126Skamil	if (strcmp(fn, "fork") == 0)
67921.99Skamil		event.pe_set_event |= PTRACE_FORK;
67931.126Skamil	if (strcmp(fn, "vfork") == 0)
67941.99Skamil		event.pe_set_event |= PTRACE_VFORK;
67951.126Skamil	if (strcmp(fn, "vforkdone") == 0)
67961.99Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
67971.99Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
67981.1Skamil
67991.99Skamil	DPRINTF("Before resuming the child process where it left off and "
68001.99Skamil	    "without signal to be sent\n");
68011.99Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
68021.1Skamil
68031.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
68041.126Skamil	    strcmp(fn, "vfork") == 0) {
68051.99Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
68061.99Skamil		    child);
68071.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
68081.99Skamil		    child);
68091.1Skamil
68101.99Skamil		validate_status_stopped(status, SIGTRAP);
68111.1Skamil
68121.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
68131.1Skamil
68141.99Skamil		if (masked) {
68151.99Skamil			DPRINTF("kp_sigmask="
68161.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
68171.99Skamil			    PRIx32 "\n",
68181.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
68191.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
68201.1Skamil
68211.99Skamil			DPRINTF("kp.p_sigmask="
68221.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
68231.99Skamil			    PRIx32 "\n",
68241.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
68251.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
68261.1Skamil
68271.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
68281.99Skamil			    sizeof(kp_sigmask)));
68291.99Skamil		}
68301.1Skamil
68311.99Skamil		if (ignored) {
68321.99Skamil			DPRINTF("kp_sigignore="
68331.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
68341.99Skamil			    PRIx32 "\n",
68351.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
68361.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
68371.1Skamil
68381.99Skamil			DPRINTF("kp.p_sigignore="
68391.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
68401.99Skamil			    PRIx32 "\n",
68411.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
68421.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
68431.1Skamil
68441.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
68451.99Skamil			    sizeof(kp_sigignore)));
68461.99Skamil		}
68471.1Skamil
68481.99Skamil		SYSCALL_REQUIRE(
68491.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
68501.126Skamil		if (strcmp(fn, "spawn") == 0) {
68511.126Skamil			ATF_REQUIRE_EQ(
68521.126Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
68531.126Skamil			       PTRACE_POSIX_SPAWN);
68541.126Skamil		}
68551.126Skamil		if (strcmp(fn, "fork") == 0) {
68561.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
68571.99Skamil			       PTRACE_FORK);
68581.99Skamil		}
68591.126Skamil		if (strcmp(fn, "vfork") == 0) {
68601.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
68611.99Skamil			       PTRACE_VFORK);
68621.99Skamil		}
68631.1Skamil
68641.99Skamil		child2 = state.pe_other_pid;
68651.99Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
68661.1Skamil
68671.99Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
68681.99Skamil		    "%d\n", TWAIT_FNAME, child2, child);
68691.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
68701.99Skamil		    child2);
68711.1Skamil
68721.99Skamil		validate_status_stopped(status, SIGTRAP);
68731.1Skamil
68741.99Skamil		name[3] = child2;
68751.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
68761.1Skamil
68771.99Skamil		if (masked) {
68781.99Skamil			DPRINTF("kp_sigmask="
68791.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
68801.99Skamil			    PRIx32 "\n",
68811.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
68821.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
68831.1Skamil
68841.99Skamil			DPRINTF("kp.p_sigmask="
68851.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
68861.99Skamil			    PRIx32 "\n",
68871.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
68881.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
68891.14Schristos
68901.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
68911.99Skamil			    sizeof(kp_sigmask)));
68921.99Skamil		}
68931.1Skamil
68941.99Skamil		if (ignored) {
68951.99Skamil			DPRINTF("kp_sigignore="
68961.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
68971.99Skamil			    PRIx32 "\n",
68981.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
68991.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
69001.1Skamil
69011.99Skamil			DPRINTF("kp.p_sigignore="
69021.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
69031.99Skamil			    PRIx32 "\n",
69041.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
69051.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
69061.1Skamil
69071.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
69081.99Skamil			    sizeof(kp_sigignore)));
69091.99Skamil		}
69101.1Skamil
69111.99Skamil		SYSCALL_REQUIRE(
69121.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
69131.126Skamil		if (strcmp(fn, "spawn") == 0) {
69141.126Skamil			ATF_REQUIRE_EQ(
69151.126Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
69161.126Skamil			       PTRACE_POSIX_SPAWN);
69171.126Skamil		}
69181.126Skamil		if (strcmp(fn, "fork") == 0) {
69191.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
69201.99Skamil			       PTRACE_FORK);
69211.99Skamil		}
69221.126Skamil		if (strcmp(fn, "vfork") == 0) {
69231.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
69241.99Skamil			       PTRACE_VFORK);
69251.99Skamil		}
69261.1Skamil
69271.99Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
69281.1Skamil
69291.99Skamil		DPRINTF("Before resuming the forkee process where it left off "
69301.99Skamil		    "and without signal to be sent\n");
69311.99Skamil		SYSCALL_REQUIRE(
69321.99Skamil		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
69331.1Skamil
69341.99Skamil		DPRINTF("Before resuming the child process where it left off "
69351.99Skamil		    "and without signal to be sent\n");
69361.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
69371.1Skamil	}
69381.1Skamil
69391.126Skamil	if (strcmp(fn, "vforkdone") == 0) {
69401.99Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
69411.99Skamil		    child);
69421.99Skamil		TWAIT_REQUIRE_SUCCESS(
69431.99Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
69441.1Skamil
69451.99Skamil		validate_status_stopped(status, SIGTRAP);
69461.1Skamil
69471.99Skamil		name[3] = child;
69481.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
69491.1Skamil
69501.102Skamil		/*
69511.102Skamil		 * SIGCHLD is now pending in the signal queue and
69521.102Skamil		 * the kernel presents it to userland as a masked signal.
69531.102Skamil		 */
69541.102Skamil		sigdelset((sigset_t *)&kp.p_sigmask, SIGCHLD);
69551.102Skamil
69561.99Skamil		if (masked) {
69571.99Skamil			DPRINTF("kp_sigmask="
69581.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
69591.99Skamil			    PRIx32 "\n",
69601.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
69611.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
69621.1Skamil
69631.99Skamil			DPRINTF("kp.p_sigmask="
69641.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
69651.99Skamil			    PRIx32 "\n",
69661.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
69671.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
69681.1Skamil
69691.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
69701.99Skamil			    sizeof(kp_sigmask)));
69711.99Skamil		}
69721.1Skamil
69731.99Skamil		if (ignored) {
69741.99Skamil			DPRINTF("kp_sigignore="
69751.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
69761.99Skamil			    PRIx32 "\n",
69771.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
69781.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
69791.1Skamil
69801.99Skamil			DPRINTF("kp.p_sigignore="
69811.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
69821.99Skamil			    PRIx32 "\n",
69831.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
69841.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
69851.1Skamil
69861.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
69871.99Skamil			    sizeof(kp_sigignore)));
69881.99Skamil		}
69891.1Skamil
69901.99Skamil		SYSCALL_REQUIRE(
69911.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
69921.99Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
69931.1Skamil
69941.99Skamil		child2 = state.pe_other_pid;
69951.99Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
69961.99Skamil		    child2);
69971.1Skamil
69981.99Skamil		DPRINTF("Before resuming the child process where it left off "
69991.99Skamil		    "and without signal to be sent\n");
70001.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
70011.99Skamil	}
70021.1Skamil
70031.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
70041.126Skamil	    strcmp(fn, "vfork") == 0) {
70051.99Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
70061.99Skamil		    "\n", TWAIT_FNAME);
70071.99Skamil		TWAIT_REQUIRE_SUCCESS(
70081.99Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
70091.1Skamil
70101.99Skamil		validate_status_exited(status, exitval2);
70111.1Skamil
70121.99Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
70131.99Skamil		    "process\n", TWAIT_FNAME);
70141.99Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
70151.99Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
70161.99Skamil	}
70171.1Skamil
70181.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
70191.1Skamil	    "SIGCHLD\n", TWAIT_FNAME);
70201.57Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
70211.1Skamil
70221.1Skamil	validate_status_stopped(status, SIGCHLD);
70231.1Skamil
70241.57Skamil	DPRINTF("Before resuming the child process where it left off and "
70251.1Skamil	    "without signal to be sent\n");
70261.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
70271.1Skamil
70281.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
70291.1Skamil	    TWAIT_FNAME);
70301.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
70311.1Skamil
70321.1Skamil	validate_status_exited(status, exitval);
70331.1Skamil
70341.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
70351.57Skamil	    TWAIT_FNAME);
70361.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
70371.1Skamil}
70381.1Skamil
70391.126Skamil#define FORK2_TEST(name,fn,masked,ignored)				\
70401.99SkamilATF_TC(name);								\
70411.99SkamilATF_TC_HEAD(name, tc)							\
70421.99Skamil{									\
70431.126Skamil	atf_tc_set_md_var(tc, "descr", "Verify that " fn " is caught "	\
70441.99Skamil	    "regardless of signal %s%s", 				\
70451.99Skamil	    masked ? "masked" : "", ignored ? "ignored" : "");		\
70461.99Skamil}									\
70471.99Skamil									\
70481.99SkamilATF_TC_BODY(name, tc)							\
70491.99Skamil{									\
70501.99Skamil									\
70511.126Skamil	fork2_body(fn, masked, ignored);				\
70521.1Skamil}
70531.1Skamil
70541.126SkamilFORK2_TEST(posix_spawn_singalmasked, "spawn", true, false)
70551.126SkamilFORK2_TEST(posix_spawn_singalignored, "spawn", false, true)
70561.126SkamilFORK2_TEST(fork_singalmasked, "fork", true, false)
70571.126SkamilFORK2_TEST(fork_singalignored, "fork", false, true)
70581.126SkamilFORK2_TEST(vfork_singalmasked, "vfork", true, false)
70591.126SkamilFORK2_TEST(vfork_singalignored, "vfork", false, true)
70601.126SkamilFORK2_TEST(vforkdone_singalmasked, "vforkdone", true, false)
70611.126SkamilFORK2_TEST(vforkdone_singalignored, "vforkdone", false, true)
70621.1Skamil#endif
70631.1Skamil
70641.99Skamil/// ----------------------------------------------------------------------------
70651.1Skamil
70661.151Skamilstatic void *
70671.151Skamilthread_and_exec_thread_cb(void *arg __unused)
70681.151Skamil{
70691.151Skamil
70701.151Skamil	execlp("/bin/echo", "/bin/echo", NULL);
70711.151Skamil
70721.151Skamil	abort();
70731.151Skamil}
70741.151Skamil
70751.151Skamilstatic void
70761.151Skamilthreads_and_exec(void)
70771.151Skamil{
70781.151Skamil	const int sigval = SIGSTOP;
70791.151Skamil	pid_t child, wpid;
70801.151Skamil#if defined(TWAIT_HAVE_STATUS)
70811.151Skamil	int status;
70821.151Skamil#endif
70831.151Skamil	ptrace_state_t state;
70841.151Skamil	const int slen = sizeof(state);
70851.151Skamil	ptrace_event_t event;
70861.151Skamil	const int elen = sizeof(event);
70871.151Skamil	struct ptrace_siginfo info;
70881.151Skamil
70891.151Skamil	pthread_t t;
70901.151Skamil	lwpid_t lid;
70911.151Skamil
70921.151Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
70931.151Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
70941.151Skamil	if (child == 0) {
70951.151Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
70961.151Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
70971.151Skamil
70981.151Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
70991.151Skamil		FORKEE_ASSERT(raise(sigval) == 0);
71001.151Skamil
71011.151Skamil		FORKEE_ASSERT(pthread_create(&t, NULL,
71021.151Skamil		    thread_and_exec_thread_cb, NULL) == 0);
71031.151Skamil
71041.151Skamil		for (;;)
71051.151Skamil			continue;
71061.151Skamil
71071.151Skamil		FORKEE_ASSERT(0 && "Not reached");
71081.151Skamil	}
71091.151Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
71101.151Skamil
71111.151Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
71121.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
71131.151Skamil
71141.151Skamil	validate_status_stopped(status, sigval);
71151.151Skamil
71161.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
71171.151Skamil	SYSCALL_REQUIRE(
71181.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
71191.151Skamil
71201.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
71211.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
71221.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
71231.151Skamil	    info.psi_siginfo.si_errno);
71241.151Skamil
71251.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
71261.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
71271.151Skamil
71281.151Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
71291.151Skamil	memset(&event, 0, sizeof(event));
71301.151Skamil	event.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
71311.151Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
71321.151Skamil
71331.151Skamil	DPRINTF("Before resuming the child process where it left off and "
71341.151Skamil	    "without signal to be sent\n");
71351.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
71361.151Skamil
71371.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
71381.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
71391.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
71401.151Skamil	    child);
71411.151Skamil
71421.151Skamil	validate_status_stopped(status, SIGTRAP);
71431.151Skamil
71441.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
71451.151Skamil	    "child\n");
71461.151Skamil	SYSCALL_REQUIRE(
71471.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
71481.151Skamil
71491.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
71501.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
71511.151Skamil	    "si_errno=%#x\n",
71521.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
71531.151Skamil	    info.psi_siginfo.si_errno);
71541.151Skamil
71551.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
71561.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
71571.151Skamil
71581.151Skamil	SYSCALL_REQUIRE(
71591.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
71601.151Skamil
71611.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
71621.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
71631.151Skamil
71641.151Skamil	lid = state.pe_lwp;
71651.151Skamil	DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
71661.151Skamil
71671.151Skamil	DPRINTF("Before resuming the child process where it left off "
71681.151Skamil	    "and without signal to be sent\n");
71691.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
71701.151Skamil
71711.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
71721.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
71731.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
71741.151Skamil	    child);
71751.151Skamil
71761.151Skamil	validate_status_stopped(status, SIGTRAP);
71771.151Skamil
71781.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
71791.151Skamil	    "child\n");
71801.151Skamil	SYSCALL_REQUIRE(
71811.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
71821.151Skamil
71831.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
71841.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
71851.151Skamil	    "si_errno=%#x\n",
71861.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
71871.151Skamil	    info.psi_siginfo.si_errno);
71881.151Skamil
71891.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
71901.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
71911.151Skamil
71921.151Skamil	SYSCALL_REQUIRE(
71931.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
71941.151Skamil
71951.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
71961.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
71971.151Skamil
71981.151Skamil	lid = state.pe_lwp;
71991.151Skamil	DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
72001.151Skamil
72011.151Skamil	DPRINTF("Before resuming the child process where it left off "
72021.151Skamil	    "and without signal to be sent\n");
72031.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
72041.151Skamil
72051.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
72061.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
72071.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
72081.151Skamil	    child);
72091.151Skamil
72101.151Skamil	validate_status_stopped(status, SIGTRAP);
72111.151Skamil
72121.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
72131.151Skamil	    "child\n");
72141.151Skamil	SYSCALL_REQUIRE(
72151.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
72161.151Skamil
72171.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
72181.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
72191.151Skamil	    "si_errno=%#x\n",
72201.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
72211.151Skamil	    info.psi_siginfo.si_errno);
72221.151Skamil
72231.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
72241.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
72251.151Skamil
72261.151Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
72271.151Skamil
72281.151Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
72291.151Skamil	    TWAIT_FNAME);
72301.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
72311.151Skamil
72321.151Skamil	validate_status_signaled(status, SIGKILL, 0);
72331.151Skamil
72341.151Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
72351.151Skamil	    TWAIT_FNAME);
72361.151Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
72371.151Skamil}
72381.151Skamil
72391.151SkamilATF_TC(threads_and_exec);
72401.151SkamilATF_TC_HEAD(threads_and_exec, tc)
72411.151Skamil{
72421.151Skamil        atf_tc_set_md_var(tc, "descr",
72431.151Skamil            "Verify that multithreaded application on exec() will report "
72441.151Skamil	    "LWP_EXIT events");
72451.151Skamil}
72461.151Skamil
72471.151SkamilATF_TC_BODY(threads_and_exec, tc)
72481.151Skamil{
72491.151Skamil
72501.151Skamil        threads_and_exec();
72511.151Skamil}
72521.151Skamil
72531.151Skamil/// ----------------------------------------------------------------------------
72541.151Skamil
72551.154SkamilATF_TC(suspend_no_deadlock);
72561.154SkamilATF_TC_HEAD(suspend_no_deadlock, tc)
72571.1Skamil{
72581.1Skamil	atf_tc_set_md_var(tc, "descr",
72591.1Skamil	    "Verify that the while the only thread within a process is "
72601.1Skamil	    "suspended, the whole process cannot be unstopped");
72611.1Skamil}
72621.1Skamil
72631.154SkamilATF_TC_BODY(suspend_no_deadlock, tc)
72641.1Skamil{
72651.1Skamil	const int exitval = 5;
72661.1Skamil	const int sigval = SIGSTOP;
72671.1Skamil	pid_t child, wpid;
72681.1Skamil#if defined(TWAIT_HAVE_STATUS)
72691.1Skamil	int status;
72701.1Skamil#endif
72711.1Skamil	struct ptrace_siginfo psi;
72721.1Skamil
72731.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
72741.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
72751.1Skamil	if (child == 0) {
72761.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
72771.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
72781.1Skamil
72791.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
72801.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
72811.1Skamil
72821.13Schristos		DPRINTF("Before exiting of the child process\n");
72831.1Skamil		_exit(exitval);
72841.1Skamil	}
72851.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
72861.1Skamil
72871.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
72881.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
72891.1Skamil
72901.1Skamil	validate_status_stopped(status, sigval);
72911.1Skamil
72921.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
72931.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
72941.1Skamil
72951.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
72961.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
72971.1Skamil
72981.13Schristos	DPRINTF("Before resuming the child process where it left off and "
72991.1Skamil	    "without signal to be sent\n");
73001.1Skamil	ATF_REQUIRE_ERRNO(EDEADLK,
73011.1Skamil	    ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
73021.1Skamil
73031.13Schristos	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
73041.13Schristos	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
73051.1Skamil
73061.13Schristos	DPRINTF("Before resuming the child process where it left off and "
73071.1Skamil	    "without signal to be sent\n");
73081.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
73091.1Skamil
73101.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
73111.1Skamil	    TWAIT_FNAME);
73121.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
73131.1Skamil
73141.1Skamil	validate_status_exited(status, exitval);
73151.1Skamil
73161.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
73171.1Skamil	    TWAIT_FNAME);
73181.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
73191.1Skamil}
73201.1Skamil
73211.154Skamil/// ----------------------------------------------------------------------------
73221.154Skamil
73231.155Skamilstatic pthread_barrier_t barrier1_resume;
73241.155Skamilstatic pthread_barrier_t barrier2_resume;
73251.154Skamil
73261.155Skamilstatic void *
73271.155Skamilresume_thread(void *arg)
73281.154Skamil{
73291.154Skamil
73301.155Skamil	raise(SIGUSR1);
73311.155Skamil
73321.155Skamil	pthread_barrier_wait(&barrier1_resume);
73331.155Skamil
73341.155Skamil	/* Debugger will suspend the process here */
73351.155Skamil
73361.155Skamil	pthread_barrier_wait(&barrier2_resume);
73371.154Skamil
73381.155Skamil	raise(SIGUSR2);
73391.155Skamil
73401.155Skamil	return infinite_thread(arg);
73411.154Skamil}
73421.154Skamil
73431.155SkamilATF_TC(resume);
73441.155SkamilATF_TC_HEAD(resume, tc)
73451.1Skamil{
73461.1Skamil	atf_tc_set_md_var(tc, "descr",
73471.1Skamil	    "Verify that a thread can be suspended by a debugger and later "
73481.1Skamil	    "resumed by the debugger");
73491.1Skamil}
73501.1Skamil
73511.155SkamilATF_TC_BODY(resume, tc)
73521.1Skamil{
73531.1Skamil	const int sigval = SIGSTOP;
73541.1Skamil	pid_t child, wpid;
73551.1Skamil#if defined(TWAIT_HAVE_STATUS)
73561.1Skamil	int status;
73571.1Skamil#endif
73581.1Skamil	lwpid_t lid;
73591.1Skamil	struct ptrace_siginfo psi;
73601.155Skamil	pthread_t t;
73611.1Skamil
73621.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
73631.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
73641.1Skamil	if (child == 0) {
73651.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
73661.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
73671.1Skamil
73681.155Skamil		pthread_barrier_init(&barrier1_resume, NULL, 2);
73691.155Skamil		pthread_barrier_init(&barrier2_resume, NULL, 2);
73701.155Skamil
73711.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
73721.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
73731.1Skamil
73741.155Skamil		DPRINTF("Before creating new thread in child\n");
73751.155Skamil		FORKEE_ASSERT(pthread_create(&t, NULL, resume_thread, NULL) == 0);
73761.1Skamil
73771.155Skamil		pthread_barrier_wait(&barrier1_resume);
73781.1Skamil
73791.155Skamil		pthread_barrier_wait(&barrier2_resume);
73801.1Skamil
73811.155Skamil		infinite_thread(NULL);
73821.1Skamil	}
73831.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
73841.1Skamil
73851.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
73861.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
73871.1Skamil
73881.1Skamil	validate_status_stopped(status, sigval);
73891.1Skamil
73901.13Schristos	DPRINTF("Before resuming the child process where it left off and "
73911.1Skamil	    "without signal to be sent\n");
73921.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
73931.1Skamil
73941.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
73951.155Skamil	    "SIGUSR1\n", TWAIT_FNAME);
73961.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
73971.1Skamil
73981.155Skamil	validate_status_stopped(status, SIGUSR1);
73991.1Skamil
74001.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
74011.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
74021.1Skamil
74031.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
74041.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
74051.1Skamil
74061.155Skamil	lid = psi.psi_lwpid;
74071.1Skamil
74081.13Schristos	DPRINTF("Before resuming the child process where it left off and "
74091.1Skamil	    "without signal to be sent\n");
74101.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
74111.1Skamil
74121.155Skamil	DPRINTF("Before suspending the parent for 1 second, we expect no signals\n");
74131.155Skamil	SYSCALL_REQUIRE(sleep(1) == 0);
74141.155Skamil
74151.155Skamil#if defined(TWAIT_HAVE_OPTIONS)
74161.155Skamil	DPRINTF("Before calling %s() for the child - expected no status\n",
74171.155Skamil	    TWAIT_FNAME);
74181.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, WNOHANG), 0);
74191.155Skamil#endif
74201.155Skamil
74211.155Skamil	DPRINTF("Before resuming the child process where it left off and "
74221.155Skamil	    "without signal to be sent\n");
74231.155Skamil	SYSCALL_REQUIRE(ptrace(PT_STOP, child, NULL, 0) != -1);
74241.155Skamil
74251.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
74261.155Skamil	    "SIGSTOP\n", TWAIT_FNAME);
74271.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74281.1Skamil
74291.155Skamil	validate_status_stopped(status, SIGSTOP);
74301.1Skamil
74311.155Skamil	DPRINTF("Before resuming LWP %d\n", lid);
74321.155Skamil	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, lid) != -1);
74331.155Skamil
74341.155Skamil	DPRINTF("Before resuming the child process where it left off and "
74351.155Skamil	    "without signal to be sent\n");
74361.155Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
74371.1Skamil
74381.155Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
74391.155Skamil	    "SIGUSR2\n", TWAIT_FNAME);
74401.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74411.1Skamil
74421.155Skamil	validate_status_stopped(status, SIGUSR2);
74431.1Skamil
74441.13Schristos	DPRINTF("Before resuming the child process where it left off and "
74451.1Skamil	    "without signal to be sent\n");
74461.155Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
74471.1Skamil
74481.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
74491.1Skamil	    TWAIT_FNAME);
74501.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74511.1Skamil
74521.155Skamil	validate_status_signaled(status, SIGKILL, 0);
74531.1Skamil
74541.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
74551.1Skamil	    TWAIT_FNAME);
74561.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
74571.155Skamil}
74581.1Skamil
74591.155Skamil/// ----------------------------------------------------------------------------
74601.1Skamil
74611.1SkamilATF_TC(syscall1);
74621.1SkamilATF_TC_HEAD(syscall1, tc)
74631.1Skamil{
74641.1Skamil	atf_tc_set_md_var(tc, "descr",
74651.1Skamil	    "Verify that getpid(2) can be traced with PT_SYSCALL");
74661.1Skamil}
74671.1Skamil
74681.1SkamilATF_TC_BODY(syscall1, tc)
74691.1Skamil{
74701.1Skamil	const int exitval = 5;
74711.1Skamil	const int sigval = SIGSTOP;
74721.1Skamil	pid_t child, wpid;
74731.1Skamil#if defined(TWAIT_HAVE_STATUS)
74741.1Skamil	int status;
74751.1Skamil#endif
74761.1Skamil	struct ptrace_siginfo info;
74771.1Skamil	memset(&info, 0, sizeof(info));
74781.1Skamil
74791.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
74801.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
74811.1Skamil	if (child == 0) {
74821.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
74831.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
74841.1Skamil
74851.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
74861.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
74871.1Skamil
74881.1Skamil		syscall(SYS_getpid);
74891.1Skamil
74901.13Schristos		DPRINTF("Before exiting of the child process\n");
74911.1Skamil		_exit(exitval);
74921.1Skamil	}
74931.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
74941.1Skamil
74951.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
74961.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74971.1Skamil
74981.1Skamil	validate_status_stopped(status, sigval);
74991.1Skamil
75001.13Schristos	DPRINTF("Before resuming the child process where it left off and "
75011.1Skamil	    "without signal to be sent\n");
75021.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
75031.1Skamil
75041.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
75051.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
75061.1Skamil
75071.1Skamil	validate_status_stopped(status, SIGTRAP);
75081.1Skamil
75091.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
75101.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
75111.1Skamil
75121.38Skamil	DPRINTF("Before checking siginfo_t and lwpid\n");
75131.38Skamil	ATF_REQUIRE_EQ(info.psi_lwpid, 1);
75141.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
75151.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_SCE);
75161.1Skamil
75171.13Schristos	DPRINTF("Before resuming the child process where it left off and "
75181.1Skamil	    "without signal to be sent\n");
75191.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
75201.1Skamil
75211.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
75221.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
75231.1Skamil
75241.1Skamil	validate_status_stopped(status, SIGTRAP);
75251.1Skamil
75261.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
75271.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
75281.1Skamil
75291.38Skamil	DPRINTF("Before checking siginfo_t and lwpid\n");
75301.38Skamil	ATF_REQUIRE_EQ(info.psi_lwpid, 1);
75311.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
75321.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_SCX);
75331.1Skamil
75341.13Schristos	DPRINTF("Before resuming the child process where it left off and "
75351.1Skamil	    "without signal to be sent\n");
75361.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
75371.1Skamil
75381.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
75391.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
75401.1Skamil
75411.1Skamil	validate_status_exited(status, exitval);
75421.1Skamil
75431.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
75441.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
75451.1Skamil}
75461.1Skamil
75471.164Skamil/// ----------------------------------------------------------------------------
75481.164Skamil
75491.1SkamilATF_TC(syscallemu1);
75501.1SkamilATF_TC_HEAD(syscallemu1, tc)
75511.1Skamil{
75521.1Skamil	atf_tc_set_md_var(tc, "descr",
75531.1Skamil	    "Verify that exit(2) can be intercepted with PT_SYSCALLEMU");
75541.1Skamil}
75551.1Skamil
75561.1SkamilATF_TC_BODY(syscallemu1, tc)
75571.1Skamil{
75581.1Skamil	const int exitval = 5;
75591.1Skamil	const int sigval = SIGSTOP;
75601.1Skamil	pid_t child, wpid;
75611.1Skamil#if defined(TWAIT_HAVE_STATUS)
75621.1Skamil	int status;
75631.1Skamil#endif
75641.1Skamil
75651.6Skamil#if defined(__sparc__) && !defined(__sparc64__)
75661.6Skamil	/* syscallemu does not work on sparc (32-bit) */
75671.6Skamil	atf_tc_expect_fail("PR kern/52166");
75681.6Skamil#endif
75691.6Skamil
75701.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
75711.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
75721.1Skamil	if (child == 0) {
75731.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
75741.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
75751.1Skamil
75761.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
75771.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
75781.1Skamil
75791.1Skamil		syscall(SYS_exit, 100);
75801.1Skamil
75811.13Schristos		DPRINTF("Before exiting of the child process\n");
75821.1Skamil		_exit(exitval);
75831.1Skamil	}
75841.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
75851.1Skamil
75861.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
75871.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
75881.1Skamil
75891.1Skamil	validate_status_stopped(status, sigval);
75901.1Skamil
75911.13Schristos	DPRINTF("Before resuming the child process where it left off and "
75921.1Skamil	    "without signal to be sent\n");
75931.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
75941.1Skamil
75951.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
75961.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
75971.1Skamil
75981.1Skamil	validate_status_stopped(status, SIGTRAP);
75991.1Skamil
76001.13Schristos	DPRINTF("Set SYSCALLEMU for intercepted syscall\n");
76011.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALLEMU, child, (void *)1, 0) != -1);
76021.1Skamil
76031.13Schristos	DPRINTF("Before resuming the child process where it left off and "
76041.1Skamil	    "without signal to be sent\n");
76051.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
76061.1Skamil
76071.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76081.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
76091.1Skamil
76101.1Skamil	validate_status_stopped(status, SIGTRAP);
76111.1Skamil
76121.13Schristos	DPRINTF("Before resuming the child process where it left off and "
76131.1Skamil	    "without signal to be sent\n");
76141.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
76151.1Skamil
76161.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76171.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
76181.1Skamil
76191.1Skamil	validate_status_exited(status, exitval);
76201.1Skamil
76211.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76221.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
76231.1Skamil}
76241.1Skamil
76251.103Skamil/// ----------------------------------------------------------------------------
76261.103Skamil
76271.106Skamilstatic void
76281.106Skamilclone_body(int flags, bool trackfork, bool trackvfork,
76291.106Skamil    bool trackvforkdone)
76301.106Skamil{
76311.106Skamil	const int exitval = 5;
76321.106Skamil	const int exitval2 = 15;
76331.106Skamil	const int sigval = SIGSTOP;
76341.106Skamil	pid_t child, child2 = 0, wpid;
76351.106Skamil#if defined(TWAIT_HAVE_STATUS)
76361.106Skamil	int status;
76371.106Skamil#endif
76381.106Skamil	ptrace_state_t state;
76391.106Skamil	const int slen = sizeof(state);
76401.106Skamil	ptrace_event_t event;
76411.106Skamil	const int elen = sizeof(event);
76421.106Skamil
76431.106Skamil	const size_t stack_size = 1024 * 1024;
76441.106Skamil	void *stack, *stack_base;
76451.106Skamil
76461.106Skamil	stack = malloc(stack_size);
76471.106Skamil	ATF_REQUIRE(stack != NULL);
76481.106Skamil
76491.106Skamil#ifdef __MACHINE_STACK_GROWS_UP
76501.106Skamil	stack_base = stack;
76511.106Skamil#else
76521.106Skamil	stack_base = (char *)stack + stack_size;
76531.106Skamil#endif
76541.106Skamil
76551.106Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
76561.106Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
76571.106Skamil	if (child == 0) {
76581.106Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
76591.106Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
76601.106Skamil
76611.106Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
76621.106Skamil		FORKEE_ASSERT(raise(sigval) == 0);
76631.106Skamil
76641.106Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
76651.106Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
76661.106Skamil
76671.106Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
76681.106Skamil		    child2);
76691.106Skamil
76701.106Skamil		// XXX WALLSIG?
76711.106Skamil		FORKEE_REQUIRE_SUCCESS
76721.106Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
76731.106Skamil
76741.106Skamil		forkee_status_exited(status, exitval2);
76751.106Skamil
76761.106Skamil		DPRINTF("Before exiting of the child process\n");
76771.106Skamil		_exit(exitval);
76781.106Skamil	}
76791.106Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
76801.106Skamil
76811.106Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76821.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
76831.106Skamil
76841.106Skamil	validate_status_stopped(status, sigval);
76851.106Skamil
76861.106Skamil	DPRINTF("Set 0%s%s%s in EVENT_MASK for the child %d\n",
76871.106Skamil	    trackfork ? "|PTRACE_FORK" : "",
76881.106Skamil	    trackvfork ? "|PTRACE_VFORK" : "",
76891.106Skamil	    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", child);
76901.106Skamil	event.pe_set_event = 0;
76911.106Skamil	if (trackfork)
76921.106Skamil		event.pe_set_event |= PTRACE_FORK;
76931.106Skamil	if (trackvfork)
76941.106Skamil		event.pe_set_event |= PTRACE_VFORK;
76951.106Skamil	if (trackvforkdone)
76961.106Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
76971.106Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
76981.106Skamil
76991.106Skamil	DPRINTF("Before resuming the child process where it left off and "
77001.106Skamil	    "without signal to be sent\n");
77011.106Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
77021.106Skamil
77031.106Skamil#if defined(TWAIT_HAVE_PID)
77041.106Skamil	if ((trackfork && !(flags & CLONE_VFORK)) ||
77051.106Skamil	    (trackvfork && (flags & CLONE_VFORK))) {
77061.106Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
77071.106Skamil		    child);
77081.106Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
77091.106Skamil		    child);
77101.106Skamil
77111.106Skamil		validate_status_stopped(status, SIGTRAP);
77121.106Skamil
77131.106Skamil		SYSCALL_REQUIRE(
77141.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
77151.106Skamil		if (trackfork && !(flags & CLONE_VFORK)) {
77161.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
77171.106Skamil			       PTRACE_FORK);
77181.106Skamil		}
77191.106Skamil		if (trackvfork && (flags & CLONE_VFORK)) {
77201.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
77211.106Skamil			       PTRACE_VFORK);
77221.106Skamil		}
77231.106Skamil
77241.106Skamil		child2 = state.pe_other_pid;
77251.106Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
77261.106Skamil
77271.106Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
77281.106Skamil		    "%d\n", TWAIT_FNAME, child2, child);
77291.106Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
77301.106Skamil		    child2);
77311.106Skamil
77321.106Skamil		validate_status_stopped(status, SIGTRAP);
77331.106Skamil
77341.106Skamil		SYSCALL_REQUIRE(
77351.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
77361.106Skamil		if (trackfork && !(flags & CLONE_VFORK)) {
77371.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
77381.106Skamil			       PTRACE_FORK);
77391.106Skamil		}
77401.106Skamil		if (trackvfork && (flags & CLONE_VFORK)) {
77411.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
77421.106Skamil			       PTRACE_VFORK);
77431.106Skamil		}
77441.106Skamil
77451.106Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
77461.106Skamil
77471.106Skamil		DPRINTF("Before resuming the forkee process where it left off "
77481.106Skamil		    "and without signal to be sent\n");
77491.106Skamil		SYSCALL_REQUIRE(
77501.106Skamil		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
77511.106Skamil
77521.106Skamil		DPRINTF("Before resuming the child process where it left off "
77531.106Skamil		    "and without signal to be sent\n");
77541.106Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
77551.106Skamil	}
77561.106Skamil#endif
77571.106Skamil
77581.106Skamil	if (trackvforkdone && (flags & CLONE_VFORK)) {
77591.106Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
77601.106Skamil		    child);
77611.106Skamil		TWAIT_REQUIRE_SUCCESS(
77621.106Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
77631.106Skamil
77641.106Skamil		validate_status_stopped(status, SIGTRAP);
77651.106Skamil
77661.106Skamil		SYSCALL_REQUIRE(
77671.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
77681.106Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
77691.106Skamil
77701.106Skamil		child2 = state.pe_other_pid;
77711.106Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
77721.106Skamil		    child2);
77731.106Skamil
77741.106Skamil		DPRINTF("Before resuming the child process where it left off "
77751.106Skamil		    "and without signal to be sent\n");
77761.106Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
77771.106Skamil	}
77781.106Skamil
77791.103Skamil#if defined(TWAIT_HAVE_PID)
77801.106Skamil	if ((trackfork && !(flags & CLONE_VFORK)) ||
77811.106Skamil	    (trackvfork && (flags & CLONE_VFORK))) {
77821.106Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
77831.106Skamil		    "\n", TWAIT_FNAME);
77841.106Skamil		TWAIT_REQUIRE_SUCCESS(
77851.106Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
77861.106Skamil
77871.106Skamil		validate_status_exited(status, exitval2);
77881.106Skamil
77891.106Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
77901.106Skamil		    "process\n", TWAIT_FNAME);
77911.106Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
77921.106Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
77931.106Skamil	}
77941.106Skamil#endif
77951.106Skamil
77961.106Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
77971.106Skamil	    "SIGCHLD\n", TWAIT_FNAME);
77981.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
77991.106Skamil
78001.106Skamil	validate_status_stopped(status, SIGCHLD);
78011.106Skamil
78021.106Skamil	DPRINTF("Before resuming the child process where it left off and "
78031.106Skamil	    "without signal to be sent\n");
78041.106Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
78051.106Skamil
78061.106Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
78071.106Skamil	    TWAIT_FNAME);
78081.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
78091.106Skamil
78101.106Skamil	validate_status_exited(status, exitval);
78111.103Skamil
78121.106Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
78131.106Skamil	    TWAIT_FNAME);
78141.106Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
78151.106Skamil}
78161.103Skamil
78171.106Skamil#define CLONE_TEST(name,flags,tfork,tvfork,tvforkdone)			\
78181.106SkamilATF_TC(name);								\
78191.106SkamilATF_TC_HEAD(name, tc)							\
78201.106Skamil{									\
78211.106Skamil	atf_tc_set_md_var(tc, "descr", "Verify clone(%s) "		\
78221.106Skamil	    "called with 0%s%s%s in EVENT_MASK",			\
78231.106Skamil	    #flags,							\
78241.106Skamil	    tfork ? "|PTRACE_FORK" : "",				\
78251.106Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
78261.106Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
78271.106Skamil}									\
78281.106Skamil									\
78291.106SkamilATF_TC_BODY(name, tc)							\
78301.106Skamil{									\
78311.106Skamil									\
78321.106Skamil	clone_body(flags, tfork, tvfork, tvforkdone);			\
78331.103Skamil}
78341.103Skamil
78351.106SkamilCLONE_TEST(clone1, 0, false, false, false)
78361.106Skamil#if defined(TWAIT_HAVE_PID)
78371.106SkamilCLONE_TEST(clone2, 0, true, false, false)
78381.106SkamilCLONE_TEST(clone3, 0, false, true, false)
78391.106SkamilCLONE_TEST(clone4, 0, true, true, false)
78401.106Skamil#endif
78411.106SkamilCLONE_TEST(clone5, 0, false, false, true)
78421.106Skamil#if defined(TWAIT_HAVE_PID)
78431.106SkamilCLONE_TEST(clone6, 0, true, false, true)
78441.106SkamilCLONE_TEST(clone7, 0, false, true, true)
78451.106SkamilCLONE_TEST(clone8, 0, true, true, true)
78461.106Skamil#endif
78471.106Skamil
78481.106SkamilCLONE_TEST(clone_vm1, CLONE_VM, false, false, false)
78491.106Skamil#if defined(TWAIT_HAVE_PID)
78501.106SkamilCLONE_TEST(clone_vm2, CLONE_VM, true, false, false)
78511.106SkamilCLONE_TEST(clone_vm3, CLONE_VM, false, true, false)
78521.106SkamilCLONE_TEST(clone_vm4, CLONE_VM, true, true, false)
78531.106Skamil#endif
78541.106SkamilCLONE_TEST(clone_vm5, CLONE_VM, false, false, true)
78551.106Skamil#if defined(TWAIT_HAVE_PID)
78561.106SkamilCLONE_TEST(clone_vm6, CLONE_VM, true, false, true)
78571.106SkamilCLONE_TEST(clone_vm7, CLONE_VM, false, true, true)
78581.106SkamilCLONE_TEST(clone_vm8, CLONE_VM, true, true, true)
78591.106Skamil#endif
78601.106Skamil
78611.106SkamilCLONE_TEST(clone_fs1, CLONE_FS, false, false, false)
78621.106Skamil#if defined(TWAIT_HAVE_PID)
78631.106SkamilCLONE_TEST(clone_fs2, CLONE_FS, true, false, false)
78641.106SkamilCLONE_TEST(clone_fs3, CLONE_FS, false, true, false)
78651.106SkamilCLONE_TEST(clone_fs4, CLONE_FS, true, true, false)
78661.106Skamil#endif
78671.106SkamilCLONE_TEST(clone_fs5, CLONE_FS, false, false, true)
78681.106Skamil#if defined(TWAIT_HAVE_PID)
78691.106SkamilCLONE_TEST(clone_fs6, CLONE_FS, true, false, true)
78701.106SkamilCLONE_TEST(clone_fs7, CLONE_FS, false, true, true)
78711.106SkamilCLONE_TEST(clone_fs8, CLONE_FS, true, true, true)
78721.106Skamil#endif
78731.106Skamil
78741.106SkamilCLONE_TEST(clone_files1, CLONE_FILES, false, false, false)
78751.106Skamil#if defined(TWAIT_HAVE_PID)
78761.106SkamilCLONE_TEST(clone_files2, CLONE_FILES, true, false, false)
78771.106SkamilCLONE_TEST(clone_files3, CLONE_FILES, false, true, false)
78781.106SkamilCLONE_TEST(clone_files4, CLONE_FILES, true, true, false)
78791.106Skamil#endif
78801.106SkamilCLONE_TEST(clone_files5, CLONE_FILES, false, false, true)
78811.106Skamil#if defined(TWAIT_HAVE_PID)
78821.106SkamilCLONE_TEST(clone_files6, CLONE_FILES, true, false, true)
78831.106SkamilCLONE_TEST(clone_files7, CLONE_FILES, false, true, true)
78841.106SkamilCLONE_TEST(clone_files8, CLONE_FILES, true, true, true)
78851.106Skamil#endif
78861.106Skamil
78871.106Skamil//CLONE_TEST(clone_sighand1, CLONE_SIGHAND, false, false, false)
78881.106Skamil#if defined(TWAIT_HAVE_PID)
78891.106Skamil//CLONE_TEST(clone_sighand2, CLONE_SIGHAND, true, false, false)
78901.106Skamil//CLONE_TEST(clone_sighand3, CLONE_SIGHAND, false, true, false)
78911.106Skamil//CLONE_TEST(clone_sighand4, CLONE_SIGHAND, true, true, false)
78921.106Skamil#endif
78931.106Skamil//CLONE_TEST(clone_sighand5, CLONE_SIGHAND, false, false, true)
78941.106Skamil#if defined(TWAIT_HAVE_PID)
78951.106Skamil//CLONE_TEST(clone_sighand6, CLONE_SIGHAND, true, false, true)
78961.106Skamil//CLONE_TEST(clone_sighand7, CLONE_SIGHAND, false, true, true)
78971.106Skamil//CLONE_TEST(clone_sighand8, CLONE_SIGHAND, true, true, true)
78981.106Skamil#endif
78991.106Skamil
79001.106SkamilCLONE_TEST(clone_vfork1, CLONE_VFORK, false, false, false)
79011.106Skamil#if defined(TWAIT_HAVE_PID)
79021.106SkamilCLONE_TEST(clone_vfork2, CLONE_VFORK, true, false, false)
79031.106SkamilCLONE_TEST(clone_vfork3, CLONE_VFORK, false, true, false)
79041.106SkamilCLONE_TEST(clone_vfork4, CLONE_VFORK, true, true, false)
79051.106Skamil#endif
79061.106SkamilCLONE_TEST(clone_vfork5, CLONE_VFORK, false, false, true)
79071.106Skamil#if defined(TWAIT_HAVE_PID)
79081.106SkamilCLONE_TEST(clone_vfork6, CLONE_VFORK, true, false, true)
79091.106SkamilCLONE_TEST(clone_vfork7, CLONE_VFORK, false, true, true)
79101.106SkamilCLONE_TEST(clone_vfork8, CLONE_VFORK, true, true, true)
79111.106Skamil#endif
79121.106Skamil
79131.106Skamil/// ----------------------------------------------------------------------------
79141.106Skamil
79151.106Skamil#if defined(TWAIT_HAVE_PID)
79161.103Skamilstatic void
79171.106Skamilclone_body2(int flags, bool masked, bool ignored)
79181.103Skamil{
79191.103Skamil	const int exitval = 5;
79201.103Skamil	const int exitval2 = 15;
79211.103Skamil	const int sigval = SIGSTOP;
79221.103Skamil	pid_t child, child2 = 0, wpid;
79231.103Skamil#if defined(TWAIT_HAVE_STATUS)
79241.103Skamil	int status;
79251.103Skamil#endif
79261.103Skamil	ptrace_state_t state;
79271.103Skamil	const int slen = sizeof(state);
79281.103Skamil	ptrace_event_t event;
79291.103Skamil	const int elen = sizeof(event);
79301.103Skamil	struct sigaction sa;
79311.103Skamil	struct ptrace_siginfo info;
79321.103Skamil	sigset_t intmask;
79331.103Skamil	struct kinfo_proc2 kp;
79341.103Skamil	size_t len = sizeof(kp);
79351.103Skamil
79361.103Skamil	int name[6];
79371.103Skamil	const size_t namelen = __arraycount(name);
79381.103Skamil	ki_sigset_t kp_sigmask;
79391.103Skamil	ki_sigset_t kp_sigignore;
79401.103Skamil
79411.103Skamil	const size_t stack_size = 1024 * 1024;
79421.103Skamil	void *stack, *stack_base;
79431.103Skamil
79441.103Skamil	stack = malloc(stack_size);
79451.103Skamil	ATF_REQUIRE(stack != NULL);
79461.103Skamil
79471.103Skamil#ifdef __MACHINE_STACK_GROWS_UP
79481.103Skamil	stack_base = stack;
79491.103Skamil#else
79501.103Skamil	stack_base = (char *)stack + stack_size;
79511.103Skamil#endif
79521.103Skamil
79531.103Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
79541.103Skamil	if (child == 0) {
79551.103Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
79561.103Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
79571.103Skamil
79581.103Skamil		if (masked) {
79591.103Skamil			sigemptyset(&intmask);
79601.103Skamil			sigaddset(&intmask, SIGTRAP);
79611.103Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
79621.103Skamil		}
79631.103Skamil
79641.103Skamil		if (ignored) {
79651.103Skamil			memset(&sa, 0, sizeof(sa));
79661.103Skamil			sa.sa_handler = SIG_IGN;
79671.103Skamil			sigemptyset(&sa.sa_mask);
79681.103Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
79691.103Skamil		}
79701.103Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
79711.103Skamil		FORKEE_ASSERT(raise(sigval) == 0);
79721.103Skamil
79731.103Skamil		DPRINTF("Before forking process PID=%d flags=%#x\n", getpid(),
79741.103Skamil		    flags);
79751.103Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
79761.103Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
79771.103Skamil
79781.103Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
79791.103Skamil		    child2);
79801.103Skamil
79811.103Skamil		// XXX WALLSIG?
79821.103Skamil		FORKEE_REQUIRE_SUCCESS
79831.103Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
79841.103Skamil
79851.103Skamil		forkee_status_exited(status, exitval2);
79861.103Skamil
79871.103Skamil		DPRINTF("Before exiting of the child process\n");
79881.103Skamil		_exit(exitval);
79891.103Skamil	}
79901.103Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
79911.103Skamil
79921.103Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
79931.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
79941.103Skamil
79951.103Skamil	validate_status_stopped(status, sigval);
79961.103Skamil
79971.103Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
79981.103Skamil	SYSCALL_REQUIRE(
79991.103Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
80001.103Skamil
80011.103Skamil	DPRINTF("Before checking siginfo_t\n");
80021.103Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
80031.103Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
80041.103Skamil
80051.103Skamil	name[0] = CTL_KERN,
80061.103Skamil	name[1] = KERN_PROC2,
80071.103Skamil	name[2] = KERN_PROC_PID;
80081.103Skamil	name[3] = child;
80091.103Skamil	name[4] = sizeof(kp);
80101.103Skamil	name[5] = 1;
80111.103Skamil
80121.103Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
80131.103Skamil
80141.103Skamil	if (masked)
80151.103Skamil		kp_sigmask = kp.p_sigmask;
80161.103Skamil
80171.103Skamil	if (ignored)
80181.103Skamil		kp_sigignore = kp.p_sigignore;
80191.103Skamil
80201.103Skamil	DPRINTF("Set PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE in "
80211.103Skamil	    "EVENT_MASK for the child %d\n", child);
80221.103Skamil	event.pe_set_event = PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE;
80231.103Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
80241.103Skamil
80251.103Skamil	DPRINTF("Before resuming the child process where it left off and "
80261.103Skamil	    "without signal to be sent\n");
80271.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
80281.103Skamil
80291.103Skamil	DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
80301.103Skamil	    child);
80311.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
80321.103Skamil	    child);
80331.103Skamil
80341.103Skamil	validate_status_stopped(status, SIGTRAP);
80351.103Skamil
80361.103Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
80371.103Skamil
80381.103Skamil	if (masked) {
80391.103Skamil		DPRINTF("kp_sigmask="
80401.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
80411.103Skamil		    PRIx32 "\n",
80421.103Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
80431.103Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
80441.103Skamil
80451.103Skamil		DPRINTF("kp.p_sigmask="
80461.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
80471.103Skamil		    PRIx32 "\n",
80481.103Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
80491.103Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
80501.103Skamil
80511.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
80521.103Skamil		    sizeof(kp_sigmask)));
80531.103Skamil	}
80541.103Skamil
80551.103Skamil	if (ignored) {
80561.103Skamil		DPRINTF("kp_sigignore="
80571.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
80581.103Skamil		    PRIx32 "\n",
80591.103Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
80601.103Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
80611.103Skamil
80621.103Skamil		DPRINTF("kp.p_sigignore="
80631.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
80641.103Skamil		    PRIx32 "\n",
80651.103Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
80661.103Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
80671.103Skamil
80681.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
80691.103Skamil		    sizeof(kp_sigignore)));
80701.103Skamil	}
80711.103Skamil
80721.103Skamil	SYSCALL_REQUIRE(
80731.103Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
80741.103Skamil	DPRINTF("state.pe_report_event=%#x pid=%d\n", state.pe_report_event,
80751.103Skamil	    child2);
80761.103Skamil	if (!(flags & CLONE_VFORK)) {
80771.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
80781.103Skamil		       PTRACE_FORK);
80791.103Skamil	} else {
80801.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
80811.103Skamil		       PTRACE_VFORK);
80821.103Skamil	}
80831.103Skamil
80841.103Skamil	child2 = state.pe_other_pid;
80851.103Skamil	DPRINTF("Reported ptrace event with forkee %d\n", child2);
80861.103Skamil
80871.103Skamil	DPRINTF("Before calling %s() for the forkee %d of the child "
80881.103Skamil	    "%d\n", TWAIT_FNAME, child2, child);
80891.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
80901.103Skamil	    child2);
80911.103Skamil
80921.103Skamil	validate_status_stopped(status, SIGTRAP);
80931.103Skamil
80941.103Skamil	name[3] = child2;
80951.103Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
80961.103Skamil
80971.103Skamil	if (masked) {
80981.103Skamil		DPRINTF("kp_sigmask="
80991.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
81001.103Skamil		    PRIx32 "\n",
81011.103Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
81021.103Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
81031.103Skamil
81041.103Skamil		DPRINTF("kp.p_sigmask="
81051.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
81061.103Skamil		    PRIx32 "\n",
81071.103Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
81081.103Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
81091.103Skamil
81101.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
81111.103Skamil		    sizeof(kp_sigmask)));
81121.103Skamil	}
81131.103Skamil
81141.103Skamil	if (ignored) {
81151.103Skamil		DPRINTF("kp_sigignore="
81161.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
81171.103Skamil		    PRIx32 "\n",
81181.103Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
81191.103Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
81201.103Skamil
81211.103Skamil		DPRINTF("kp.p_sigignore="
81221.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
81231.103Skamil		    PRIx32 "\n",
81241.103Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
81251.103Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
81261.103Skamil
81271.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
81281.103Skamil		    sizeof(kp_sigignore)));
81291.103Skamil	}
81301.103Skamil
81311.103Skamil	SYSCALL_REQUIRE(
81321.103Skamil	    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
81331.103Skamil	if (!(flags & CLONE_VFORK)) {
81341.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
81351.103Skamil		       PTRACE_FORK);
81361.103Skamil	} else {
81371.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
81381.103Skamil		       PTRACE_VFORK);
81391.103Skamil	}
81401.103Skamil
81411.103Skamil	ATF_REQUIRE_EQ(state.pe_other_pid, child);
81421.103Skamil
81431.103Skamil	DPRINTF("Before resuming the forkee process where it left off "
81441.103Skamil	    "and without signal to be sent\n");
81451.103Skamil	SYSCALL_REQUIRE(
81461.103Skamil	    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
81471.103Skamil
81481.103Skamil	DPRINTF("Before resuming the child process where it left off "
81491.103Skamil	    "and without signal to be sent\n");
81501.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
81511.103Skamil
81521.103Skamil	if (flags & CLONE_VFORK) {
81531.103Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
81541.103Skamil		    child);
81551.103Skamil		TWAIT_REQUIRE_SUCCESS(
81561.103Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
81571.103Skamil
81581.103Skamil		validate_status_stopped(status, SIGTRAP);
81591.103Skamil
81601.103Skamil		name[3] = child;
81611.103Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
81621.103Skamil
81631.103Skamil		/*
81641.103Skamil		 * SIGCHLD is now pending in the signal queue and
81651.103Skamil		 * the kernel presents it to userland as a masked signal.
81661.103Skamil		 */
81671.103Skamil		sigdelset((sigset_t *)&kp.p_sigmask, SIGCHLD);
81681.103Skamil
81691.103Skamil		if (masked) {
81701.103Skamil			DPRINTF("kp_sigmask="
81711.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
81721.103Skamil			    PRIx32 "\n",
81731.103Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
81741.103Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
81751.103Skamil
81761.103Skamil			DPRINTF("kp.p_sigmask="
81771.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
81781.103Skamil			    PRIx32 "\n",
81791.103Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
81801.103Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
81811.103Skamil
81821.103Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
81831.103Skamil			    sizeof(kp_sigmask)));
81841.103Skamil		}
81851.103Skamil
81861.103Skamil		if (ignored) {
81871.103Skamil			DPRINTF("kp_sigignore="
81881.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
81891.103Skamil			    PRIx32 "\n",
81901.103Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
81911.103Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
81921.103Skamil
81931.103Skamil			DPRINTF("kp.p_sigignore="
81941.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
81951.103Skamil			    PRIx32 "\n",
81961.103Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
81971.103Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
81981.103Skamil
81991.103Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
82001.103Skamil			    sizeof(kp_sigignore)));
82011.103Skamil		}
82021.103Skamil
82031.103Skamil		SYSCALL_REQUIRE(
82041.103Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
82051.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
82061.103Skamil
82071.103Skamil		child2 = state.pe_other_pid;
82081.103Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
82091.103Skamil		    child2);
82101.103Skamil
82111.103Skamil		DPRINTF("Before resuming the child process where it left off "
82121.103Skamil		    "and without signal to be sent\n");
82131.103Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
82141.103Skamil	}
82151.103Skamil
82161.103Skamil	DPRINTF("Before calling %s() for the forkee - expected exited"
82171.103Skamil	    "\n", TWAIT_FNAME);
82181.103Skamil	TWAIT_REQUIRE_SUCCESS(
82191.103Skamil	    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
82201.103Skamil
82211.103Skamil	validate_status_exited(status, exitval2);
82221.103Skamil
82231.103Skamil	DPRINTF("Before calling %s() for the forkee - expected no "
82241.103Skamil	    "process\n", TWAIT_FNAME);
82251.103Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
82261.103Skamil	    wpid = TWAIT_GENERIC(child2, &status, 0));
82271.103Skamil
82281.103Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
82291.103Skamil	    "SIGCHLD\n", TWAIT_FNAME);
82301.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
82311.103Skamil
82321.103Skamil	validate_status_stopped(status, SIGCHLD);
82331.103Skamil
82341.103Skamil	DPRINTF("Before resuming the child process where it left off and "
82351.103Skamil	    "without signal to be sent\n");
82361.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
82371.103Skamil
82381.103Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
82391.103Skamil	    TWAIT_FNAME);
82401.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
82411.103Skamil
82421.103Skamil	validate_status_exited(status, exitval);
82431.103Skamil
82441.103Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
82451.103Skamil	    TWAIT_FNAME);
82461.103Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
82471.103Skamil}
82481.103Skamil
82491.106Skamil#define CLONE_TEST2(name,flags,masked,ignored)				\
82501.103SkamilATF_TC(name);								\
82511.103SkamilATF_TC_HEAD(name, tc)							\
82521.103Skamil{									\
82531.103Skamil	atf_tc_set_md_var(tc, "descr", "Verify that clone(%s) is caught"\
82541.103Skamil	    " regardless of signal %s%s", 				\
82551.103Skamil	    #flags, masked ? "masked" : "", ignored ? "ignored" : "");	\
82561.103Skamil}									\
82571.103Skamil									\
82581.103SkamilATF_TC_BODY(name, tc)							\
82591.103Skamil{									\
82601.103Skamil									\
82611.106Skamil	clone_body2(flags, masked, ignored);				\
82621.103Skamil}
82631.103Skamil
82641.106SkamilCLONE_TEST2(clone_signalignored, 0, true, false)
82651.106SkamilCLONE_TEST2(clone_signalmasked, 0, false, true)
82661.106SkamilCLONE_TEST2(clone_vm_signalignored, CLONE_VM, true, false)
82671.106SkamilCLONE_TEST2(clone_vm_signalmasked, CLONE_VM, false, true)
82681.106SkamilCLONE_TEST2(clone_fs_signalignored, CLONE_FS, true, false)
82691.106SkamilCLONE_TEST2(clone_fs_signalmasked, CLONE_FS, false, true)
82701.106SkamilCLONE_TEST2(clone_files_signalignored, CLONE_FILES, true, false)
82711.106SkamilCLONE_TEST2(clone_files_signalmasked, CLONE_FILES, false, true)
82721.106Skamil//CLONE_TEST2(clone_sighand_signalignored, CLONE_SIGHAND, true, false) // XXX
82731.106Skamil//CLONE_TEST2(clone_sighand_signalmasked, CLONE_SIGHAND, false, true)  // XXX
82741.106SkamilCLONE_TEST2(clone_vfork_signalignored, CLONE_VFORK, true, false)
82751.106SkamilCLONE_TEST2(clone_vfork_signalmasked, CLONE_VFORK, false, true)
82761.103Skamil#endif
82771.103Skamil
82781.103Skamil/// ----------------------------------------------------------------------------
82791.103Skamil
82801.107Skamil#if defined(TWAIT_HAVE_PID)
82811.107Skamilstatic void
82821.107Skamiltraceme_vfork_clone_body(int flags)
82831.107Skamil{
82841.107Skamil	const int exitval = 5;
82851.107Skamil	const int exitval2 = 15;
82861.107Skamil	pid_t child, child2 = 0, wpid;
82871.107Skamil#if defined(TWAIT_HAVE_STATUS)
82881.107Skamil	int status;
82891.107Skamil#endif
82901.107Skamil
82911.107Skamil	const size_t stack_size = 1024 * 1024;
82921.107Skamil	void *stack, *stack_base;
82931.107Skamil
82941.107Skamil	stack = malloc(stack_size);
82951.107Skamil	ATF_REQUIRE(stack != NULL);
82961.107Skamil
82971.107Skamil#ifdef __MACHINE_STACK_GROWS_UP
82981.107Skamil	stack_base = stack;
82991.107Skamil#else
83001.107Skamil	stack_base = (char *)stack + stack_size;
83011.107Skamil#endif
83021.107Skamil
83031.107Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
83041.107Skamil	if (child == 0) {
83051.107Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
83061.107Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
83071.107Skamil
83081.107Skamil		DPRINTF("Before forking process PID=%d flags=%#x\n", getpid(),
83091.107Skamil		    flags);
83101.107Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
83111.107Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
83121.107Skamil
83131.107Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
83141.107Skamil		    child2);
83151.107Skamil
83161.107Skamil		// XXX WALLSIG?
83171.107Skamil		FORKEE_REQUIRE_SUCCESS
83181.107Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
83191.107Skamil
83201.107Skamil		forkee_status_exited(status, exitval2);
83211.107Skamil
83221.107Skamil		DPRINTF("Before exiting of the child process\n");
83231.107Skamil		_exit(exitval);
83241.107Skamil	}
83251.107Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
83261.107Skamil
83271.107Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
83281.107Skamil	    TWAIT_FNAME);
83291.107Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
83301.107Skamil
83311.107Skamil	validate_status_exited(status, exitval);
83321.107Skamil
83331.107Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
83341.107Skamil	    TWAIT_FNAME);
83351.107Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
83361.107Skamil}
83371.107Skamil
83381.107Skamil#define TRACEME_VFORK_CLONE_TEST(name,flags)				\
83391.107SkamilATF_TC(name);								\
83401.107SkamilATF_TC_HEAD(name, tc)							\
83411.107Skamil{									\
83421.107Skamil	atf_tc_set_md_var(tc, "descr", "Verify that clone(%s) is "	\
83431.107Skamil	    "handled correctly with vfork(2)ed tracer", 		\
83441.107Skamil	    #flags);							\
83451.107Skamil}									\
83461.107Skamil									\
83471.107SkamilATF_TC_BODY(name, tc)							\
83481.107Skamil{									\
83491.107Skamil									\
83501.107Skamil	traceme_vfork_clone_body(flags);				\
83511.107Skamil}
83521.107Skamil
83531.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone, 0)
83541.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_vm, CLONE_VM)
83551.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_fs, CLONE_FS)
83561.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_files, CLONE_FILES)
83571.107Skamil//TRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_sighand, CLONE_SIGHAND)  // XXX
83581.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_vfork, CLONE_VFORK)
83591.107Skamil#endif
83601.107Skamil
83611.107Skamil/// ----------------------------------------------------------------------------
83621.107Skamil
83631.122Skamilstatic void
83641.122Skamiluser_va0_disable(int operation)
83651.122Skamil{
83661.122Skamil	pid_t child, wpid;
83671.122Skamil#if defined(TWAIT_HAVE_STATUS)
83681.122Skamil	int status;
83691.122Skamil#endif
83701.122Skamil	const int sigval = SIGSTOP;
83711.122Skamil	int rv;
83721.122Skamil
83731.122Skamil	struct ptrace_siginfo info;
83741.122Skamil
83751.122Skamil	if (get_user_va0_disable() == 0)
83761.122Skamil		atf_tc_skip("vm.user_va0_disable is set to 0");
83771.122Skamil
83781.122Skamil	memset(&info, 0, sizeof(info));
83791.122Skamil
83801.122Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
83811.122Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
83821.122Skamil	if (child == 0) {
83831.122Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
83841.122Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
83851.122Skamil
83861.122Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
83871.122Skamil		FORKEE_ASSERT(raise(sigval) == 0);
83881.122Skamil
83891.122Skamil		/* NOTREACHED */
83901.122Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
83911.122Skamil		__unreachable();
83921.122Skamil	}
83931.122Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
83941.122Skamil
83951.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
83961.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
83971.122Skamil
83981.122Skamil	validate_status_stopped(status, sigval);
83991.122Skamil
84001.122Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
84011.122Skamil		"child\n");
84021.122Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
84031.122Skamil		sizeof(info)) != -1);
84041.122Skamil
84051.122Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
84061.122Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
84071.122Skamil		"si_errno=%#x\n",
84081.122Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
84091.122Skamil		info.psi_siginfo.si_errno);
84101.122Skamil
84111.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
84121.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
84131.122Skamil
84141.122Skamil	DPRINTF("Before resuming the child process in PC=0x0 "
84151.122Skamil	    "and without signal to be sent\n");
84161.122Skamil	errno = 0;
84171.122Skamil	rv = ptrace(operation, child, (void *)0, 0);
84181.122Skamil	ATF_REQUIRE_EQ(errno, EINVAL);
84191.122Skamil	ATF_REQUIRE_EQ(rv, -1);
84201.122Skamil
84211.122Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
84221.122Skamil
84231.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
84241.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
84251.122Skamil	validate_status_signaled(status, SIGKILL, 0);
84261.122Skamil
84271.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
84281.122Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
84291.122Skamil}
84301.122Skamil
84311.122Skamil#define USER_VA0_DISABLE(test, operation)				\
84321.122SkamilATF_TC(test);								\
84331.122SkamilATF_TC_HEAD(test, tc)							\
84341.122Skamil{									\
84351.122Skamil	atf_tc_set_md_var(tc, "descr",					\
84361.122Skamil	    "Verify behavior of " #operation " with PC set to 0x0");	\
84371.122Skamil}									\
84381.122Skamil									\
84391.122SkamilATF_TC_BODY(test, tc)							\
84401.122Skamil{									\
84411.122Skamil									\
84421.122Skamil	user_va0_disable(operation);					\
84431.122Skamil}
84441.122Skamil
84451.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_continue, PT_CONTINUE)
84461.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_syscall, PT_SYSCALL)
84471.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_detach, PT_DETACH)
84481.122Skamil
84491.122Skamil/// ----------------------------------------------------------------------------
84501.122Skamil
84511.130Smgorny/*
84521.130Smgorny * Parse the core file and find the requested note.  If the reading or parsing
84531.130Smgorny * fails, the test is failed.  If the note is found, it is read onto buf, up to
84541.130Smgorny * buf_len.  The actual length of the note is returned (which can be greater
84551.130Smgorny * than buf_len, indicating that it has been truncated).  If the note is not
84561.130Smgorny * found, -1 is returned.
84571.130Smgorny */
84581.130Smgornystatic ssize_t core_find_note(const char *core_path,
84591.130Smgorny    const char *note_name, uint64_t note_type, void *buf, size_t buf_len)
84601.130Smgorny{
84611.130Smgorny	int core_fd;
84621.130Smgorny	Elf *core_elf;
84631.130Smgorny	size_t core_numhdr, i;
84641.130Smgorny	ssize_t ret = -1;
84651.130Smgorny	/* note: we assume note name will be null-terminated */
84661.130Smgorny	size_t name_len = strlen(note_name) + 1;
84671.130Smgorny
84681.130Smgorny	SYSCALL_REQUIRE((core_fd = open(core_path, O_RDONLY)) != -1);
84691.130Smgorny	SYSCALL_REQUIRE(elf_version(EV_CURRENT) != EV_NONE);
84701.130Smgorny	SYSCALL_REQUIRE((core_elf = elf_begin(core_fd, ELF_C_READ, NULL)));
84711.130Smgorny
84721.130Smgorny	SYSCALL_REQUIRE(elf_getphnum(core_elf, &core_numhdr) != 0);
84731.130Smgorny	for (i = 0; i < core_numhdr && ret == -1; i++) {
84741.130Smgorny		GElf_Phdr core_hdr;
84751.130Smgorny		size_t offset;
84761.130Smgorny		SYSCALL_REQUIRE(gelf_getphdr(core_elf, i, &core_hdr));
84771.130Smgorny		if (core_hdr.p_type != PT_NOTE)
84781.130Smgorny		    continue;
84791.130Smgorny
84801.130Smgorny		for (offset = core_hdr.p_offset;
84811.130Smgorny		    offset < core_hdr.p_offset + core_hdr.p_filesz;) {
84821.130Smgorny			Elf64_Nhdr note_hdr;
84831.130Smgorny			char name_buf[64];
84841.130Smgorny
84851.130Smgorny			switch (gelf_getclass(core_elf)) {
84861.130Smgorny			case ELFCLASS64:
84871.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &note_hdr,
84881.130Smgorny				    sizeof(note_hdr), offset)
84891.130Smgorny				    == sizeof(note_hdr));
84901.130Smgorny				offset += sizeof(note_hdr);
84911.130Smgorny				break;
84921.130Smgorny			case ELFCLASS32:
84931.130Smgorny				{
84941.130Smgorny				Elf32_Nhdr tmp_hdr;
84951.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &tmp_hdr,
84961.130Smgorny				    sizeof(tmp_hdr), offset)
84971.130Smgorny				    == sizeof(tmp_hdr));
84981.130Smgorny				offset += sizeof(tmp_hdr);
84991.130Smgorny				note_hdr.n_namesz = tmp_hdr.n_namesz;
85001.130Smgorny				note_hdr.n_descsz = tmp_hdr.n_descsz;
85011.130Smgorny				note_hdr.n_type = tmp_hdr.n_type;
85021.130Smgorny				}
85031.130Smgorny				break;
85041.130Smgorny			}
85051.130Smgorny
85061.130Smgorny			/* indicates end of notes */
85071.130Smgorny			if (note_hdr.n_namesz == 0 || note_hdr.n_descsz == 0)
85081.130Smgorny				break;
85091.130Smgorny			if (note_hdr.n_namesz == name_len &&
85101.130Smgorny			    note_hdr.n_namesz <= sizeof(name_buf)) {
85111.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, name_buf,
85121.130Smgorny				    note_hdr.n_namesz, offset)
85131.131Skamil				    == (ssize_t)(size_t)note_hdr.n_namesz);
85141.130Smgorny
85151.130Smgorny				if (!strncmp(note_name, name_buf, name_len) &&
85161.130Smgorny				    note_hdr.n_type == note_type)
85171.130Smgorny					ret = note_hdr.n_descsz;
85181.130Smgorny			}
85191.130Smgorny
85201.130Smgorny			offset += note_hdr.n_namesz;
85211.130Smgorny			/* fix to alignment */
85221.146Smgorny			offset = roundup(offset, core_hdr.p_align);
85231.130Smgorny
85241.130Smgorny			/* if name & type matched above */
85251.130Smgorny			if (ret != -1) {
85261.130Smgorny				ssize_t read_len = MIN(buf_len,
85271.130Smgorny				    note_hdr.n_descsz);
85281.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, buf,
85291.130Smgorny				    read_len, offset) == read_len);
85301.130Smgorny				break;
85311.130Smgorny			}
85321.130Smgorny
85331.130Smgorny			offset += note_hdr.n_descsz;
85341.146Smgorny			/* fix to alignment */
85351.146Smgorny			offset = roundup(offset, core_hdr.p_align);
85361.130Smgorny		}
85371.130Smgorny	}
85381.130Smgorny
85391.130Smgorny	elf_end(core_elf);
85401.130Smgorny	close(core_fd);
85411.130Smgorny
85421.130Smgorny	return ret;
85431.130Smgorny}
85441.130Smgorny
85451.130SmgornyATF_TC(core_dump_procinfo);
85461.130SmgornyATF_TC_HEAD(core_dump_procinfo, tc)
85471.130Smgorny{
85481.130Smgorny	atf_tc_set_md_var(tc, "descr",
85491.130Smgorny		"Trigger a core dump and verify its contents.");
85501.130Smgorny}
85511.130Smgorny
85521.130SmgornyATF_TC_BODY(core_dump_procinfo, tc)
85531.130Smgorny{
85541.130Smgorny	const int exitval = 5;
85551.130Smgorny	pid_t child, wpid;
85561.130Smgorny#if defined(TWAIT_HAVE_STATUS)
85571.130Smgorny	const int sigval = SIGTRAP;
85581.130Smgorny	int status;
85591.130Smgorny#endif
85601.130Smgorny	char core_path[] = "/tmp/core.XXXXXX";
85611.130Smgorny	int core_fd;
85621.130Smgorny	struct netbsd_elfcore_procinfo procinfo;
85631.130Smgorny
85641.130Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
85651.130Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
85661.130Smgorny	if (child == 0) {
85671.130Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
85681.130Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
85691.130Smgorny
85701.130Smgorny		DPRINTF("Before triggering SIGTRAP\n");
85711.130Smgorny		trigger_trap();
85721.130Smgorny
85731.130Smgorny		DPRINTF("Before exiting of the child process\n");
85741.130Smgorny		_exit(exitval);
85751.130Smgorny	}
85761.130Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
85771.130Smgorny
85781.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
85791.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
85801.130Smgorny
85811.130Smgorny	validate_status_stopped(status, sigval);
85821.130Smgorny
85831.130Smgorny	SYSCALL_REQUIRE((core_fd = mkstemp(core_path)) != -1);
85841.130Smgorny	close(core_fd);
85851.130Smgorny
85861.130Smgorny	DPRINTF("Call DUMPCORE for the child process\n");
85871.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_DUMPCORE, child, core_path, strlen(core_path))
85881.130Smgorny	    != -1);
85891.130Smgorny
85901.130Smgorny	DPRINTF("Read core file\n");
85911.130Smgorny	ATF_REQUIRE_EQ(core_find_note(core_path, "NetBSD-CORE",
85921.130Smgorny	    ELF_NOTE_NETBSD_CORE_PROCINFO, &procinfo, sizeof(procinfo)),
85931.130Smgorny	    sizeof(procinfo));
85941.130Smgorny
85951.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_version, 1);
85961.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_cpisize, sizeof(procinfo));
85971.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_signo, SIGTRAP);
85981.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pid, child);
85991.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ppid, getpid());
86001.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pgrp, getpgid(child));
86011.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_sid, getsid(child));
86021.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ruid, getuid());
86031.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_euid, geteuid());
86041.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_rgid, getgid());
86051.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_egid, getegid());
86061.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_nlwps, 1);
86071.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_siglwp, 1);
86081.130Smgorny
86091.130Smgorny	unlink(core_path);
86101.130Smgorny
86111.130Smgorny	DPRINTF("Before resuming the child process where it left off and "
86121.130Smgorny	    "without signal to be sent\n");
86131.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
86141.130Smgorny
86151.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
86161.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
86171.130Smgorny
86181.130Smgorny	validate_status_exited(status, exitval);
86191.130Smgorny
86201.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
86211.130Smgorny	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
86221.130Smgorny}
86231.130Smgorny
86241.130Smgorny/// ----------------------------------------------------------------------------
86251.130Smgorny
86261.138Smgorny#if defined(TWAIT_HAVE_STATUS)
86271.138Smgorny
86281.160Smgorny#define THREAD_CONCURRENT_BREAKPOINT_NUM 50
86291.156Smgorny#define THREAD_CONCURRENT_SIGNALS_NUM 50
86301.161Smgorny#define THREAD_CONCURRENT_WATCHPOINT_NUM 50
86311.138Smgorny
86321.138Smgorny/* List of signals to use for the test */
86331.138Smgornyconst int thread_concurrent_signals_list[] = {
86341.138Smgorny	SIGIO,
86351.138Smgorny	SIGXCPU,
86361.138Smgorny	SIGXFSZ,
86371.138Smgorny	SIGVTALRM,
86381.138Smgorny	SIGPROF,
86391.138Smgorny	SIGWINCH,
86401.138Smgorny	SIGINFO,
86411.138Smgorny	SIGUSR1,
86421.138Smgorny	SIGUSR2
86431.138Smgorny};
86441.138Smgorny
86451.157Smgornyenum thread_concurrent_signal_handling {
86461.157Smgorny	/* the signal is discarded by debugger */
86471.157Smgorny	TCSH_DISCARD,
86481.157Smgorny	/* the handler is set to SIG_IGN */
86491.157Smgorny	TCSH_SIG_IGN,
86501.157Smgorny	/* an actual handler is used */
86511.157Smgorny	TCSH_HANDLER
86521.157Smgorny};
86531.157Smgorny
86541.156Smgornystatic pthread_barrier_t thread_concurrent_barrier;
86551.158Smgornystatic pthread_key_t thread_concurrent_key;
86561.161Smgornystatic uint32_t thread_concurrent_watchpoint_var = 0;
86571.138Smgorny
86581.160Smgornystatic void *
86591.160Smgornythread_concurrent_breakpoint_thread(void *arg)
86601.160Smgorny{
86611.160Smgorny	static volatile int watchme = 1;
86621.160Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
86631.160Smgorny	DPRINTF("Before entering breakpoint func from LWP %d\n", _lwp_self());
86641.160Smgorny	check_happy(watchme);
86651.160Smgorny	return NULL;
86661.160Smgorny}
86671.160Smgorny
86681.157Smgornystatic void
86691.157Smgornythread_concurrent_sig_handler(int sig)
86701.157Smgorny{
86711.158Smgorny	void *tls_val = pthread_getspecific(thread_concurrent_key);
86721.158Smgorny	DPRINTF("Before increment, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
86731.158Smgorny	FORKEE_ASSERT(pthread_setspecific(thread_concurrent_key,
86741.158Smgorny	    (void*)((uintptr_t)tls_val + 1)) == 0);
86751.157Smgorny}
86761.157Smgorny
86771.138Smgornystatic void *
86781.138Smgornythread_concurrent_signals_thread(void *arg)
86791.138Smgorny{
86801.138Smgorny	int sigval = thread_concurrent_signals_list[
86811.138Smgorny	    _lwp_self() % __arraycount(thread_concurrent_signals_list)];
86821.158Smgorny	enum thread_concurrent_signal_handling *signal_handle = arg;
86831.158Smgorny	void *tls_val;
86841.158Smgorny
86851.156Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
86861.138Smgorny	DPRINTF("Before raising %s from LWP %d\n", strsignal(sigval),
86871.138Smgorny		_lwp_self());
86881.138Smgorny	pthread_kill(pthread_self(), sigval);
86891.158Smgorny	if (*signal_handle == TCSH_HANDLER) {
86901.158Smgorny	    tls_val = pthread_getspecific(thread_concurrent_key);
86911.158Smgorny	    DPRINTF("After raising, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
86921.158Smgorny	    FORKEE_ASSERT(tls_val == (void*)1);
86931.158Smgorny	}
86941.138Smgorny	return NULL;
86951.138Smgorny}
86961.138Smgorny
86971.161Smgornystatic void *
86981.161Smgornythread_concurrent_watchpoint_thread(void *arg)
86991.161Smgorny{
87001.161Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
87011.161Smgorny	DPRINTF("Before modifying var from LWP %d\n", _lwp_self());
87021.161Smgorny	thread_concurrent_watchpoint_var = 1;
87031.161Smgorny	return NULL;
87041.161Smgorny}
87051.161Smgorny
87061.160Smgorny#if defined(__i386__) || defined(__x86_64__)
87071.160Smgornyenum thread_concurrent_sigtrap_event {
87081.160Smgorny	TCSE_UNKNOWN,
87091.161Smgorny	TCSE_BREAKPOINT,
87101.161Smgorny	TCSE_WATCHPOINT
87111.160Smgorny};
87121.160Smgorny
87131.160Smgornystatic void
87141.160Smgornythread_concurrent_lwp_setup(pid_t child, lwpid_t lwpid);
87151.160Smgornystatic enum thread_concurrent_sigtrap_event
87161.160Smgornythread_concurrent_handle_sigtrap(pid_t child, ptrace_siginfo_t *info);
87171.160Smgorny#endif
87181.160Smgorny
87191.156Smgornystatic void
87201.157Smgornythread_concurrent_test(enum thread_concurrent_signal_handling signal_handle,
87211.161Smgorny    int breakpoint_threads, int signal_threads, int watchpoint_threads)
87221.138Smgorny{
87231.138Smgorny	const int exitval = 5;
87241.138Smgorny	const int sigval = SIGSTOP;
87251.138Smgorny	pid_t child, wpid;
87261.138Smgorny	int status;
87271.141Skamil	struct lwp_event_count signal_counts[THREAD_CONCURRENT_SIGNALS_NUM]
87281.141Skamil	    = {{0, 0}};
87291.160Smgorny	struct lwp_event_count bp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
87301.160Smgorny	    = {{0, 0}};
87311.161Smgorny	struct lwp_event_count wp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
87321.161Smgorny	    = {{0, 0}};
87331.159Smgorny	ptrace_event_t event;
87341.156Smgorny	int i;
87351.156Smgorny
87361.164Skamil#if defined(HAVE_DBREGS)
87371.164Skamil	if (!can_we_set_dbregs()) {
87381.164Skamil		atf_tc_skip("Either run this test as root or set sysctl(3) "
87391.164Skamil		            "security.models.extensions.user_set_dbregs to 1");
87401.164Skamil        }
87411.164Skamil#endif
87421.164Skamil
87431.164Skamil	atf_tc_skip("PR kern/54960");
87441.157Smgorny
87451.156Smgorny	/* Protect against out-of-bounds array access. */
87461.160Smgorny	ATF_REQUIRE(breakpoint_threads <= THREAD_CONCURRENT_BREAKPOINT_NUM);
87471.156Smgorny	ATF_REQUIRE(signal_threads <= THREAD_CONCURRENT_SIGNALS_NUM);
87481.161Smgorny	ATF_REQUIRE(watchpoint_threads <= THREAD_CONCURRENT_WATCHPOINT_NUM);
87491.138Smgorny
87501.138Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
87511.138Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
87521.138Smgorny	if (child == 0) {
87531.160Smgorny		pthread_t bp_threads[THREAD_CONCURRENT_BREAKPOINT_NUM];
87541.156Smgorny		pthread_t sig_threads[THREAD_CONCURRENT_SIGNALS_NUM];
87551.161Smgorny		pthread_t wp_threads[THREAD_CONCURRENT_WATCHPOINT_NUM];
87561.138Smgorny
87571.138Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
87581.138Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
87591.138Smgorny
87601.138Smgorny		DPRINTF("Before raising %s from child\n", strsignal(sigval));
87611.138Smgorny		FORKEE_ASSERT(raise(sigval) == 0);
87621.138Smgorny
87631.157Smgorny		if (signal_handle != TCSH_DISCARD) {
87641.157Smgorny			struct sigaction sa;
87651.157Smgorny			unsigned int j;
87661.157Smgorny
87671.157Smgorny			memset(&sa, 0, sizeof(sa));
87681.157Smgorny			if (signal_handle == TCSH_SIG_IGN)
87691.157Smgorny				sa.sa_handler = SIG_IGN;
87701.157Smgorny			else
87711.157Smgorny				sa.sa_handler = thread_concurrent_sig_handler;
87721.157Smgorny			sigemptyset(&sa.sa_mask);
87731.157Smgorny
87741.157Smgorny			for (j = 0;
87751.157Smgorny			    j < __arraycount(thread_concurrent_signals_list);
87761.157Smgorny			    j++)
87771.157Smgorny				FORKEE_ASSERT(sigaction(
87781.157Smgorny				    thread_concurrent_signals_list[j], &sa, NULL)
87791.157Smgorny				    != -1);
87801.157Smgorny		}
87811.157Smgorny
87821.138Smgorny		DPRINTF("Before starting threads from the child\n");
87831.138Smgorny		FORKEE_ASSERT(pthread_barrier_init(
87841.156Smgorny		    &thread_concurrent_barrier, NULL,
87851.161Smgorny		    breakpoint_threads + signal_threads + watchpoint_threads)
87861.161Smgorny		    == 0);
87871.158Smgorny		FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL)
87881.158Smgorny		    == 0);
87891.138Smgorny
87901.156Smgorny		for (i = 0; i < signal_threads; i++) {
87911.156Smgorny			FORKEE_ASSERT(pthread_create(&sig_threads[i], NULL,
87921.158Smgorny			    thread_concurrent_signals_thread,
87931.158Smgorny			    &signal_handle) == 0);
87941.138Smgorny		}
87951.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
87961.160Smgorny			FORKEE_ASSERT(pthread_create(&bp_threads[i], NULL,
87971.160Smgorny			    thread_concurrent_breakpoint_thread, NULL) == 0);
87981.160Smgorny		}
87991.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
88001.161Smgorny			FORKEE_ASSERT(pthread_create(&wp_threads[i], NULL,
88011.161Smgorny			    thread_concurrent_watchpoint_thread, NULL) == 0);
88021.161Smgorny		}
88031.138Smgorny
88041.138Smgorny		DPRINTF("Before joining threads from the child\n");
88051.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
88061.161Smgorny			FORKEE_ASSERT(pthread_join(wp_threads[i], NULL) == 0);
88071.161Smgorny		}
88081.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
88091.160Smgorny			FORKEE_ASSERT(pthread_join(bp_threads[i], NULL) == 0);
88101.160Smgorny		}
88111.156Smgorny		for (i = 0; i < signal_threads; i++) {
88121.156Smgorny			FORKEE_ASSERT(pthread_join(sig_threads[i], NULL) == 0);
88131.138Smgorny		}
88141.138Smgorny
88151.158Smgorny		FORKEE_ASSERT(pthread_key_delete(thread_concurrent_key) == 0);
88161.138Smgorny		FORKEE_ASSERT(pthread_barrier_destroy(
88171.156Smgorny		    &thread_concurrent_barrier) == 0);
88181.138Smgorny
88191.138Smgorny		DPRINTF("Before exiting of the child process\n");
88201.138Smgorny		_exit(exitval);
88211.138Smgorny	}
88221.138Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
88231.138Smgorny
88241.138Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
88251.138Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
88261.138Smgorny
88271.138Smgorny	validate_status_stopped(status, sigval);
88281.138Smgorny
88291.159Smgorny	DPRINTF("Set LWP event mask for the child process\n");
88301.159Smgorny	memset(&event, 0, sizeof(event));
88311.159Smgorny	event.pe_set_event |= PTRACE_LWP_CREATE;
88321.159Smgorny	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, sizeof(event))
88331.159Smgorny	    != -1);
88341.159Smgorny
88351.138Smgorny	DPRINTF("Before resuming the child process where it left off\n");
88361.138Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
88371.138Smgorny
88381.138Smgorny	DPRINTF("Before entering signal collection loop\n");
88391.138Smgorny	while (1) {
88401.138Smgorny		ptrace_siginfo_t info;
88411.138Smgorny
88421.138Smgorny		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
88431.138Smgorny		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
88441.138Smgorny		    child);
88451.138Smgorny		if (WIFEXITED(status))
88461.138Smgorny			break;
88471.138Smgorny		/* Note: we use validate_status_stopped() to get nice error
88481.138Smgorny		 * message.  Signal is irrelevant since it won't be reached.
88491.138Smgorny		 */
88501.138Smgorny		else if (!WIFSTOPPED(status))
88511.138Smgorny			validate_status_stopped(status, 0);
88521.138Smgorny
88531.138Smgorny		DPRINTF("Before calling PT_GET_SIGINFO\n");
88541.138Smgorny		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
88551.138Smgorny		    sizeof(info)) != -1);
88561.138Smgorny
88571.138Smgorny		DPRINTF("Received signal %d from LWP %d (wait: %d)\n",
88581.138Smgorny		    info.psi_siginfo.si_signo, info.psi_lwpid,
88591.138Smgorny		    WSTOPSIG(status));
88601.138Smgorny
88611.159Smgorny		ATF_CHECK_EQ_MSG(info.psi_siginfo.si_signo, WSTOPSIG(status),
88621.159Smgorny		    "lwp=%d, WSTOPSIG=%d, psi_siginfo=%d", info.psi_lwpid,
88631.159Smgorny		    WSTOPSIG(status), info.psi_siginfo.si_signo);
88641.159Smgorny
88651.159Smgorny		if (WSTOPSIG(status) != SIGTRAP) {
88661.159Smgorny			int expected_sig =
88671.159Smgorny			    thread_concurrent_signals_list[info.psi_lwpid %
88681.159Smgorny			    __arraycount(thread_concurrent_signals_list)];
88691.159Smgorny			ATF_CHECK_EQ_MSG(WSTOPSIG(status), expected_sig,
88701.159Smgorny				"lwp=%d, expected %d, got %d", info.psi_lwpid,
88711.159Smgorny				expected_sig, WSTOPSIG(status));
88721.138Smgorny
88731.159Smgorny			*FIND_EVENT_COUNT(signal_counts, info.psi_lwpid) += 1;
88741.160Smgorny		} else if (info.psi_siginfo.si_code == TRAP_LWP) {
88751.160Smgorny#if defined(__i386__) || defined(__x86_64__)
88761.160Smgorny			thread_concurrent_lwp_setup(child, info.psi_lwpid);
88771.160Smgorny#endif
88781.159Smgorny		} else {
88791.160Smgorny#if defined(__i386__) || defined(__x86_64__)
88801.160Smgorny			switch (thread_concurrent_handle_sigtrap(child, &info)) {
88811.160Smgorny				case TCSE_UNKNOWN:
88821.160Smgorny					/* already reported inside the function */
88831.160Smgorny					break;
88841.160Smgorny				case TCSE_BREAKPOINT:
88851.160Smgorny					*FIND_EVENT_COUNT(bp_counts,
88861.160Smgorny					    info.psi_lwpid) += 1;
88871.160Smgorny					break;
88881.161Smgorny				case TCSE_WATCHPOINT:
88891.161Smgorny					*FIND_EVENT_COUNT(wp_counts,
88901.161Smgorny					    info.psi_lwpid) += 1;
88911.161Smgorny					break;
88921.160Smgorny			}
88931.160Smgorny#else
88941.160Smgorny			ATF_CHECK_MSG(0, "Unexpected SIGTRAP, si_code=%d\n",
88951.160Smgorny			    info.psi_siginfo.si_code);
88961.160Smgorny#endif
88971.159Smgorny		}
88981.138Smgorny
88991.138Smgorny		DPRINTF("Before resuming the child process\n");
89001.157Smgorny		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
89011.159Smgorny		     signal_handle != TCSH_DISCARD && WSTOPSIG(status) != SIGTRAP
89021.159Smgorny		     ? WSTOPSIG(status) : 0) != -1);
89031.138Smgorny	}
89041.138Smgorny
89051.156Smgorny	for (i = 0; i < signal_threads; i++)
89061.141Skamil		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 1,
89071.141Skamil		    "signal_counts[%d].lec_count=%d; lec_lwp=%d",
89081.141Skamil		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
89091.156Smgorny	for (i = signal_threads; i < THREAD_CONCURRENT_SIGNALS_NUM; i++)
89101.156Smgorny		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 0,
89111.156Smgorny		    "extraneous signal_counts[%d].lec_count=%d; lec_lwp=%d",
89121.156Smgorny		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
89131.138Smgorny
89141.160Smgorny	for (i = 0; i < breakpoint_threads; i++)
89151.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 1,
89161.160Smgorny		    "bp_counts[%d].lec_count=%d; lec_lwp=%d",
89171.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
89181.160Smgorny	for (i = breakpoint_threads; i < THREAD_CONCURRENT_BREAKPOINT_NUM; i++)
89191.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 0,
89201.160Smgorny		    "extraneous bp_counts[%d].lec_count=%d; lec_lwp=%d",
89211.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
89221.160Smgorny
89231.161Smgorny	for (i = 0; i < watchpoint_threads; i++)
89241.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 1,
89251.161Smgorny		    "wp_counts[%d].lec_count=%d; lec_lwp=%d",
89261.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
89271.161Smgorny	for (i = watchpoint_threads; i < THREAD_CONCURRENT_WATCHPOINT_NUM; i++)
89281.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 0,
89291.161Smgorny		    "extraneous wp_counts[%d].lec_count=%d; lec_lwp=%d",
89301.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
89311.161Smgorny
89321.138Smgorny	validate_status_exited(status, exitval);
89331.138Smgorny}
89341.138Smgorny
89351.161Smgorny#define THREAD_CONCURRENT_TEST(test, sig_hdl, bps, sigs, wps, descr)	\
89361.156SmgornyATF_TC(test);								\
89371.156SmgornyATF_TC_HEAD(test, tc)							\
89381.156Smgorny{									\
89391.156Smgorny	atf_tc_set_md_var(tc, "descr", descr);				\
89401.156Smgorny}									\
89411.156Smgorny									\
89421.156SmgornyATF_TC_BODY(test, tc)							\
89431.156Smgorny{									\
89441.161Smgorny	thread_concurrent_test(sig_hdl, bps, sigs, wps);		\
89451.156Smgorny}
89461.156Smgorny
89471.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals, TCSH_DISCARD,
89481.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
89491.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
89501.157Smgorny    "correctly");
89511.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_sig_ign, TCSH_SIG_IGN,
89521.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
89531.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
89541.157Smgorny    "correctly and passed back to SIG_IGN handler");
89551.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_handler, TCSH_HANDLER,
89561.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
89571.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
89581.157Smgorny    "correctly and passed back to a handler function");
89591.156Smgorny
89601.163Skamil#if defined(__i386__) || defined(__x86_64__)
89611.160SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_breakpoints, TCSH_DISCARD,
89621.161Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, 0,
89631.161Smgorny    "Verify that concurrent breakpoints are reported correctly");
89641.161SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_watchpoints, TCSH_DISCARD,
89651.161Smgorny    0, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
89661.160Smgorny    "Verify that concurrent breakpoints are reported correctly");
89671.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp, TCSH_DISCARD,
89681.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
89691.162Smgorny    "Verify that concurrent breakpoints and watchpoints are reported "
89701.162Smgorny    "correctly");
89711.162Smgorny
89721.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig, TCSH_DISCARD,
89731.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
89741.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly");
89751.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_sig_ign, TCSH_SIG_IGN,
89761.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
89771.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
89781.162Smgorny    "and passed back to SIG_IGN handler");
89791.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_handler, TCSH_HANDLER,
89801.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
89811.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
89821.162Smgorny    "and passed back to a handler function");
89831.162Smgorny
89841.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig, TCSH_DISCARD,
89851.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
89861.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly");
89871.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_sig_ign, TCSH_SIG_IGN,
89881.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
89891.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
89901.162Smgorny    "and passed back to SIG_IGN handler");
89911.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_handler, TCSH_HANDLER,
89921.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
89931.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
89941.162Smgorny    "and passed back to a handler function");
89951.162Smgorny
89961.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig, TCSH_DISCARD,
89971.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
89981.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
89991.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
90001.162Smgorny    "correctly");
90011.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_sig_ign, TCSH_SIG_IGN,
90021.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
90031.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
90041.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
90051.162Smgorny    "correctly and passed back to SIG_IGN handler");
90061.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_handler, TCSH_HANDLER,
90071.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
90081.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
90091.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
90101.162Smgorny    "correctly and passed back to a handler function");
90111.163Skamil#endif
90121.160Smgorny
90131.138Smgorny#endif /*defined(TWAIT_HAVE_STATUS)*/
90141.138Smgorny
90151.138Smgorny/// ----------------------------------------------------------------------------
90161.138Smgorny
90171.1Skamil#include "t_ptrace_amd64_wait.h"
90181.1Skamil#include "t_ptrace_i386_wait.h"
90191.1Skamil#include "t_ptrace_x86_wait.h"
90201.1Skamil
90211.165Skamil/// ----------------------------------------------------------------------------
90221.165Skamil
90231.165Skamil#else
90241.165SkamilATF_TC(dummy);
90251.165SkamilATF_TC_HEAD(dummy, tc)
90261.165Skamil{
90271.165Skamil	atf_tc_set_md_var(tc, "descr", "A dummy test");
90281.165Skamil}
90291.165Skamil
90301.165SkamilATF_TC_BODY(dummy, tc)
90311.165Skamil{
90321.165Skamil
90331.165Skamil	// Dummy, skipped
90341.165Skamil	// The ATF framework requires at least a single defined test.
90351.165Skamil}
90361.165Skamil#endif
90371.165Skamil
90381.1SkamilATF_TP_ADD_TCS(tp)
90391.1Skamil{
90401.1Skamil	setvbuf(stdout, NULL, _IONBF, 0);
90411.1Skamil	setvbuf(stderr, NULL, _IONBF, 0);
90421.33Skamil
90431.165Skamil#ifdef ENABLE_TESTS
90441.36Skamil	ATF_TP_ADD_TC(tp, traceme_raise1);
90451.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise2);
90461.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise3);
90471.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise4);
90481.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise5);
90491.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise6);
90501.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise7);
90511.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise8);
90521.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise9);
90531.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise10);
90541.33Skamil
90551.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored1);
90561.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored2);
90571.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored3);
90581.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored4);
90591.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored5);
90601.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored6);
90611.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored7);
90621.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored8);
90631.87Skamil
90641.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked1);
90651.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked2);
90661.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked3);
90671.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked4);
90681.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked5);
90691.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked6);
90701.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked7);
90711.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked8);
90721.86Skamil
90731.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_trap);
90741.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_segv);
90751.71Skamil	ATF_TP_ADD_TC(tp, traceme_crash_ill);
90761.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_fpe);
90771.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_bus);
90781.59Skamil
90791.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_trap);
90801.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_segv);
90811.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_ill);
90821.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_fpe);
90831.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_bus);
90841.88Skamil
90851.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_trap);
90861.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_segv);
90871.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_ill);
90881.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_fpe);
90891.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_bus);
90901.88Skamil
90911.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle1);
90921.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle2);
90931.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle3);
90941.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle4);
90951.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle5);
90961.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle6);
90971.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle7);
90981.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle8);
90991.50Skamil
91001.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked1);
91011.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked2);
91021.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked3);
91031.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked4);
91041.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked5);
91051.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked6);
91061.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked7);
91071.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked8);
91081.50Skamil
91091.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored1);
91101.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored2);
91111.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored3);
91121.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored4);
91131.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored5);
91141.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored6);
91151.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored7);
91161.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored8);
91171.50Skamil
91181.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple1);
91191.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple2);
91201.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple3);
91211.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple4);
91221.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple5);
91231.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple6);
91241.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple7);
91251.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple8);
91261.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple9);
91271.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple10);
91281.1Skamil
91291.37Skamil	ATF_TP_ADD_TC(tp, traceme_pid1_parent);
91301.37Skamil
91311.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise1);
91321.46Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise2);
91331.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise3);
91341.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise4);
91351.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise5);
91361.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise6);
91371.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise7);
91381.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise8);
91391.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise9);
91401.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise10);
91411.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise11);
91421.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise12);
91431.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise13);
91441.40Skamil
91451.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_trap);
91461.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_segv);
91471.71Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_ill);
91481.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_fpe);
91491.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_bus);
91501.41Skamil
91511.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_trap);
91521.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_segv);
91531.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_ill);
91541.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_fpe);
91551.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_bus);
91561.92Skamil
91571.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_trap);
91581.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_segv);
91591.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_ill);
91601.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_fpe);
91611.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_bus);
91621.92Skamil
91631.43Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_exec);
91641.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_exec);
91651.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_exec);
91661.43Skamil
91671.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_trap);
91681.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_segv);
91691.71Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_ill);
91701.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_fpe);
91711.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_bus);
91721.59Skamil
91731.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
91741.94Skamil	    unrelated_tracer_sees_signalmasked_crash_trap);
91751.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
91761.94Skamil	    unrelated_tracer_sees_signalmasked_crash_segv);
91771.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
91781.94Skamil	    unrelated_tracer_sees_signalmasked_crash_ill);
91791.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
91801.94Skamil	    unrelated_tracer_sees_signalmasked_crash_fpe);
91811.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
91821.94Skamil	    unrelated_tracer_sees_signalmasked_crash_bus);
91831.94Skamil
91841.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
91851.94Skamil	    unrelated_tracer_sees_signalignored_crash_trap);
91861.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
91871.94Skamil	    unrelated_tracer_sees_signalignored_crash_segv);
91881.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
91891.94Skamil	    unrelated_tracer_sees_signalignored_crash_ill);
91901.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
91911.94Skamil	    unrelated_tracer_sees_signalignored_crash_fpe);
91921.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
91931.94Skamil	    unrelated_tracer_sees_signalignored_crash_bus);
91941.94Skamil
91951.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sees_terminaton_before_the_parent);
91961.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sysctl_lookup_without_duplicates);
91971.61Skre	ATF_TP_ADD_TC_HAVE_PID(tp,
91981.61Skre		unrelated_tracer_sees_terminaton_before_the_parent);
91991.67Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_attach_to_unrelated_stopped_process);
92001.51Skamil
92011.51Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_child);
92021.66Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_stopped_child);
92031.51Skamil
92041.51Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_parent);
92051.65Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_stopped_parent);
92061.51Skamil
92071.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92081.51Skamil		tracee_sees_its_original_parent_getppid);
92091.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92101.51Skamil		tracee_sees_its_original_parent_sysctl_kinfo_proc2);
92111.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92121.51Skamil		tracee_sees_its_original_parent_procfs_status);
92131.1Skamil
92141.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_empty);
92151.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_fork);
92161.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork);
92171.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork_done);
92181.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_create);
92191.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_exit);
92201.125Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_posix_spawn);
92211.1Skamil
92221.31Skamil	ATF_TP_ADD_TC(tp, fork1);
92231.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork2);
92241.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork3);
92251.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork4);
92261.31Skamil	ATF_TP_ADD_TC(tp, fork5);
92271.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork6);
92281.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork7);
92291.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork8);
92301.125Skamil	ATF_TP_ADD_TC(tp, fork9);
92311.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork10);
92321.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork11);
92331.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork12);
92341.125Skamil	ATF_TP_ADD_TC(tp, fork13);
92351.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork14);
92361.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork15);
92371.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork16);
92381.31Skamil
92391.31Skamil	ATF_TP_ADD_TC(tp, vfork1);
92401.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork2);
92411.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork3);
92421.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork4);
92431.31Skamil	ATF_TP_ADD_TC(tp, vfork5);
92441.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork6);
92451.104Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork7);
92461.104Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork8);
92471.125Skamil	ATF_TP_ADD_TC(tp, vfork9);
92481.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork10);
92491.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork11);
92501.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork12);
92511.125Skamil	ATF_TP_ADD_TC(tp, vfork13);
92521.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork14);
92531.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork15);
92541.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork16);
92551.1Skamil
92561.124Skamil	ATF_TP_ADD_TC(tp, posix_spawn1);
92571.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn2);
92581.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn3);
92591.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn4);
92601.124Skamil	ATF_TP_ADD_TC(tp, posix_spawn5);
92611.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn6);
92621.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn7);
92631.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn8);
92641.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn9);
92651.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn10);
92661.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn11);
92671.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn12);
92681.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn13);
92691.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn14);
92701.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn15);
92711.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn16);
92721.124Skamil
92731.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork1);
92741.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork2);
92751.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork3);
92761.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork4);
92771.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork5);
92781.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork6);
92791.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork7);
92801.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork8);
92811.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork9);
92821.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork10);
92831.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork11);
92841.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork12);
92851.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork13);
92861.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork14);
92871.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork15);
92881.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork16);
92891.149Skamil
92901.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork1);
92911.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork2);
92921.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork3);
92931.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork4);
92941.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork5);
92951.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork6);
92961.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork7);
92971.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork8);
92981.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork9);
92991.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork10);
93001.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork11);
93011.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork12);
93021.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork13);
93031.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork14);
93041.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork15);
93051.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork16);
93061.149Skamil
93071.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn1);
93081.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn2);
93091.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn3);
93101.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn4);
93111.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn5);
93121.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn6);
93131.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn7);
93141.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn8);
93151.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn9);
93161.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn10);
93171.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn11);
93181.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn12);
93191.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn13);
93201.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn14);
93211.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn15);
93221.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn16);
93231.149Skamil
93241.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_detach_spawner);
93251.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_detach_forker);
93261.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_detach_vforker);
93271.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_detach_vforkerdone);
93281.126Skamil
93291.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_kill_spawner);
93301.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_kill_forker);
93311.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_kill_vforker);
93321.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_kill_vforkerdone);
93331.116Skamil
93341.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn_detach_spawner);
93351.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork_detach_forker);
93361.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork_detach_vforker);
93371.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork_detach_vforkerdone);
93381.150Skamil
93391.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn_kill_spawner);
93401.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork_kill_forker);
93411.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork_kill_vforker);
93421.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork_kill_vforkerdone);
93431.150Skamil
93441.108Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_fork);
93451.108Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_vfork);
93461.108Skamil
93471.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8);
93481.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16);
93491.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32);
93501.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64);
93511.54Skamil
93521.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8);
93531.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16);
93541.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32);
93551.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64);
93561.54Skamil
93571.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8);
93581.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16);
93591.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32);
93601.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64);
93611.54Skamil
93621.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8);
93631.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16);
93641.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32);
93651.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64);
93661.54Skamil
93671.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d);
93681.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i);
93691.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d);
93701.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i);
93711.54Skamil
93721.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8_text);
93731.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16_text);
93741.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32_text);
93751.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64_text);
93761.54Skamil
93771.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8_text);
93781.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16_text);
93791.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32_text);
93801.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64_text);
93811.54Skamil
93821.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8_text);
93831.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16_text);
93841.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32_text);
93851.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64_text);
93861.54Skamil
93871.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8_text);
93881.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16_text);
93891.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32_text);
93901.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64_text);
93911.54Skamil
93921.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d_text);
93931.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i_text);
93941.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d_text);
93951.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i_text);
93961.1Skamil
93971.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_auxv);
93981.1Skamil
93991.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_i);
94001.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_d);
94011.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_i);
94021.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_d);
94031.101Skamil
94041.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_i);
94051.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_d);
94061.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_i);
94071.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_d);
94081.101Skamil
94091.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_auxv);
94101.101Skamil
94111.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_i);
94121.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_d);
94131.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_i);
94141.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_d);
94151.115Skamil
94161.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_i);
94171.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_d);
94181.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_i);
94191.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_d);
94201.115Skamil
94211.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs1);
94221.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs2);
94231.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs3);
94241.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs4);
94251.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs5);
94261.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs6);
94271.1Skamil
94281.148Smartin	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs_set_unaligned_pc_0x1);
94291.148Smartin	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs_set_unaligned_pc_0x3);
94301.148Smartin	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs_set_unaligned_pc_0x7);
94311.147Skamil
94321.72Skamil	ATF_TP_ADD_TC_HAVE_FPREGS(tp, access_fpregs1);
94331.72Skamil	ATF_TP_ADD_TC_HAVE_FPREGS(tp, access_fpregs2);
94341.1Skamil
94351.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step1);
94361.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step2);
94371.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step3);
94381.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step4);
94391.1Skamil
94401.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep1);
94411.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep2);
94421.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep3);
94431.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep4);
94441.2Skamil
94451.95Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step_signalmasked);
94461.95Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step_signalignored);
94471.95Skamil
94481.1Skamil	ATF_TP_ADD_TC(tp, kill1);
94491.1Skamil	ATF_TP_ADD_TC(tp, kill2);
94501.75Skamil	ATF_TP_ADD_TC(tp, kill3);
94511.1Skamil
94521.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0);
94531.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1);
94541.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2);
94551.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3);
94561.77Skamil
94571.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus);
94581.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus);
94591.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus);
94601.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus);
94611.143Skamil
94621.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_sigmask);
94631.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_sigmask);
94641.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_sigmask);
94651.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_sigmask);
94661.143Skamil
94671.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_name);
94681.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_name);
94691.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_name);
94701.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_name);
94711.143Skamil
94721.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_private);
94731.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_private);
94741.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_private);
94751.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_private);
94761.143Skamil
94771.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0);
94781.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1);
94791.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2);
94801.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3);
94811.143Skamil
94821.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_sigmask);
94831.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_sigmask);
94841.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_sigmask);
94851.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_sigmask);
94861.143Skamil
94871.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_name);
94881.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_name);
94891.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_name);
94901.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_name);
94911.143Skamil
94921.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_private);
94931.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_private);
94941.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_private);
94951.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_private);
94961.143Skamil
94971.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo0);
94981.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo1);
94991.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo2);
95001.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo3);
95011.1Skamil
95021.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_unmodified);
95031.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_faked);
95041.79Skamil
95051.82Skamil	ATF_TP_ADD_TC(tp, traceme_exec);
95061.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_exec);
95071.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_exec);
95081.1Skamil
95091.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_nolwpevents);
95101.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit);
95111.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate);
95121.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit);
95131.1Skamil
95141.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit_masked_sigtrap);
95151.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_masked_sigtrap);
95161.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit_masked_sigtrap);
95171.153Skamil
95181.84Skamil	ATF_TP_ADD_TC(tp, signal_mask_unrelated);
95191.84Skamil
95201.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_singalmasked);
95211.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_singalignored);
95221.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_singalmasked);
95231.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_singalignored);
95241.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_singalmasked);
95251.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_singalignored);
95261.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vforkdone_singalmasked);
95271.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vforkdone_singalignored);
95281.99Skamil
95291.151Skamil	ATF_TP_ADD_TC(tp, threads_and_exec);
95301.151Skamil
95311.154Skamil	ATF_TP_ADD_TC(tp, suspend_no_deadlock);
95321.1Skamil
95331.155Skamil	ATF_TP_ADD_TC(tp, resume);
95341.1Skamil
95351.1Skamil	ATF_TP_ADD_TC(tp, syscall1);
95361.1Skamil
95371.1Skamil	ATF_TP_ADD_TC(tp, syscallemu1);
95381.1Skamil
95391.106Skamil	ATF_TP_ADD_TC(tp, clone1);
95401.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone2);
95411.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone3);
95421.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone4);
95431.106Skamil	ATF_TP_ADD_TC(tp, clone5);
95441.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone6);
95451.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone7);
95461.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone8);
95471.106Skamil
95481.106Skamil	ATF_TP_ADD_TC(tp, clone_vm1);
95491.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm2);
95501.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm3);
95511.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm4);
95521.106Skamil	ATF_TP_ADD_TC(tp, clone_vm5);
95531.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm6);
95541.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm7);
95551.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm8);
95561.106Skamil
95571.106Skamil	ATF_TP_ADD_TC(tp, clone_fs1);
95581.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs2);
95591.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs3);
95601.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs4);
95611.106Skamil	ATF_TP_ADD_TC(tp, clone_fs5);
95621.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs6);
95631.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs7);
95641.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs8);
95651.106Skamil
95661.106Skamil	ATF_TP_ADD_TC(tp, clone_files1);
95671.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files2);
95681.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files3);
95691.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files4);
95701.106Skamil	ATF_TP_ADD_TC(tp, clone_files5);
95711.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files6);
95721.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files7);
95731.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files8);
95741.106Skamil
95751.106Skamil//	ATF_TP_ADD_TC(tp, clone_sighand1); // XXX
95761.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand2); // XXX
95771.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand3); // XXX
95781.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand4); // XXX
95791.106Skamil//	ATF_TP_ADD_TC(tp, clone_sighand5); // XXX
95801.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand6); // XXX
95811.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand7); // XXX
95821.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand8); // XXX
95831.106Skamil
95841.106Skamil	ATF_TP_ADD_TC(tp, clone_vfork1);
95851.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork2);
95861.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork3);
95871.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork4);
95881.106Skamil	ATF_TP_ADD_TC(tp, clone_vfork5);
95891.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork6);
95901.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork7);
95911.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork8);
95921.106Skamil
95931.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_signalignored);
95941.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_signalmasked);
95951.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm_signalignored);
95961.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm_signalmasked);
95971.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs_signalignored);
95981.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs_signalmasked);
95991.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files_signalignored);
96001.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files_signalmasked);
96011.103Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand_signalignored); // XXX
96021.103Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand_signalmasked); // XXX
96031.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork_signalignored);
96041.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork_signalmasked);
96051.103Skamil
96061.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone);
96071.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_vm);
96081.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_fs);
96091.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_files);
96101.107Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_sighand); // XXX
96111.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_vfork);
96121.107Skamil
96131.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_continue);
96141.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall);
96151.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach);
96161.122Skamil
96171.130Smgorny	ATF_TP_ADD_TC(tp, core_dump_procinfo);
96181.130Smgorny
96191.138Smgorny#if defined(TWAIT_HAVE_STATUS)
96201.138Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals);
96211.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_sig_ign);
96221.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_handler);
96231.160Smgorny#if defined(__i386__) || defined(__x86_64__)
96241.160Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_breakpoints);
96251.161Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_watchpoints);
96261.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp);
96271.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig);
96281.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_sig_ign);
96291.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_handler);
96301.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig);
96311.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_sig_ign);
96321.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_handler);
96331.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig);
96341.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_sig_ign);
96351.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_handler);
96361.160Smgorny#endif
96371.138Smgorny#endif
96381.138Smgorny
96391.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
96401.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_I386();
96411.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_X86();
96421.1Skamil
96431.165Skamil#else
96441.165Skamil	ATF_TP_ADD_TC(tp, dummy);
96451.165Skamil#endif
96461.165Skamil
96471.1Skamil	return atf_no_error();
96481.1Skamil}
9649