t_ptrace_wait.c revision 1.170
11.170Skamil/*	$NetBSD: t_ptrace_wait.c,v 1.170 2020/04/14 22:37:24 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.170Skamil__RCSID("$NetBSD: t_ptrace_wait.c,v 1.170 2020/04/14 22:37:24 kamil Exp $");
311.143Skamil
321.143Skamil#define __LEGACY_PT_LWPINFO
331.1Skamil
341.1Skamil#include <sys/param.h>
351.1Skamil#include <sys/types.h>
361.130Smgorny#include <sys/exec_elf.h>
371.39Skamil#include <sys/mman.h>
381.1Skamil#include <sys/ptrace.h>
391.1Skamil#include <sys/resource.h>
401.1Skamil#include <sys/stat.h>
411.1Skamil#include <sys/syscall.h>
421.1Skamil#include <sys/sysctl.h>
431.129Smgorny#include <sys/uio.h>
441.1Skamil#include <sys/wait.h>
451.1Skamil#include <machine/reg.h>
461.132Skamil#include <assert.h>
471.1Skamil#include <elf.h>
481.1Skamil#include <err.h>
491.1Skamil#include <errno.h>
501.130Smgorny#include <fcntl.h>
511.1Skamil#include <lwp.h>
521.77Skamil#include <pthread.h>
531.1Skamil#include <sched.h>
541.1Skamil#include <signal.h>
551.124Skamil#include <spawn.h>
561.1Skamil#include <stdint.h>
571.1Skamil#include <stdio.h>
581.1Skamil#include <stdlib.h>
591.1Skamil#include <strings.h>
601.26Skamil#include <time.h>
611.1Skamil#include <unistd.h>
621.1Skamil
631.121Smgorny#if defined(__i386__) || defined(__x86_64__)
641.121Smgorny#include <cpuid.h>
651.121Smgorny#include <x86/cpu_extended_state.h>
661.129Smgorny#include <x86/specialreg.h>
671.121Smgorny#endif
681.121Smgorny
691.130Smgorny#include <libelf.h>
701.130Smgorny#include <gelf.h>
711.130Smgorny
721.1Skamil#include <atf-c.h>
731.1Skamil
741.165Skamil#ifdef ENABLE_TESTS
751.165Skamil
761.132Skamil/* Assumptions in the kernel code that must be kept. */
771.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_report_event) ==
781.132Skamil    sizeof(((siginfo_t *)0)->si_pe_report_event),
791.132Skamil    "pe_report_event and si_pe_report_event must be of the same size");
801.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_other_pid) ==
811.132Skamil    sizeof(((siginfo_t *)0)->si_pe_other_pid),
821.132Skamil    "pe_other_pid and si_pe_other_pid must be of the same size");
831.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_lwp) ==
841.132Skamil    sizeof(((siginfo_t *)0)->si_pe_lwp),
851.132Skamil    "pe_lwp and si_pe_lwp must be of the same size");
861.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_other_pid) ==
871.132Skamil    sizeof(((struct ptrace_state *)0)->pe_lwp),
881.132Skamil    "pe_other_pid and pe_lwp must be of the same size");
891.132Skamil
901.1Skamil#include "h_macros.h"
911.1Skamil
921.1Skamil#include "t_ptrace_wait.h"
931.1Skamil#include "msg.h"
941.1Skamil
951.13Schristos#define SYSCALL_REQUIRE(expr) ATF_REQUIRE_MSG(expr, "%s: %s", # expr, \
961.13Schristos    strerror(errno))
971.18Schristos#define SYSCALL_REQUIRE_ERRNO(res, exp) ATF_REQUIRE_MSG(res == exp, \
981.18Schristos    "%d(%s) != %d", res, strerror(res), exp)
991.13Schristos
1001.152Skamilstatic int debug = 0;
1011.13Schristos
1021.13Schristos#define DPRINTF(a, ...)	do  \
1031.123Skamil	if (debug) \
1041.142Skamil	printf("%s() %d.%d %s:%d " a, \
1051.142Skamil	__func__, getpid(), _lwp_self(), __FILE__, __LINE__,  ##__VA_ARGS__); \
1061.13Schristos    while (/*CONSTCOND*/0)
1071.1Skamil
1081.34Skamil/// ----------------------------------------------------------------------------
1091.34Skamil
1101.33Skamilstatic void
1111.33Skamiltraceme_raise(int sigval)
1121.1Skamil{
1131.1Skamil	const int exitval = 5;
1141.1Skamil	pid_t child, wpid;
1151.1Skamil#if defined(TWAIT_HAVE_STATUS)
1161.1Skamil	int status;
1171.1Skamil#endif
1181.1Skamil
1191.133Skamil	ptrace_state_t state, zero_state;
1201.133Skamil	const int slen = sizeof(state);
1211.45Skamil	struct ptrace_siginfo info;
1221.133Skamil	memset(&zero_state, 0, sizeof(zero_state));
1231.45Skamil	memset(&info, 0, sizeof(info));
1241.45Skamil
1251.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
1261.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
1271.1Skamil	if (child == 0) {
1281.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1291.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
1301.1Skamil
1311.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
1321.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
1331.1Skamil
1341.36Skamil		switch (sigval) {
1351.36Skamil		case SIGKILL:
1361.36Skamil			/* NOTREACHED */
1371.36Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
1381.70Smrg			__unreachable();
1391.36Skamil		default:
1401.36Skamil			DPRINTF("Before exiting of the child process\n");
1411.36Skamil			_exit(exitval);
1421.36Skamil		}
1431.1Skamil	}
1441.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
1451.1Skamil
1461.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1471.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
1481.1Skamil
1491.36Skamil	switch (sigval) {
1501.36Skamil	case SIGKILL:
1511.36Skamil		validate_status_signaled(status, sigval, 0);
1521.133Skamil		SYSCALL_REQUIRE(
1531.133Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) == -1);
1541.133Skamil
1551.36Skamil		break;
1561.36Skamil	default:
1571.36Skamil		validate_status_stopped(status, sigval);
1581.1Skamil
1591.45Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
1601.61Skre			"child\n");
1611.45Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
1621.61Skre			sizeof(info)) != -1);
1631.45Skamil
1641.45Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
1651.45Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
1661.61Skre			"si_errno=%#x\n",
1671.61Skre			info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
1681.61Skre			info.psi_siginfo.si_errno);
1691.45Skamil
1701.45Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
1711.45Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
1721.45Skamil
1731.133Skamil		DPRINTF("Assert that PT_GET_PROCESS_STATE returns non-error");
1741.133Skamil		SYSCALL_REQUIRE(
1751.133Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
1761.133Skamil		ATF_REQUIRE(memcmp(&state, &zero_state, slen) == 0);
1771.133Skamil
1781.36Skamil		DPRINTF("Before resuming the child process where it left off "
1791.36Skamil		    "and without signal to be sent\n");
1801.36Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
1811.1Skamil
1821.36Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1831.36Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
1841.61Skre		    child);
1851.36Skamil		break;
1861.36Skamil	}
1871.1Skamil
1881.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1891.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
1901.1Skamil}
1911.1Skamil
1921.61Skre#define TRACEME_RAISE(test, sig)					\
1931.61SkreATF_TC(test);								\
1941.61SkreATF_TC_HEAD(test, tc)							\
1951.61Skre{									\
1961.61Skre	atf_tc_set_md_var(tc, "descr",					\
1971.61Skre	    "Verify " #sig " followed by _exit(2) in a child");		\
1981.61Skre}									\
1991.61Skre									\
2001.61SkreATF_TC_BODY(test, tc)							\
2011.61Skre{									\
2021.61Skre									\
2031.61Skre	traceme_raise(sig);						\
2041.33Skamil}
2051.33Skamil
2061.36SkamilTRACEME_RAISE(traceme_raise1, SIGKILL) /* non-maskable */
2071.33SkamilTRACEME_RAISE(traceme_raise2, SIGSTOP) /* non-maskable */
2081.33SkamilTRACEME_RAISE(traceme_raise3, SIGABRT) /* regular abort trap */
2091.33SkamilTRACEME_RAISE(traceme_raise4, SIGHUP)  /* hangup */
2101.33SkamilTRACEME_RAISE(traceme_raise5, SIGCONT) /* continued? */
2111.85SkamilTRACEME_RAISE(traceme_raise6, SIGTRAP) /* crash signal */
2121.85SkamilTRACEME_RAISE(traceme_raise7, SIGBUS) /* crash signal */
2131.85SkamilTRACEME_RAISE(traceme_raise8, SIGILL) /* crash signal */
2141.85SkamilTRACEME_RAISE(traceme_raise9, SIGFPE) /* crash signal */
2151.85SkamilTRACEME_RAISE(traceme_raise10, SIGSEGV) /* crash signal */
2161.33Skamil
2171.34Skamil/// ----------------------------------------------------------------------------
2181.1Skamil
2191.1Skamilstatic void
2201.87Skamiltraceme_raisesignal_ignored(int sigignored)
2211.87Skamil{
2221.87Skamil	const int exitval = 5;
2231.87Skamil	const int sigval = SIGSTOP;
2241.87Skamil	pid_t child, wpid;
2251.87Skamil	struct sigaction sa;
2261.87Skamil#if defined(TWAIT_HAVE_STATUS)
2271.87Skamil	int status;
2281.87Skamil#endif
2291.87Skamil	struct ptrace_siginfo info;
2301.87Skamil
2311.87Skamil	memset(&info, 0, sizeof(info));
2321.87Skamil
2331.87Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
2341.87Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
2351.87Skamil	if (child == 0) {
2361.87Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
2371.87Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
2381.87Skamil
2391.87Skamil		memset(&sa, 0, sizeof(sa));
2401.87Skamil		sa.sa_handler = SIG_IGN;
2411.87Skamil		sigemptyset(&sa.sa_mask);
2421.87Skamil		FORKEE_ASSERT(sigaction(sigignored, &sa, NULL) != -1);
2431.87Skamil
2441.87Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
2451.87Skamil		FORKEE_ASSERT(raise(sigval) == 0);
2461.87Skamil
2471.87Skamil		DPRINTF("Before raising %s from child\n",
2481.87Skamil		    strsignal(sigignored));
2491.87Skamil		FORKEE_ASSERT(raise(sigignored) == 0);
2501.87Skamil
2511.87Skamil		DPRINTF("Before exiting of the child process\n");
2521.87Skamil		_exit(exitval);
2531.87Skamil	}
2541.87Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
2551.87Skamil
2561.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2571.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2581.87Skamil
2591.87Skamil	validate_status_stopped(status, sigval);
2601.87Skamil
2611.87Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
2621.87Skamil	SYSCALL_REQUIRE(
2631.87Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
2641.87Skamil
2651.87Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
2661.87Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
2671.87Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
2681.87Skamil	    info.psi_siginfo.si_errno);
2691.87Skamil
2701.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
2711.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
2721.87Skamil
2731.87Skamil	DPRINTF("Before resuming the child process where it left off and "
2741.87Skamil	    "without signal to be sent\n");
2751.87Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
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, sigignored);
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, sigignored);
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_exited(status, exitval);
3021.87Skamil
3031.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3041.87Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
3051.87Skamil}
3061.87Skamil
3071.87Skamil#define TRACEME_RAISESIGNAL_IGNORED(test, sig)				\
3081.87SkamilATF_TC(test);								\
3091.87SkamilATF_TC_HEAD(test, tc)							\
3101.87Skamil{									\
3111.87Skamil	atf_tc_set_md_var(tc, "descr",					\
3121.87Skamil	    "Verify that ignoring (with SIG_IGN) " #sig " in tracee "	\
3131.87Skamil	    "does not stop tracer from catching this raised signal");	\
3141.87Skamil}									\
3151.87Skamil									\
3161.87SkamilATF_TC_BODY(test, tc)							\
3171.87Skamil{									\
3181.87Skamil									\
3191.87Skamil	traceme_raisesignal_ignored(sig);				\
3201.87Skamil}
3211.87Skamil
3221.87Skamil// A signal handler for SIGKILL and SIGSTOP cannot be ignored.
3231.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored1, SIGABRT) /* abort */
3241.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored2, SIGHUP)  /* hangup */
3251.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored3, SIGCONT) /* cont. */
3261.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored4, SIGTRAP) /* crash */
3271.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored5, SIGBUS) /* crash */
3281.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored6, SIGILL) /* crash */
3291.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored7, SIGFPE) /* crash */
3301.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored8, SIGSEGV) /* crash */
3311.87Skamil
3321.87Skamil/// ----------------------------------------------------------------------------
3331.87Skamil
3341.87Skamilstatic void
3351.86Skamiltraceme_raisesignal_masked(int sigmasked)
3361.86Skamil{
3371.86Skamil	const int exitval = 5;
3381.86Skamil	const int sigval = SIGSTOP;
3391.86Skamil	pid_t child, wpid;
3401.86Skamil#if defined(TWAIT_HAVE_STATUS)
3411.86Skamil	int status;
3421.86Skamil#endif
3431.86Skamil	sigset_t intmask;
3441.86Skamil	struct ptrace_siginfo info;
3451.86Skamil
3461.86Skamil	memset(&info, 0, sizeof(info));
3471.86Skamil
3481.86Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
3491.86Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
3501.86Skamil	if (child == 0) {
3511.86Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
3521.86Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
3531.86Skamil
3541.86Skamil		sigemptyset(&intmask);
3551.86Skamil		sigaddset(&intmask, sigmasked);
3561.86Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
3571.86Skamil
3581.86Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
3591.86Skamil		FORKEE_ASSERT(raise(sigval) == 0);
3601.86Skamil
3611.86Skamil		DPRINTF("Before raising %s breakpoint from child\n",
3621.86Skamil		    strsignal(sigmasked));
3631.86Skamil		FORKEE_ASSERT(raise(sigmasked) == 0);
3641.86Skamil
3651.86Skamil		DPRINTF("Before exiting of the child process\n");
3661.86Skamil		_exit(exitval);
3671.86Skamil	}
3681.86Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
3691.86Skamil
3701.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3711.86Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
3721.86Skamil
3731.86Skamil	validate_status_stopped(status, sigval);
3741.86Skamil
3751.86Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
3761.86Skamil	SYSCALL_REQUIRE(
3771.86Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
3781.86Skamil
3791.86Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
3801.86Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
3811.86Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
3821.86Skamil	    info.psi_siginfo.si_errno);
3831.86Skamil
3841.86Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
3851.86Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
3861.86Skamil
3871.86Skamil	DPRINTF("Before resuming the child process where it left off and "
3881.86Skamil	    "without signal to be sent\n");
3891.86Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
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_exited(status, exitval);
3951.86Skamil
3961.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3971.86Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
3981.86Skamil}
3991.86Skamil
4001.86Skamil#define TRACEME_RAISESIGNAL_MASKED(test, sig)				\
4011.86SkamilATF_TC(test);								\
4021.86SkamilATF_TC_HEAD(test, tc)							\
4031.86Skamil{									\
4041.86Skamil	atf_tc_set_md_var(tc, "descr",					\
4051.86Skamil	    "Verify that masking (with SIG_BLOCK) " #sig " in tracee "	\
4061.86Skamil	    "stops tracer from catching this raised signal");		\
4071.86Skamil}									\
4081.86Skamil									\
4091.86SkamilATF_TC_BODY(test, tc)							\
4101.86Skamil{									\
4111.86Skamil									\
4121.86Skamil	traceme_raisesignal_masked(sig);				\
4131.86Skamil}
4141.86Skamil
4151.86Skamil// A signal handler for SIGKILL and SIGSTOP cannot be masked.
4161.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked1, SIGABRT) /* abort trap */
4171.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked2, SIGHUP)  /* hangup */
4181.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked3, SIGCONT) /* continued? */
4191.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked4, SIGTRAP) /* crash sig. */
4201.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked5, SIGBUS) /* crash sig. */
4211.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked6, SIGILL) /* crash sig. */
4221.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked7, SIGFPE) /* crash sig. */
4231.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked8, SIGSEGV) /* crash sig. */
4241.86Skamil
4251.86Skamil/// ----------------------------------------------------------------------------
4261.86Skamil
4271.86Skamilstatic void
4281.59Skamiltraceme_crash(int sig)
4291.59Skamil{
4301.59Skamil	pid_t child, wpid;
4311.59Skamil#if defined(TWAIT_HAVE_STATUS)
4321.59Skamil	int status;
4331.59Skamil#endif
4341.59Skamil	struct ptrace_siginfo info;
4351.61Skre
4361.71Skamil#ifndef PTRACE_ILLEGAL_ASM
4371.71Skamil	if (sig == SIGILL)
4381.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
4391.71Skamil#endif
4401.71Skamil
4411.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
4421.114Skamil		atf_tc_skip("FP exceptions are not supported");
4431.114Skamil
4441.59Skamil	memset(&info, 0, sizeof(info));
4451.59Skamil
4461.59Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
4471.59Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
4481.59Skamil	if (child == 0) {
4491.59Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
4501.59Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
4511.59Skamil
4521.59Skamil		DPRINTF("Before executing a trap\n");
4531.59Skamil		switch (sig) {
4541.59Skamil		case SIGTRAP:
4551.59Skamil			trigger_trap();
4561.59Skamil			break;
4571.59Skamil		case SIGSEGV:
4581.59Skamil			trigger_segv();
4591.59Skamil			break;
4601.59Skamil		case SIGILL:
4611.59Skamil			trigger_ill();
4621.59Skamil			break;
4631.59Skamil		case SIGFPE:
4641.59Skamil			trigger_fpe();
4651.59Skamil			break;
4661.59Skamil		case SIGBUS:
4671.59Skamil			trigger_bus();
4681.59Skamil			break;
4691.59Skamil		default:
4701.59Skamil			/* NOTREACHED */
4711.59Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
4721.59Skamil		}
4731.59Skamil
4741.59Skamil		/* NOTREACHED */
4751.59Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
4761.59Skamil	}
4771.59Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
4781.59Skamil
4791.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
4801.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
4811.59Skamil
4821.59Skamil	validate_status_stopped(status, sig);
4831.59Skamil
4841.59Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
4851.61Skre	SYSCALL_REQUIRE(
4861.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
4871.59Skamil
4881.59Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
4891.59Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
4901.61Skre	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
4911.61Skre	    info.psi_siginfo.si_errno);
4921.59Skamil
4931.59Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
4941.59Skamil	switch (sig) {
4951.59Skamil	case SIGTRAP:
4961.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
4971.59Skamil		break;
4981.59Skamil	case SIGSEGV:
4991.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
5001.59Skamil		break;
5011.71Skamil	case SIGILL:
5021.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
5031.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
5041.71Skamil		break;
5051.59Skamil	case SIGFPE:
5061.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
5071.59Skamil		break;
5081.59Skamil	case SIGBUS:
5091.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
5101.59Skamil		break;
5111.59Skamil	}
5121.59Skamil
5131.59Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
5141.59Skamil
5151.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5161.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
5171.59Skamil
5181.59Skamil	validate_status_signaled(status, SIGKILL, 0);
5191.59Skamil
5201.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5211.59Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
5221.59Skamil}
5231.59Skamil
5241.61Skre#define TRACEME_CRASH(test, sig)					\
5251.61SkreATF_TC(test);								\
5261.61SkreATF_TC_HEAD(test, tc)							\
5271.61Skre{									\
5281.61Skre	atf_tc_set_md_var(tc, "descr",					\
5291.61Skre	    "Verify crash signal " #sig " in a child after PT_TRACE_ME"); \
5301.61Skre}									\
5311.61Skre									\
5321.61SkreATF_TC_BODY(test, tc)							\
5331.61Skre{									\
5341.61Skre									\
5351.61Skre	traceme_crash(sig);						\
5361.59Skamil}
5371.59Skamil
5381.59SkamilTRACEME_CRASH(traceme_crash_trap, SIGTRAP)
5391.59SkamilTRACEME_CRASH(traceme_crash_segv, SIGSEGV)
5401.71SkamilTRACEME_CRASH(traceme_crash_ill, SIGILL)
5411.59SkamilTRACEME_CRASH(traceme_crash_fpe, SIGFPE)
5421.59SkamilTRACEME_CRASH(traceme_crash_bus, SIGBUS)
5431.59Skamil
5441.59Skamil/// ----------------------------------------------------------------------------
5451.59Skamil
5461.59Skamilstatic void
5471.88Skamiltraceme_signalmasked_crash(int sig)
5481.88Skamil{
5491.89Skamil	const int sigval = SIGSTOP;
5501.88Skamil	pid_t child, wpid;
5511.88Skamil#if defined(TWAIT_HAVE_STATUS)
5521.88Skamil	int status;
5531.88Skamil#endif
5541.88Skamil	struct ptrace_siginfo info;
5551.88Skamil	sigset_t intmask;
5561.89Skamil	struct kinfo_proc2 kp;
5571.89Skamil	size_t len = sizeof(kp);
5581.89Skamil
5591.89Skamil	int name[6];
5601.89Skamil	const size_t namelen = __arraycount(name);
5611.89Skamil	ki_sigset_t kp_sigmask;
5621.88Skamil
5631.88Skamil#ifndef PTRACE_ILLEGAL_ASM
5641.88Skamil	if (sig == SIGILL)
5651.88Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
5661.88Skamil#endif
5671.88Skamil
5681.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
5691.114Skamil		atf_tc_skip("FP exceptions are not supported");
5701.114Skamil
5711.88Skamil	memset(&info, 0, sizeof(info));
5721.88Skamil
5731.88Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
5741.88Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
5751.88Skamil	if (child == 0) {
5761.88Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
5771.88Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
5781.88Skamil
5791.88Skamil		sigemptyset(&intmask);
5801.88Skamil		sigaddset(&intmask, sig);
5811.88Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
5821.88Skamil
5831.89Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
5841.89Skamil		FORKEE_ASSERT(raise(sigval) == 0);
5851.89Skamil
5861.88Skamil		DPRINTF("Before executing a trap\n");
5871.88Skamil		switch (sig) {
5881.88Skamil		case SIGTRAP:
5891.88Skamil			trigger_trap();
5901.88Skamil			break;
5911.88Skamil		case SIGSEGV:
5921.88Skamil			trigger_segv();
5931.88Skamil			break;
5941.88Skamil		case SIGILL:
5951.88Skamil			trigger_ill();
5961.88Skamil			break;
5971.88Skamil		case SIGFPE:
5981.88Skamil			trigger_fpe();
5991.88Skamil			break;
6001.88Skamil		case SIGBUS:
6011.88Skamil			trigger_bus();
6021.88Skamil			break;
6031.88Skamil		default:
6041.88Skamil			/* NOTREACHED */
6051.88Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
6061.88Skamil		}
6071.88Skamil
6081.88Skamil		/* NOTREACHED */
6091.88Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
6101.88Skamil	}
6111.88Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
6121.88Skamil
6131.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6141.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
6151.88Skamil
6161.89Skamil	validate_status_stopped(status, sigval);
6171.89Skamil
6181.89Skamil	name[0] = CTL_KERN,
6191.89Skamil	name[1] = KERN_PROC2,
6201.89Skamil	name[2] = KERN_PROC_PID;
6211.89Skamil	name[3] = child;
6221.89Skamil	name[4] = sizeof(kp);
6231.89Skamil	name[5] = 1;
6241.89Skamil
6251.89Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
6261.89Skamil
6271.89Skamil	kp_sigmask = kp.p_sigmask;
6281.89Skamil
6291.89Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
6301.89Skamil	SYSCALL_REQUIRE(
6311.89Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
6321.89Skamil
6331.89Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
6341.89Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
6351.89Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
6361.89Skamil	    info.psi_siginfo.si_errno);
6371.89Skamil
6381.89Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
6391.89Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
6401.89Skamil
6411.89Skamil	DPRINTF("Before resuming the child process where it left off and "
6421.89Skamil	    "without signal to be sent\n");
6431.89Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
6441.89Skamil
6451.89Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6461.89Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
6471.89Skamil
6481.88Skamil	validate_status_stopped(status, sig);
6491.88Skamil
6501.88Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
6511.88Skamil	SYSCALL_REQUIRE(
6521.88Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
6531.88Skamil
6541.88Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
6551.88Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
6561.88Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
6571.88Skamil	    info.psi_siginfo.si_errno);
6581.88Skamil
6591.89Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
6601.89Skamil
6611.89Skamil	DPRINTF("kp_sigmask="
6621.89Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
6631.89Skamil	    kp_sigmask.__bits[0], kp_sigmask.__bits[1], kp_sigmask.__bits[2],
6641.89Skamil	    kp_sigmask.__bits[3]);
6651.89Skamil
6661.89Skamil	DPRINTF("kp.p_sigmask="
6671.89Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
6681.89Skamil	    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
6691.89Skamil	    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
6701.89Skamil
6711.89Skamil	ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask, sizeof(kp_sigmask)));
6721.89Skamil
6731.88Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
6741.88Skamil	switch (sig) {
6751.88Skamil	case SIGTRAP:
6761.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
6771.88Skamil		break;
6781.88Skamil	case SIGSEGV:
6791.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
6801.88Skamil		break;
6811.88Skamil	case SIGILL:
6821.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
6831.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
6841.88Skamil		break;
6851.88Skamil	case SIGFPE:
6861.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
6871.88Skamil		break;
6881.88Skamil	case SIGBUS:
6891.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
6901.88Skamil		break;
6911.88Skamil	}
6921.88Skamil
6931.88Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
6941.88Skamil
6951.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6961.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
6971.88Skamil
6981.88Skamil	validate_status_signaled(status, SIGKILL, 0);
6991.88Skamil
7001.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
7011.88Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
7021.88Skamil}
7031.88Skamil
7041.88Skamil#define TRACEME_SIGNALMASKED_CRASH(test, sig)				\
7051.88SkamilATF_TC(test);								\
7061.88SkamilATF_TC_HEAD(test, tc)							\
7071.88Skamil{									\
7081.88Skamil	atf_tc_set_md_var(tc, "descr",					\
7091.88Skamil	    "Verify masked crash signal " #sig " in a child after "	\
7101.88Skamil	    "PT_TRACE_ME is delivered to its tracer");			\
7111.88Skamil}									\
7121.88Skamil									\
7131.88SkamilATF_TC_BODY(test, tc)							\
7141.88Skamil{									\
7151.88Skamil									\
7161.88Skamil	traceme_signalmasked_crash(sig);				\
7171.88Skamil}
7181.88Skamil
7191.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_trap, SIGTRAP)
7201.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_segv, SIGSEGV)
7211.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_ill, SIGILL)
7221.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_fpe, SIGFPE)
7231.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_bus, SIGBUS)
7241.88Skamil
7251.88Skamil/// ----------------------------------------------------------------------------
7261.88Skamil
7271.88Skamilstatic void
7281.88Skamiltraceme_signalignored_crash(int sig)
7291.88Skamil{
7301.90Skamil	const int sigval = SIGSTOP;
7311.88Skamil	pid_t child, wpid;
7321.88Skamil#if defined(TWAIT_HAVE_STATUS)
7331.88Skamil	int status;
7341.88Skamil#endif
7351.88Skamil	struct sigaction sa;
7361.88Skamil	struct ptrace_siginfo info;
7371.90Skamil	struct kinfo_proc2 kp;
7381.90Skamil	size_t len = sizeof(kp);
7391.90Skamil
7401.90Skamil	int name[6];
7411.90Skamil	const size_t namelen = __arraycount(name);
7421.90Skamil	ki_sigset_t kp_sigignore;
7431.88Skamil
7441.88Skamil#ifndef PTRACE_ILLEGAL_ASM
7451.88Skamil	if (sig == SIGILL)
7461.88Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
7471.88Skamil#endif
7481.88Skamil
7491.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
7501.114Skamil		atf_tc_skip("FP exceptions are not supported");
7511.114Skamil
7521.88Skamil	memset(&info, 0, sizeof(info));
7531.88Skamil
7541.88Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
7551.88Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
7561.88Skamil	if (child == 0) {
7571.88Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
7581.88Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
7591.88Skamil
7601.88Skamil		memset(&sa, 0, sizeof(sa));
7611.88Skamil		sa.sa_handler = SIG_IGN;
7621.88Skamil		sigemptyset(&sa.sa_mask);
7631.88Skamil
7641.88Skamil		FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
7651.88Skamil
7661.90Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
7671.90Skamil		FORKEE_ASSERT(raise(sigval) == 0);
7681.90Skamil
7691.88Skamil		DPRINTF("Before executing a trap\n");
7701.88Skamil		switch (sig) {
7711.88Skamil		case SIGTRAP:
7721.88Skamil			trigger_trap();
7731.88Skamil			break;
7741.88Skamil		case SIGSEGV:
7751.88Skamil			trigger_segv();
7761.88Skamil			break;
7771.88Skamil		case SIGILL:
7781.88Skamil			trigger_ill();
7791.88Skamil			break;
7801.88Skamil		case SIGFPE:
7811.88Skamil			trigger_fpe();
7821.88Skamil			break;
7831.88Skamil		case SIGBUS:
7841.88Skamil			trigger_bus();
7851.88Skamil			break;
7861.88Skamil		default:
7871.88Skamil			/* NOTREACHED */
7881.88Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
7891.88Skamil		}
7901.88Skamil
7911.88Skamil		/* NOTREACHED */
7921.88Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
7931.88Skamil	}
7941.88Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
7951.88Skamil
7961.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
7971.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
7981.88Skamil
7991.90Skamil	validate_status_stopped(status, sigval);
8001.90Skamil
8011.90Skamil	name[0] = CTL_KERN,
8021.90Skamil	name[1] = KERN_PROC2,
8031.90Skamil	name[2] = KERN_PROC_PID;
8041.90Skamil	name[3] = child;
8051.90Skamil	name[4] = sizeof(kp);
8061.90Skamil	name[5] = 1;
8071.90Skamil
8081.90Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
8091.90Skamil
8101.90Skamil	kp_sigignore = kp.p_sigignore;
8111.90Skamil
8121.90Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
8131.90Skamil	SYSCALL_REQUIRE(
8141.90Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
8151.90Skamil
8161.90Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
8171.90Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
8181.90Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
8191.90Skamil	    info.psi_siginfo.si_errno);
8201.90Skamil
8211.90Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
8221.90Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
8231.90Skamil
8241.90Skamil	DPRINTF("Before resuming the child process where it left off and "
8251.90Skamil	    "without signal to be sent\n");
8261.90Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
8271.90Skamil
8281.90Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8291.90Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8301.90Skamil
8311.88Skamil	validate_status_stopped(status, sig);
8321.88Skamil
8331.88Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
8341.88Skamil	SYSCALL_REQUIRE(
8351.88Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
8361.88Skamil
8371.88Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
8381.88Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
8391.88Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
8401.88Skamil	    info.psi_siginfo.si_errno);
8411.88Skamil
8421.90Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
8431.90Skamil
8441.90Skamil	DPRINTF("kp_sigignore="
8451.90Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
8461.90Skamil	    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
8471.90Skamil	    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
8481.90Skamil
8491.90Skamil	DPRINTF("kp.p_sigignore="
8501.90Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
8511.90Skamil	    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
8521.90Skamil	    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
8531.90Skamil
8541.90Skamil	ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore, sizeof(kp_sigignore)));
8551.90Skamil
8561.88Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
8571.88Skamil	switch (sig) {
8581.88Skamil	case SIGTRAP:
8591.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
8601.88Skamil		break;
8611.88Skamil	case SIGSEGV:
8621.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
8631.88Skamil		break;
8641.88Skamil	case SIGILL:
8651.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
8661.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
8671.88Skamil		break;
8681.88Skamil	case SIGFPE:
8691.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
8701.88Skamil		break;
8711.88Skamil	case SIGBUS:
8721.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
8731.88Skamil		break;
8741.88Skamil	}
8751.88Skamil
8761.88Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
8771.88Skamil
8781.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8791.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8801.88Skamil
8811.88Skamil	validate_status_signaled(status, SIGKILL, 0);
8821.88Skamil
8831.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8841.88Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
8851.88Skamil}
8861.88Skamil
8871.88Skamil#define TRACEME_SIGNALIGNORED_CRASH(test, sig)				\
8881.88SkamilATF_TC(test);								\
8891.88SkamilATF_TC_HEAD(test, tc)							\
8901.88Skamil{									\
8911.88Skamil	atf_tc_set_md_var(tc, "descr",					\
8921.88Skamil	    "Verify ignored crash signal " #sig " in a child after "	\
8931.88Skamil	    "PT_TRACE_ME is delivered to its tracer"); 			\
8941.88Skamil}									\
8951.88Skamil									\
8961.88SkamilATF_TC_BODY(test, tc)							\
8971.88Skamil{									\
8981.88Skamil									\
8991.88Skamil	traceme_signalignored_crash(sig);				\
9001.88Skamil}
9011.88Skamil
9021.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_trap, SIGTRAP)
9031.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_segv, SIGSEGV)
9041.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_ill, SIGILL)
9051.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_fpe, SIGFPE)
9061.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_bus, SIGBUS)
9071.88Skamil
9081.88Skamil/// ----------------------------------------------------------------------------
9091.88Skamil
9101.88Skamilstatic void
9111.50Skamiltraceme_sendsignal_handle(int sigsent, void (*sah)(int a), int *traceme_caught)
9121.1Skamil{
9131.1Skamil	const int exitval = 5;
9141.34Skamil	const int sigval = SIGSTOP;
9151.1Skamil	pid_t child, wpid;
9161.1Skamil	struct sigaction sa;
9171.1Skamil#if defined(TWAIT_HAVE_STATUS)
9181.1Skamil	int status;
9191.1Skamil#endif
9201.61Skre	struct ptrace_siginfo info;
9211.1Skamil
9221.45Skamil	memset(&info, 0, sizeof(info));
9231.45Skamil
9241.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
9251.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
9261.1Skamil	if (child == 0) {
9271.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
9281.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
9291.1Skamil
9301.34Skamil		sa.sa_handler = sah;
9311.1Skamil		sa.sa_flags = SA_SIGINFO;
9321.1Skamil		sigemptyset(&sa.sa_mask);
9331.1Skamil
9341.1Skamil		FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
9351.1Skamil
9361.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
9371.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
9381.1Skamil
9391.34Skamil		FORKEE_ASSERT_EQ(*traceme_caught, 1);
9401.1Skamil
9411.13Schristos		DPRINTF("Before exiting of the child process\n");
9421.1Skamil		_exit(exitval);
9431.1Skamil	}
9441.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
9451.1Skamil
9461.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9471.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9481.1Skamil
9491.1Skamil	validate_status_stopped(status, sigval);
9501.1Skamil
9511.45Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
9521.61Skre	SYSCALL_REQUIRE(
9531.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
9541.45Skamil
9551.45Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
9561.45Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
9571.45Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
9581.45Skamil	    info.psi_siginfo.si_errno);
9591.45Skamil
9601.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
9611.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
9621.45Skamil
9631.13Schristos	DPRINTF("Before resuming the child process where it left off and with "
9641.1Skamil	    "signal %s to be sent\n", strsignal(sigsent));
9651.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
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_exited(status, exitval);
9711.1Skamil
9721.13Schristos	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
9731.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
9741.1Skamil}
9751.1Skamil
9761.61Skre#define TRACEME_SENDSIGNAL_HANDLE(test, sig)				\
9771.61SkreATF_TC(test);								\
9781.61SkreATF_TC_HEAD(test, tc)							\
9791.61Skre{									\
9801.61Skre	atf_tc_set_md_var(tc, "descr",					\
9811.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
9821.61Skre	    "handled correctly and caught by a signal handler");	\
9831.61Skre}									\
9841.61Skre									\
9851.61Skrestatic int test##_caught = 0;						\
9861.61Skre									\
9871.61Skrestatic void								\
9881.61Skretest##_sighandler(int arg)						\
9891.61Skre{									\
9901.61Skre	FORKEE_ASSERT_EQ(arg, sig);					\
9911.61Skre									\
9921.61Skre	++ test##_caught;						\
9931.61Skre}									\
9941.61Skre									\
9951.61SkreATF_TC_BODY(test, tc)							\
9961.61Skre{									\
9971.61Skre									\
9981.61Skre	traceme_sendsignal_handle(sig, test##_sighandler, & test##_caught); \
9991.34Skamil}
10001.34Skamil
10011.34Skamil// A signal handler for SIGKILL and SIGSTOP cannot be registered.
10021.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle1, SIGABRT) /* abort trap */
10031.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle2, SIGHUP)  /* hangup */
10041.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle3, SIGCONT) /* continued? */
10051.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle4, SIGTRAP) /* crash sig. */
10061.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle5, SIGBUS) /* crash sig. */
10071.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle6, SIGILL) /* crash sig. */
10081.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle7, SIGFPE) /* crash sig. */
10091.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle8, SIGSEGV) /* crash sig. */
10101.34Skamil
10111.34Skamil/// ----------------------------------------------------------------------------
10121.34Skamil
10131.35Skamilstatic void
10141.50Skamiltraceme_sendsignal_masked(int sigsent)
10151.50Skamil{
10161.50Skamil	const int exitval = 5;
10171.50Skamil	const int sigval = SIGSTOP;
10181.50Skamil	pid_t child, wpid;
10191.50Skamil	sigset_t set;
10201.50Skamil#if defined(TWAIT_HAVE_STATUS)
10211.50Skamil	int status;
10221.50Skamil#endif
10231.61Skre	struct ptrace_siginfo info;
10241.50Skamil
10251.50Skamil	memset(&info, 0, sizeof(info));
10261.50Skamil
10271.50Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
10281.50Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
10291.50Skamil	if (child == 0) {
10301.50Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
10311.50Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
10321.50Skamil
10331.50Skamil		sigemptyset(&set);
10341.50Skamil		sigaddset(&set, sigsent);
10351.50Skamil		FORKEE_ASSERT(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
10361.50Skamil
10371.50Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
10381.50Skamil		FORKEE_ASSERT(raise(sigval) == 0);
10391.50Skamil
10401.50Skamil		_exit(exitval);
10411.50Skamil	}
10421.50Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
10431.50Skamil
10441.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10451.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
10461.50Skamil
10471.50Skamil	validate_status_stopped(status, sigval);
10481.50Skamil
10491.50Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
10501.61Skre	SYSCALL_REQUIRE(
10511.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
10521.50Skamil
10531.50Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
10541.50Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
10551.50Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
10561.50Skamil	    info.psi_siginfo.si_errno);
10571.50Skamil
10581.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
10591.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
10601.50Skamil
10611.50Skamil	DPRINTF("Before resuming the child process where it left off and with "
10621.50Skamil	    "signal %s to be sent\n", strsignal(sigsent));
10631.50Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
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_exited(status, exitval);
10691.50Skamil
10701.50Skamil	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
10711.50Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
10721.50Skamil}
10731.50Skamil
10741.61Skre#define TRACEME_SENDSIGNAL_MASKED(test, sig)				\
10751.61SkreATF_TC(test);								\
10761.61SkreATF_TC_HEAD(test, tc)							\
10771.61Skre{									\
10781.61Skre	atf_tc_set_md_var(tc, "descr",					\
10791.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
10801.61Skre	    "handled correctly and the signal is masked by SIG_BLOCK");	\
10811.61Skre}									\
10821.61Skre									\
10831.61SkreATF_TC_BODY(test, tc)							\
10841.61Skre{									\
10851.61Skre									\
10861.61Skre	traceme_sendsignal_masked(sig);					\
10871.50Skamil}
10881.50Skamil
10891.50Skamil// A signal handler for SIGKILL and SIGSTOP cannot be masked.
10901.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked1, SIGABRT) /* abort trap */
10911.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked2, SIGHUP)  /* hangup */
10921.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked3, SIGCONT) /* continued? */
10931.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked4, SIGTRAP) /* crash sig. */
10941.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked5, SIGBUS) /* crash sig. */
10951.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked6, SIGILL) /* crash sig. */
10961.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked7, SIGFPE) /* crash sig. */
10971.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked8, SIGSEGV) /* crash sig. */
10981.50Skamil
10991.50Skamil/// ----------------------------------------------------------------------------
11001.50Skamil
11011.50Skamilstatic void
11021.50Skamiltraceme_sendsignal_ignored(int sigsent)
11031.50Skamil{
11041.50Skamil	const int exitval = 5;
11051.50Skamil	const int sigval = SIGSTOP;
11061.50Skamil	pid_t child, wpid;
11071.50Skamil	struct sigaction sa;
11081.50Skamil#if defined(TWAIT_HAVE_STATUS)
11091.50Skamil	int status;
11101.50Skamil#endif
11111.61Skre	struct ptrace_siginfo info;
11121.50Skamil
11131.50Skamil	memset(&info, 0, sizeof(info));
11141.50Skamil
11151.50Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
11161.50Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
11171.50Skamil	if (child == 0) {
11181.50Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
11191.61Skre
11201.50Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
11211.50Skamil
11221.50Skamil		memset(&sa, 0, sizeof(sa));
11231.50Skamil		sa.sa_handler = SIG_IGN;
11241.50Skamil		sigemptyset(&sa.sa_mask);
11251.50Skamil		FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
11261.50Skamil
11271.50Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
11281.50Skamil		FORKEE_ASSERT(raise(sigval) == 0);
11291.50Skamil
11301.50Skamil		_exit(exitval);
11311.50Skamil	}
11321.50Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
11331.50Skamil
11341.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11351.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11361.50Skamil
11371.50Skamil	validate_status_stopped(status, sigval);
11381.50Skamil
11391.50Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
11401.61Skre	SYSCALL_REQUIRE(
11411.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
11421.50Skamil
11431.50Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
11441.50Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
11451.50Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
11461.50Skamil	    info.psi_siginfo.si_errno);
11471.50Skamil
11481.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
11491.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
11501.50Skamil
11511.50Skamil	DPRINTF("Before resuming the child process where it left off and with "
11521.50Skamil	    "signal %s to be sent\n", strsignal(sigsent));
11531.50Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
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_exited(status, exitval);
11591.50Skamil
11601.50Skamil	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
11611.50Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
11621.50Skamil}
11631.50Skamil
11641.61Skre#define TRACEME_SENDSIGNAL_IGNORED(test, sig)				\
11651.61SkreATF_TC(test);								\
11661.61SkreATF_TC_HEAD(test, tc)							\
11671.61Skre{									\
11681.61Skre	atf_tc_set_md_var(tc, "descr",					\
11691.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
11701.61Skre	    "handled correctly and the signal is masked by SIG_IGN");	\
11711.61Skre}									\
11721.61Skre									\
11731.61SkreATF_TC_BODY(test, tc)							\
11741.61Skre{									\
11751.61Skre									\
11761.61Skre	traceme_sendsignal_ignored(sig);				\
11771.50Skamil}
11781.50Skamil
11791.50Skamil// A signal handler for SIGKILL and SIGSTOP cannot be ignored.
11801.61SkreTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored1, SIGABRT) /* abort */
11811.50SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored2, SIGHUP)  /* hangup */
11821.61SkreTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored3, SIGCONT) /* continued */
11831.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored4, SIGTRAP) /* crash s. */
11841.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored5, SIGBUS) /* crash s. */
11851.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored6, SIGILL) /* crash s. */
11861.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored7, SIGFPE) /* crash s. */
11871.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored8, SIGSEGV) /* crash s. */
11881.50Skamil
11891.50Skamil/// ----------------------------------------------------------------------------
11901.50Skamil
11911.50Skamilstatic void
11921.50Skamiltraceme_sendsignal_simple(int sigsent)
11931.1Skamil{
11941.35Skamil	const int sigval = SIGSTOP;
11951.35Skamil	int exitval = 0;
11961.1Skamil	pid_t child, wpid;
11971.1Skamil#if defined(TWAIT_HAVE_STATUS)
11981.1Skamil	int status;
11991.85Skamil	int expect_core;
12001.85Skamil
12011.85Skamil	switch (sigsent) {
12021.85Skamil	case SIGABRT:
12031.85Skamil	case SIGTRAP:
12041.85Skamil	case SIGBUS:
12051.85Skamil	case SIGILL:
12061.85Skamil	case SIGFPE:
12071.85Skamil	case SIGSEGV:
12081.85Skamil		expect_core = 1;
12091.85Skamil		break;
12101.85Skamil	default:
12111.85Skamil		expect_core = 0;
12121.85Skamil		break;
12131.85Skamil	}
12141.1Skamil#endif
12151.61Skre	struct ptrace_siginfo info;
12161.1Skamil
12171.45Skamil	memset(&info, 0, sizeof(info));
12181.45Skamil
12191.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
12201.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
12211.1Skamil	if (child == 0) {
12221.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
12231.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
12241.1Skamil
12251.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
12261.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
12271.1Skamil
12281.35Skamil		switch (sigsent) {
12291.35Skamil		case SIGCONT:
12301.48Skamil		case SIGSTOP:
12311.35Skamil			_exit(exitval);
12321.35Skamil		default:
12331.35Skamil			/* NOTREACHED */
12341.35Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
12351.35Skamil		}
12361.1Skamil	}
12371.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
12381.1Skamil
12391.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12401.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
12411.1Skamil
12421.1Skamil	validate_status_stopped(status, sigval);
12431.1Skamil
12441.45Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
12451.61Skre	SYSCALL_REQUIRE(
12461.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
12471.45Skamil
12481.45Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12491.45Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
12501.45Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12511.45Skamil	    info.psi_siginfo.si_errno);
12521.45Skamil
12531.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
12541.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
12551.45Skamil
12561.13Schristos	DPRINTF("Before resuming the child process where it left off and with "
12571.1Skamil	    "signal %s to be sent\n", strsignal(sigsent));
12581.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
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.35Skamil	switch (sigsent) {
12641.48Skamil	case SIGSTOP:
12651.48Skamil		validate_status_stopped(status, sigsent);
12661.48Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
12671.61Skre		    "child\n");
12681.48Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
12691.61Skre		    sizeof(info)) != -1);
12701.48Skamil
12711.48Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12721.48Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
12731.61Skre		    "si_errno=%#x\n",
12741.61Skre		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12751.61Skre		    info.psi_siginfo.si_errno);
12761.48Skamil
12771.48Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
12781.48Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
12791.48Skamil
12801.48Skamil		DPRINTF("Before resuming the child process where it left off "
12811.61Skre		    "and with signal %s to be sent\n", strsignal(sigsent));
12821.48Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
12831.48Skamil
12841.48Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12851.48Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
12861.61Skre		    child);
12871.48Skamil		/* FALLTHROUGH */
12881.35Skamil	case SIGCONT:
12891.35Skamil		validate_status_exited(status, exitval);
12901.35Skamil		break;
12911.35Skamil	default:
12921.35Skamil		validate_status_signaled(status, sigsent, expect_core);
12931.35Skamil		break;
12941.35Skamil	}
12951.1Skamil
12961.13Schristos	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
12971.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
12981.1Skamil}
12991.1Skamil
13001.61Skre#define TRACEME_SENDSIGNAL_SIMPLE(test, sig)				\
13011.61SkreATF_TC(test);								\
13021.61SkreATF_TC_HEAD(test, tc)							\
13031.61Skre{									\
13041.61Skre	atf_tc_set_md_var(tc, "descr",					\
13051.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
13061.61Skre	    "handled correctly in a child without a signal handler");	\
13071.61Skre}									\
13081.61Skre									\
13091.61SkreATF_TC_BODY(test, tc)							\
13101.61Skre{									\
13111.61Skre									\
13121.61Skre	traceme_sendsignal_simple(sig);					\
13131.35Skamil}
13141.35Skamil
13151.61SkreTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple1, SIGKILL) /* non-maskable*/
13161.61SkreTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple2, SIGSTOP) /* non-maskable*/
13171.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple3, SIGABRT) /* abort trap */
13181.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple4, SIGHUP)  /* hangup */
13191.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple5, SIGCONT) /* continued? */
13201.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple6, SIGTRAP) /* crash sig. */
13211.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple7, SIGBUS) /* crash sig. */
13221.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple8, SIGILL) /* crash sig. */
13231.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple9, SIGFPE) /* crash sig. */
13241.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple10, SIGSEGV) /* crash sig. */
13251.35Skamil
13261.35Skamil/// ----------------------------------------------------------------------------
13271.35Skamil
13281.37SkamilATF_TC(traceme_pid1_parent);
13291.37SkamilATF_TC_HEAD(traceme_pid1_parent, tc)
13301.37Skamil{
13311.37Skamil	atf_tc_set_md_var(tc, "descr",
13321.37Skamil	    "Verify that PT_TRACE_ME is not allowed when our parent is PID1");
13331.37Skamil}
13341.37Skamil
13351.37SkamilATF_TC_BODY(traceme_pid1_parent, tc)
13361.37Skamil{
13371.37Skamil	struct msg_fds parent_child;
13381.37Skamil	int exitval_child1 = 1, exitval_child2 = 2;
13391.37Skamil	pid_t child1, child2, wpid;
13401.37Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
13411.37Skamil#if defined(TWAIT_HAVE_STATUS)
13421.37Skamil	int status;
13431.37Skamil#endif
13441.37Skamil
13451.37Skamil	SYSCALL_REQUIRE(msg_open(&parent_child) == 0);
13461.37Skamil
13471.37Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
13481.37Skamil	SYSCALL_REQUIRE((child1 = fork()) != -1);
13491.37Skamil	if (child1 == 0) {
13501.37Skamil		DPRINTF("Before forking process PID=%d\n", getpid());
13511.37Skamil		SYSCALL_REQUIRE((child2 = fork()) != -1);
13521.37Skamil		if (child2 != 0) {
13531.37Skamil			DPRINTF("Parent process PID=%d, child2's PID=%d\n",
13541.61Skre			    getpid(), child2);
13551.37Skamil			_exit(exitval_child1);
13561.37Skamil		}
13571.37Skamil		CHILD_FROM_PARENT("exit child1", parent_child, msg);
13581.37Skamil
13591.37Skamil		DPRINTF("Assert that our parent is PID1 (initproc)\n");
13601.37Skamil		FORKEE_ASSERT_EQ(getppid(), 1);
13611.37Skamil
13621.37Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
13631.37Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) == -1);
13641.37Skamil		SYSCALL_REQUIRE_ERRNO(errno, EPERM);
13651.37Skamil
13661.37Skamil		CHILD_TO_PARENT("child2 exiting", parent_child, msg);
13671.37Skamil
13681.37Skamil		_exit(exitval_child2);
13691.37Skamil	}
13701.37Skamil	DPRINTF("Parent process PID=%d, child1's PID=%d\n", getpid(), child1);
13711.37Skamil
13721.37Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
13731.61Skre	TWAIT_REQUIRE_SUCCESS(
13741.61Skre	    wpid = TWAIT_GENERIC(child1, &status, WEXITED), child1);
13751.37Skamil
13761.37Skamil	validate_status_exited(status, exitval_child1);
13771.37Skamil
13781.37Skamil	DPRINTF("Notify that child1 is dead\n");
13791.37Skamil	PARENT_TO_CHILD("exit child1", parent_child, msg);
13801.37Skamil
13811.37Skamil	DPRINTF("Wait for exiting of child2\n");
13821.37Skamil	PARENT_FROM_CHILD("child2 exiting", parent_child, msg);
13831.37Skamil}
13841.37Skamil
13851.37Skamil/// ----------------------------------------------------------------------------
13861.37Skamil
13871.40Skamilstatic void
13881.40Skamiltraceme_vfork_raise(int sigval)
13891.40Skamil{
13901.46Skamil	const int exitval = 5, exitval_watcher = 10;
13911.46Skamil	pid_t child, parent, watcher, wpid;
13921.46Skamil	int rv;
13931.40Skamil#if defined(TWAIT_HAVE_STATUS)
13941.40Skamil	int status;
13951.85Skamil
13961.85Skamil	/* volatile workarounds GCC -Werror=clobbered */
13971.85Skamil	volatile int expect_core;
13981.85Skamil
13991.85Skamil	switch (sigval) {
14001.85Skamil	case SIGABRT:
14011.85Skamil	case SIGTRAP:
14021.85Skamil	case SIGBUS:
14031.85Skamil	case SIGILL:
14041.85Skamil	case SIGFPE:
14051.85Skamil	case SIGSEGV:
14061.85Skamil		expect_core = 1;
14071.85Skamil		break;
14081.85Skamil	default:
14091.85Skamil		expect_core = 0;
14101.85Skamil		break;
14111.85Skamil	}
14121.40Skamil#endif
14131.40Skamil
14141.46Skamil	/*
14151.46Skamil	 * Spawn a dedicated thread to watch for a stopped child and emit
14161.46Skamil	 * the SIGKILL signal to it.
14171.46Skamil	 *
14181.46Skamil	 * vfork(2) might clobber watcher, this means that it's safer and
14191.46Skamil	 * simpler to reparent this process to initproc and forget about it.
14201.46Skamil	 */
14211.46Skamil	if (sigval == SIGSTOP) {
14221.46Skamil		parent = getpid();
14231.46Skamil
14241.46Skamil		watcher = fork();
14251.46Skamil		ATF_REQUIRE(watcher != 1);
14261.46Skamil		if (watcher == 0) {
14271.46Skamil			/* Double fork(2) trick to reparent to initproc */
14281.46Skamil			watcher = fork();
14291.46Skamil			FORKEE_ASSERT_NEQ(watcher, -1);
14301.46Skamil			if (watcher != 0)
14311.46Skamil				_exit(exitval_watcher);
14321.46Skamil
14331.46Skamil			child = await_stopped_child(parent);
14341.46Skamil
14351.46Skamil			errno = 0;
14361.46Skamil			rv = kill(child, SIGKILL);
14371.46Skamil			FORKEE_ASSERT_EQ(rv, 0);
14381.46Skamil			FORKEE_ASSERT_EQ(errno, 0);
14391.46Skamil
14401.46Skamil			/* This exit value will be collected by initproc */
14411.46Skamil			_exit(0);
14421.46Skamil		}
14431.46Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14441.46Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(watcher, &status, 0),
14451.61Skre		    watcher);
14461.46Skamil
14471.46Skamil		validate_status_exited(status, exitval_watcher);
14481.46Skamil
14491.46Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14501.61Skre		TWAIT_REQUIRE_FAILURE(ECHILD,
14511.61Skre		    wpid = TWAIT_GENERIC(watcher, &status, 0));
14521.46Skamil	}
14531.46Skamil
14541.40Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
14551.40Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
14561.40Skamil	if (child == 0) {
14571.40Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
14581.40Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
14591.40Skamil
14601.40Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
14611.40Skamil		FORKEE_ASSERT(raise(sigval) == 0);
14621.40Skamil
14631.40Skamil		switch (sigval) {
14641.46Skamil		case SIGSTOP:
14651.40Skamil		case SIGKILL:
14661.40Skamil		case SIGABRT:
14671.40Skamil		case SIGHUP:
14681.85Skamil		case SIGTRAP:
14691.85Skamil		case SIGBUS:
14701.85Skamil		case SIGILL:
14711.85Skamil		case SIGFPE:
14721.85Skamil		case SIGSEGV:
14731.40Skamil			/* NOTREACHED */
14741.40Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
14751.70Smrg			__unreachable();
14761.40Skamil		default:
14771.40Skamil			DPRINTF("Before exiting of the child process\n");
14781.40Skamil			_exit(exitval);
14791.40Skamil		}
14801.40Skamil	}
14811.40Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
14821.40Skamil
14831.40Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14841.40Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
14851.40Skamil
14861.40Skamil	switch (sigval) {
14871.40Skamil	case SIGKILL:
14881.40Skamil	case SIGABRT:
14891.40Skamil	case SIGHUP:
14901.85Skamil	case SIGTRAP:
14911.85Skamil	case SIGBUS:
14921.85Skamil	case SIGILL:
14931.85Skamil	case SIGFPE:
14941.85Skamil	case SIGSEGV:
14951.40Skamil		validate_status_signaled(status, sigval, expect_core);
14961.40Skamil		break;
14971.40Skamil	case SIGSTOP:
14981.46Skamil		validate_status_signaled(status, SIGKILL, 0);
14991.46Skamil		break;
15001.40Skamil	case SIGCONT:
15011.47Skamil	case SIGTSTP:
15021.47Skamil	case SIGTTIN:
15031.47Skamil	case SIGTTOU:
15041.40Skamil		validate_status_exited(status, exitval);
15051.40Skamil		break;
15061.40Skamil	default:
15071.40Skamil		/* NOTREACHED */
15081.40Skamil		ATF_REQUIRE(0 && "NOT IMPLEMENTED");
15091.40Skamil		break;
15101.40Skamil	}
15111.40Skamil
15121.40Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15131.40Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
15141.40Skamil}
15151.40Skamil
15161.61Skre#define TRACEME_VFORK_RAISE(test, sig)					\
15171.61SkreATF_TC(test);								\
15181.61SkreATF_TC_HEAD(test, tc)							\
15191.61Skre{									\
15201.61Skre	atf_tc_set_md_var(tc, "descr",					\
15211.61Skre	    "Verify PT_TRACE_ME followed by raise of " #sig " in a "	\
15221.61Skre	    "vfork(2)ed child");					\
15231.61Skre}									\
15241.61Skre									\
15251.61SkreATF_TC_BODY(test, tc)							\
15261.61Skre{									\
15271.61Skre									\
15281.61Skre	traceme_vfork_raise(sig);					\
15291.40Skamil}
15301.40Skamil
15311.40SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise1, SIGKILL) /* non-maskable */
15321.46SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise2, SIGSTOP) /* non-maskable */
15331.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise3, SIGTSTP) /* ignored in vfork(2) */
15341.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise4, SIGTTIN) /* ignored in vfork(2) */
15351.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise5, SIGTTOU) /* ignored in vfork(2) */
15361.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise6, SIGABRT) /* regular abort trap */
15371.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise7, SIGHUP)  /* hangup */
15381.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise8, SIGCONT) /* continued? */
15391.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise9, SIGTRAP) /* crash signal */
15401.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise10, SIGBUS) /* crash signal */
15411.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise11, SIGILL) /* crash signal */
15421.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise12, SIGFPE) /* crash signal */
15431.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise13, SIGSEGV) /* crash signal */
15441.40Skamil
15451.40Skamil/// ----------------------------------------------------------------------------
15461.40Skamil
15471.52Skamilstatic void
15481.52Skamiltraceme_vfork_crash(int sig)
15491.41Skamil{
15501.41Skamil	pid_t child, wpid;
15511.41Skamil#if defined(TWAIT_HAVE_STATUS)
15521.41Skamil	int status;
15531.41Skamil#endif
15541.41Skamil
15551.71Skamil#ifndef PTRACE_ILLEGAL_ASM
15561.71Skamil	if (sig == SIGILL)
15571.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
15581.71Skamil#endif
15591.71Skamil
15601.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
15611.114Skamil		atf_tc_skip("FP exceptions are not supported");
15621.114Skamil
15631.41Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
15641.41Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
15651.41Skamil	if (child == 0) {
15661.41Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
15671.41Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
15681.41Skamil
15691.52Skamil		DPRINTF("Before executing a trap\n");
15701.52Skamil		switch (sig) {
15711.52Skamil		case SIGTRAP:
15721.52Skamil			trigger_trap();
15731.52Skamil			break;
15741.52Skamil		case SIGSEGV:
15751.52Skamil			trigger_segv();
15761.52Skamil			break;
15771.52Skamil		case SIGILL:
15781.52Skamil			trigger_ill();
15791.52Skamil			break;
15801.52Skamil		case SIGFPE:
15811.52Skamil			trigger_fpe();
15821.52Skamil			break;
15831.52Skamil		case SIGBUS:
15841.52Skamil			trigger_bus();
15851.52Skamil			break;
15861.52Skamil		default:
15871.52Skamil			/* NOTREACHED */
15881.52Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
15891.52Skamil		}
15901.41Skamil
15911.41Skamil		/* NOTREACHED */
15921.41Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
15931.41Skamil	}
15941.41Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
15951.41Skamil
15961.41Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15971.41Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
15981.41Skamil
15991.52Skamil	validate_status_signaled(status, sig, 1);
16001.41Skamil
16011.41Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16021.41Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
16031.41Skamil}
16041.41Skamil
16051.61Skre#define TRACEME_VFORK_CRASH(test, sig)					\
16061.61SkreATF_TC(test);								\
16071.61SkreATF_TC_HEAD(test, tc)							\
16081.61Skre{									\
16091.61Skre	atf_tc_set_md_var(tc, "descr",					\
16101.61Skre	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
16111.61Skre	    "vfork(2)ed child");					\
16121.61Skre}									\
16131.61Skre									\
16141.61SkreATF_TC_BODY(test, tc)							\
16151.61Skre{									\
16161.61Skre									\
16171.61Skre	traceme_vfork_crash(sig);					\
16181.52Skamil}
16191.52Skamil
16201.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_trap, SIGTRAP)
16211.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_segv, SIGSEGV)
16221.71SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_ill, SIGILL)
16231.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_fpe, SIGFPE)
16241.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_bus, SIGBUS)
16251.52Skamil
16261.41Skamil/// ----------------------------------------------------------------------------
16271.41Skamil
16281.92Skamilstatic void
16291.92Skamiltraceme_vfork_signalmasked_crash(int sig)
16301.92Skamil{
16311.92Skamil	pid_t child, wpid;
16321.92Skamil#if defined(TWAIT_HAVE_STATUS)
16331.92Skamil	int status;
16341.92Skamil#endif
16351.92Skamil	sigset_t intmask;
16361.92Skamil
16371.92Skamil#ifndef PTRACE_ILLEGAL_ASM
16381.92Skamil	if (sig == SIGILL)
16391.92Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
16401.92Skamil#endif
16411.92Skamil
16421.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
16431.114Skamil		atf_tc_skip("FP exceptions are not supported");
16441.114Skamil
16451.92Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
16461.92Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
16471.92Skamil	if (child == 0) {
16481.92Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
16491.92Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
16501.92Skamil
16511.92Skamil		sigemptyset(&intmask);
16521.92Skamil		sigaddset(&intmask, sig);
16531.92Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
16541.92Skamil
16551.92Skamil		DPRINTF("Before executing a trap\n");
16561.92Skamil		switch (sig) {
16571.92Skamil		case SIGTRAP:
16581.92Skamil			trigger_trap();
16591.92Skamil			break;
16601.92Skamil		case SIGSEGV:
16611.92Skamil			trigger_segv();
16621.92Skamil			break;
16631.92Skamil		case SIGILL:
16641.92Skamil			trigger_ill();
16651.92Skamil			break;
16661.92Skamil		case SIGFPE:
16671.92Skamil			trigger_fpe();
16681.92Skamil			break;
16691.92Skamil		case SIGBUS:
16701.92Skamil			trigger_bus();
16711.92Skamil			break;
16721.92Skamil		default:
16731.92Skamil			/* NOTREACHED */
16741.92Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
16751.92Skamil		}
16761.92Skamil
16771.92Skamil		/* NOTREACHED */
16781.92Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
16791.92Skamil	}
16801.92Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
16811.92Skamil
16821.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16831.92Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
16841.92Skamil
16851.92Skamil	validate_status_signaled(status, sig, 1);
16861.92Skamil
16871.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16881.92Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
16891.92Skamil}
16901.92Skamil
16911.92Skamil#define TRACEME_VFORK_SIGNALMASKED_CRASH(test, sig)			\
16921.92SkamilATF_TC(test);								\
16931.92SkamilATF_TC_HEAD(test, tc)							\
16941.92Skamil{									\
16951.92Skamil	atf_tc_set_md_var(tc, "descr",					\
16961.92Skamil	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
16971.92Skamil	    "vfork(2)ed child with a masked signal");			\
16981.92Skamil}									\
16991.92Skamil									\
17001.92SkamilATF_TC_BODY(test, tc)							\
17011.92Skamil{									\
17021.92Skamil									\
17031.92Skamil	traceme_vfork_signalmasked_crash(sig);				\
17041.92Skamil}
17051.92Skamil
17061.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_trap, SIGTRAP)
17071.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_segv, SIGSEGV)
17081.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_ill, SIGILL)
17091.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_fpe, SIGFPE)
17101.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_bus, SIGBUS)
17111.92Skamil
17121.92Skamil/// ----------------------------------------------------------------------------
17131.92Skamil
17141.92Skamilstatic void
17151.92Skamiltraceme_vfork_signalignored_crash(int sig)
17161.92Skamil{
17171.92Skamil	pid_t child, wpid;
17181.92Skamil#if defined(TWAIT_HAVE_STATUS)
17191.92Skamil	int status;
17201.92Skamil#endif
17211.92Skamil	struct sigaction sa;
17221.92Skamil
17231.92Skamil#ifndef PTRACE_ILLEGAL_ASM
17241.92Skamil	if (sig == SIGILL)
17251.92Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
17261.92Skamil#endif
17271.92Skamil
17281.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
17291.114Skamil		atf_tc_skip("FP exceptions are not supported");
17301.114Skamil
17311.92Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
17321.92Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
17331.92Skamil	if (child == 0) {
17341.92Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
17351.92Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
17361.92Skamil
17371.92Skamil		memset(&sa, 0, sizeof(sa));
17381.92Skamil		sa.sa_handler = SIG_IGN;
17391.92Skamil		sigemptyset(&sa.sa_mask);
17401.92Skamil
17411.92Skamil		FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
17421.92Skamil
17431.92Skamil		DPRINTF("Before executing a trap\n");
17441.92Skamil		switch (sig) {
17451.92Skamil		case SIGTRAP:
17461.92Skamil			trigger_trap();
17471.92Skamil			break;
17481.92Skamil		case SIGSEGV:
17491.92Skamil			trigger_segv();
17501.92Skamil			break;
17511.92Skamil		case SIGILL:
17521.92Skamil			trigger_ill();
17531.92Skamil			break;
17541.92Skamil		case SIGFPE:
17551.92Skamil			trigger_fpe();
17561.92Skamil			break;
17571.92Skamil		case SIGBUS:
17581.92Skamil			trigger_bus();
17591.92Skamil			break;
17601.92Skamil		default:
17611.92Skamil			/* NOTREACHED */
17621.92Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
17631.92Skamil		}
17641.92Skamil
17651.92Skamil		/* NOTREACHED */
17661.92Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
17671.92Skamil	}
17681.92Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
17691.92Skamil
17701.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17711.92Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17721.92Skamil
17731.92Skamil	validate_status_signaled(status, sig, 1);
17741.92Skamil
17751.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17761.92Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
17771.92Skamil}
17781.92Skamil
17791.92Skamil#define TRACEME_VFORK_SIGNALIGNORED_CRASH(test, sig)			\
17801.92SkamilATF_TC(test);								\
17811.92SkamilATF_TC_HEAD(test, tc)							\
17821.92Skamil{									\
17831.92Skamil	atf_tc_set_md_var(tc, "descr",					\
17841.92Skamil	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
17851.92Skamil	    "vfork(2)ed child with ignored signal");			\
17861.92Skamil}									\
17871.92Skamil									\
17881.92SkamilATF_TC_BODY(test, tc)							\
17891.92Skamil{									\
17901.92Skamil									\
17911.92Skamil	traceme_vfork_signalignored_crash(sig);				\
17921.92Skamil}
17931.92Skamil
17941.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_trap,
17951.92Skamil    SIGTRAP)
17961.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_segv,
17971.92Skamil    SIGSEGV)
17981.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_ill,
17991.92Skamil    SIGILL)
18001.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_fpe,
18011.92Skamil    SIGFPE)
18021.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_bus,
18031.92Skamil    SIGBUS)
18041.92Skamil
18051.92Skamil/// ----------------------------------------------------------------------------
18061.92Skamil
18071.96Skamilstatic void
18081.96Skamiltraceme_vfork_exec(bool masked, bool ignored)
18091.43Skamil{
18101.43Skamil	const int sigval = SIGTRAP;
18111.43Skamil	pid_t child, wpid;
18121.43Skamil#if defined(TWAIT_HAVE_STATUS)
18131.43Skamil	int status;
18141.43Skamil#endif
18151.96Skamil	struct sigaction sa;
18161.61Skre	struct ptrace_siginfo info;
18171.96Skamil	sigset_t intmask;
18181.96Skamil	struct kinfo_proc2 kp;
18191.96Skamil	size_t len = sizeof(kp);
18201.96Skamil
18211.96Skamil	int name[6];
18221.96Skamil	const size_t namelen = __arraycount(name);
18231.96Skamil	ki_sigset_t kp_sigmask;
18241.96Skamil	ki_sigset_t kp_sigignore;
18251.43Skamil
18261.43Skamil	memset(&info, 0, sizeof(info));
18271.43Skamil
18281.43Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
18291.43Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
18301.43Skamil	if (child == 0) {
18311.43Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
18321.43Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
18331.43Skamil
18341.96Skamil		if (masked) {
18351.96Skamil			sigemptyset(&intmask);
18361.96Skamil			sigaddset(&intmask, sigval);
18371.96Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
18381.96Skamil		}
18391.96Skamil
18401.96Skamil		if (ignored) {
18411.96Skamil			memset(&sa, 0, sizeof(sa));
18421.96Skamil			sa.sa_handler = SIG_IGN;
18431.96Skamil			sigemptyset(&sa.sa_mask);
18441.96Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
18451.96Skamil		}
18461.96Skamil
18471.43Skamil		DPRINTF("Before calling execve(2) from child\n");
18481.43Skamil		execlp("/bin/echo", "/bin/echo", NULL);
18491.43Skamil
18501.43Skamil		/* NOTREACHED */
18511.43Skamil		FORKEE_ASSERTX(0 && "Not reached");
18521.43Skamil	}
18531.43Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
18541.43Skamil
18551.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18561.43Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
18571.43Skamil
18581.43Skamil	validate_status_stopped(status, sigval);
18591.43Skamil
18601.96Skamil	name[0] = CTL_KERN,
18611.96Skamil	name[1] = KERN_PROC2,
18621.96Skamil	name[2] = KERN_PROC_PID;
18631.96Skamil	name[3] = getpid();
18641.96Skamil	name[4] = sizeof(kp);
18651.96Skamil	name[5] = 1;
18661.96Skamil
18671.96Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
18681.96Skamil
18691.96Skamil	if (masked)
18701.96Skamil		kp_sigmask = kp.p_sigmask;
18711.96Skamil
18721.96Skamil	if (ignored)
18731.96Skamil		kp_sigignore = kp.p_sigignore;
18741.96Skamil
18751.96Skamil	name[3] = getpid();
18761.96Skamil
18771.96Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
18781.96Skamil
18791.96Skamil	if (masked) {
18801.96Skamil		DPRINTF("kp_sigmask="
18811.96Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
18821.96Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
18831.96Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
18841.96Skamil
18851.96Skamil	        DPRINTF("kp.p_sigmask="
18861.96Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
18871.96Skamil	            kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
18881.96Skamil	            kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
18891.96Skamil
18901.96Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
18911.96Skamil		    sizeof(kp_sigmask)));
18921.96Skamil	}
18931.96Skamil
18941.96Skamil	if (ignored) {
18951.96Skamil		DPRINTF("kp_sigignore="
18961.96Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
18971.96Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
18981.96Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
18991.96Skamil
19001.96Skamil	        DPRINTF("kp.p_sigignore="
19011.96Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19021.96Skamil	            kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
19031.96Skamil	            kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
19041.96Skamil
19051.96Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
19061.96Skamil		    sizeof(kp_sigignore)));
19071.96Skamil	}
19081.96Skamil
19091.43Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
19101.61Skre	SYSCALL_REQUIRE(
19111.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
19121.43Skamil
19131.43Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
19141.43Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
19151.43Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
19161.43Skamil	    info.psi_siginfo.si_errno);
19171.43Skamil
19181.43Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
19191.43Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
19201.43Skamil
19211.43Skamil	DPRINTF("Before resuming the child process where it left off and "
19221.43Skamil	    "without signal to be sent\n");
19231.43Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
19241.43Skamil
19251.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
19261.43Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
19271.43Skamil
19281.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
19291.43Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
19301.43Skamil}
19311.43Skamil
19321.96Skamil#define TRACEME_VFORK_EXEC(test, masked, ignored)			\
19331.96SkamilATF_TC(test);								\
19341.96SkamilATF_TC_HEAD(test, tc)							\
19351.96Skamil{									\
19361.96Skamil	atf_tc_set_md_var(tc, "descr",					\
19371.96Skamil	    "Verify PT_TRACE_ME followed by exec(3) in a vfork(2)ed "	\
19381.96Skamil	    "child%s%s", masked ? " with masked signal" : "",		\
19391.96Skamil	    masked ? " with ignored signal" : "");			\
19401.96Skamil}									\
19411.96Skamil									\
19421.96SkamilATF_TC_BODY(test, tc)							\
19431.96Skamil{									\
19441.96Skamil									\
19451.96Skamil	traceme_vfork_exec(masked, ignored);				\
19461.96Skamil}
19471.96Skamil
19481.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_exec, false, false)
19491.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalmasked_exec, true, false)
19501.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalignored_exec, false, true)
19511.96Skamil
19521.43Skamil/// ----------------------------------------------------------------------------
19531.43Skamil
19541.1Skamil#if defined(TWAIT_HAVE_PID)
19551.51Skamilstatic void
19561.94Skamilunrelated_tracer_sees_crash(int sig, bool masked, bool ignored)
19571.59Skamil{
19581.94Skamil	const int sigval = SIGSTOP;
19591.59Skamil	struct msg_fds parent_tracee, parent_tracer;
19601.59Skamil	const int exitval = 10;
19611.59Skamil	pid_t tracee, tracer, wpid;
19621.59Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
19631.59Skamil#if defined(TWAIT_HAVE_STATUS)
19641.59Skamil	int status;
19651.59Skamil#endif
19661.94Skamil	struct sigaction sa;
19671.59Skamil	struct ptrace_siginfo info;
19681.94Skamil	sigset_t intmask;
19691.94Skamil	struct kinfo_proc2 kp;
19701.94Skamil	size_t len = sizeof(kp);
19711.94Skamil
19721.94Skamil	int name[6];
19731.94Skamil	const size_t namelen = __arraycount(name);
19741.94Skamil	ki_sigset_t kp_sigmask;
19751.94Skamil	ki_sigset_t kp_sigignore;
19761.61Skre
19771.71Skamil#ifndef PTRACE_ILLEGAL_ASM
19781.71Skamil	if (sig == SIGILL)
19791.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
19801.71Skamil#endif
19811.71Skamil
19821.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
19831.114Skamil		atf_tc_skip("FP exceptions are not supported");
19841.114Skamil
19851.59Skamil	memset(&info, 0, sizeof(info));
19861.59Skamil
19871.59Skamil	DPRINTF("Spawn tracee\n");
19881.59Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
19891.59Skamil	tracee = atf_utils_fork();
19901.59Skamil	if (tracee == 0) {
19911.59Skamil		// Wait for parent to let us crash
19921.59Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
19931.61Skre
19941.94Skamil		if (masked) {
19951.94Skamil			sigemptyset(&intmask);
19961.94Skamil			sigaddset(&intmask, sig);
19971.94Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
19981.94Skamil		}
19991.94Skamil
20001.94Skamil		if (ignored) {
20011.94Skamil			memset(&sa, 0, sizeof(sa));
20021.94Skamil			sa.sa_handler = SIG_IGN;
20031.94Skamil			sigemptyset(&sa.sa_mask);
20041.94Skamil			FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
20051.94Skamil		}
20061.94Skamil
20071.94Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
20081.94Skamil		FORKEE_ASSERT(raise(sigval) == 0);
20091.94Skamil
20101.59Skamil		DPRINTF("Before executing a trap\n");
20111.59Skamil		switch (sig) {
20121.59Skamil		case SIGTRAP:
20131.59Skamil			trigger_trap();
20141.59Skamil			break;
20151.59Skamil		case SIGSEGV:
20161.59Skamil			trigger_segv();
20171.59Skamil			break;
20181.59Skamil		case SIGILL:
20191.59Skamil			trigger_ill();
20201.59Skamil			break;
20211.59Skamil		case SIGFPE:
20221.59Skamil			trigger_fpe();
20231.59Skamil			break;
20241.59Skamil		case SIGBUS:
20251.59Skamil			trigger_bus();
20261.59Skamil			break;
20271.59Skamil		default:
20281.59Skamil			/* NOTREACHED */
20291.59Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
20301.59Skamil		}
20311.59Skamil
20321.59Skamil		/* NOTREACHED */
20331.59Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
20341.59Skamil	}
20351.59Skamil
20361.59Skamil	DPRINTF("Spawn debugger\n");
20371.59Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
20381.59Skamil	tracer = atf_utils_fork();
20391.59Skamil	if (tracer == 0) {
20401.59Skamil		/* Fork again and drop parent to reattach to PID 1 */
20411.59Skamil		tracer = atf_utils_fork();
20421.59Skamil		if (tracer != 0)
20431.61Skre			_exit(exitval);
20441.59Skamil
20451.59Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
20461.59Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
20471.59Skamil
20481.59Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
20491.59Skamil		FORKEE_REQUIRE_SUCCESS(
20501.59Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
20511.59Skamil
20521.59Skamil		forkee_status_stopped(status, SIGSTOP);
20531.59Skamil
20541.94Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
20551.94Skamil		    "traced process\n");
20561.94Skamil		SYSCALL_REQUIRE(
20571.94Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
20581.94Skamil
20591.94Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
20601.94Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
20611.94Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
20621.94Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
20631.94Skamil
20641.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
20651.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
20661.94Skamil
20671.59Skamil		/* Resume tracee with PT_CONTINUE */
20681.59Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
20691.59Skamil
20701.59Skamil		/* Inform parent that tracer has attached to tracee */
20711.59Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
20721.59Skamil
20731.59Skamil		/* Wait for parent to tell use that tracee should have exited */
20741.59Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
20751.59Skamil
20761.59Skamil		/* Wait for tracee and assert that it exited */
20771.59Skamil		FORKEE_REQUIRE_SUCCESS(
20781.59Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
20791.59Skamil
20801.94Skamil		forkee_status_stopped(status, sigval);
20811.94Skamil
20821.94Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
20831.94Skamil		    "traced process\n");
20841.94Skamil		SYSCALL_REQUIRE(
20851.94Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
20861.94Skamil
20871.94Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
20881.94Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
20891.94Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
20901.94Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
20911.94Skamil
20921.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
20931.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
20941.94Skamil
20951.94Skamil		name[0] = CTL_KERN,
20961.94Skamil		name[1] = KERN_PROC2,
20971.94Skamil		name[2] = KERN_PROC_PID;
20981.94Skamil		name[3] = tracee;
20991.94Skamil		name[4] = sizeof(kp);
21001.94Skamil		name[5] = 1;
21011.94Skamil
21021.94Skamil		FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
21031.94Skamil
21041.94Skamil		if (masked)
21051.94Skamil			kp_sigmask = kp.p_sigmask;
21061.94Skamil
21071.94Skamil		if (ignored)
21081.94Skamil			kp_sigignore = kp.p_sigignore;
21091.94Skamil
21101.94Skamil		/* Resume tracee with PT_CONTINUE */
21111.94Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
21121.94Skamil
21131.94Skamil		/* Wait for tracee and assert that it exited */
21141.94Skamil		FORKEE_REQUIRE_SUCCESS(
21151.94Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
21161.94Skamil
21171.93Skamil		forkee_status_stopped(status, sig);
21181.59Skamil
21191.59Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
21201.61Skre		    "traced process\n");
21211.61Skre		SYSCALL_REQUIRE(
21221.61Skre		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
21231.59Skamil
21241.59Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
21251.59Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
21261.61Skre		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
21271.61Skre		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
21281.59Skamil
21291.93Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sig);
21301.94Skamil
21311.94Skamil		FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
21321.94Skamil
21331.94Skamil		if (masked) {
21341.94Skamil			DPRINTF("kp_sigmask="
21351.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21361.94Skamil			    PRIx32 "\n",
21371.94Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
21381.94Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
21391.94Skamil
21401.94Skamil			DPRINTF("kp.p_sigmask="
21411.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21421.94Skamil			    PRIx32 "\n",
21431.94Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
21441.94Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
21451.94Skamil
21461.94Skamil			FORKEE_ASSERTX(!memcmp(&kp_sigmask, &kp.p_sigmask,
21471.94Skamil			    sizeof(kp_sigmask)));
21481.94Skamil		}
21491.94Skamil
21501.94Skamil		if (ignored) {
21511.94Skamil			DPRINTF("kp_sigignore="
21521.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21531.94Skamil			    PRIx32 "\n",
21541.94Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
21551.94Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
21561.94Skamil
21571.94Skamil			DPRINTF("kp.p_sigignore="
21581.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21591.94Skamil			    PRIx32 "\n",
21601.94Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
21611.94Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
21621.94Skamil
21631.94Skamil			FORKEE_ASSERTX(!memcmp(&kp_sigignore, &kp.p_sigignore,
21641.94Skamil			    sizeof(kp_sigignore)));
21651.94Skamil		}
21661.94Skamil
21671.59Skamil		switch (sig) {
21681.59Skamil		case SIGTRAP:
21691.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
21701.59Skamil			break;
21711.59Skamil		case SIGSEGV:
21721.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
21731.59Skamil			break;
21741.71Skamil		case SIGILL:
21751.113Skamil			FORKEE_ASSERT(info.psi_siginfo.si_code >= ILL_ILLOPC &&
21761.112Skamil			            info.psi_siginfo.si_code <= ILL_BADSTK);
21771.71Skamil			break;
21781.59Skamil		case SIGFPE:
21791.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
21801.59Skamil			break;
21811.59Skamil		case SIGBUS:
21821.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
21831.59Skamil			break;
21841.59Skamil		}
21851.59Skamil
21861.59Skamil		FORKEE_ASSERT(ptrace(PT_KILL, tracee, NULL, 0) != -1);
21871.59Skamil		DPRINTF("Before calling %s() for the tracee\n", TWAIT_FNAME);
21881.93Skamil		FORKEE_REQUIRE_SUCCESS(
21891.61Skre		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
21901.59Skamil
21911.93Skamil		forkee_status_signaled(status, SIGKILL, 0);
21921.59Skamil
21931.71Skamil		/* Inform parent that tracer is exiting normally */
21941.71Skamil		CHILD_TO_PARENT("tracer done", parent_tracer, msg);
21951.71Skamil
21961.59Skamil		DPRINTF("Before exiting of the tracer process\n");
21971.59Skamil		_exit(0 /* collect by initproc */);
21981.59Skamil	}
21991.59Skamil
22001.59Skamil	DPRINTF("Wait for the tracer process (direct child) to exit "
22011.59Skamil	    "calling %s()\n", TWAIT_FNAME);
22021.59Skamil	TWAIT_REQUIRE_SUCCESS(
22031.59Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
22041.59Skamil
22051.59Skamil	validate_status_exited(status, exitval);
22061.59Skamil
22071.59Skamil	DPRINTF("Wait for the non-exited tracee process with %s()\n",
22081.59Skamil	    TWAIT_FNAME);
22091.59Skamil	TWAIT_REQUIRE_SUCCESS(
22101.59Skamil	    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
22111.59Skamil
22121.59Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
22131.59Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
22141.59Skamil
22151.59Skamil	DPRINTF("Resume the tracee and let it crash\n");
22161.59Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
22171.59Skamil
22181.59Skamil	DPRINTF("Resume the tracer and let it detect crashed tracee\n");
22191.59Skamil	PARENT_TO_CHILD("Message 2", parent_tracer, msg);
22201.59Skamil
22211.59Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
22221.59Skamil	    TWAIT_FNAME);
22231.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
22241.59Skamil
22251.59Skamil	validate_status_signaled(status, SIGKILL, 0);
22261.59Skamil
22271.71Skamil	DPRINTF("Await normal exit of tracer\n");
22281.71Skamil	PARENT_FROM_CHILD("tracer done", parent_tracer, msg);
22291.71Skamil
22301.59Skamil	msg_close(&parent_tracer);
22311.59Skamil	msg_close(&parent_tracee);
22321.59Skamil}
22331.59Skamil
22341.61Skre#define UNRELATED_TRACER_SEES_CRASH(test, sig)				\
22351.61SkreATF_TC(test);								\
22361.61SkreATF_TC_HEAD(test, tc)							\
22371.61Skre{									\
22381.61Skre	atf_tc_set_md_var(tc, "descr",					\
22391.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
22401.94Skamil	    "the debuggee");						\
22411.61Skre}									\
22421.61Skre									\
22431.61SkreATF_TC_BODY(test, tc)							\
22441.61Skre{									\
22451.61Skre									\
22461.94Skamil	unrelated_tracer_sees_crash(sig, false, false);			\
22471.59Skamil}
22481.59Skamil
22491.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_trap, SIGTRAP)
22501.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_segv, SIGSEGV)
22511.71SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_ill, SIGILL)
22521.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_fpe, SIGFPE)
22531.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_bus, SIGBUS)
22541.94Skamil
22551.94Skamil#define UNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(test, sig)		\
22561.94SkamilATF_TC(test);								\
22571.94SkamilATF_TC_HEAD(test, tc)							\
22581.94Skamil{									\
22591.94Skamil	atf_tc_set_md_var(tc, "descr",					\
22601.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
22611.94Skamil	    "the debuggee with masked signal");				\
22621.94Skamil}									\
22631.94Skamil									\
22641.94SkamilATF_TC_BODY(test, tc)							\
22651.94Skamil{									\
22661.94Skamil									\
22671.94Skamil	unrelated_tracer_sees_crash(sig, true, false);			\
22681.94Skamil}
22691.94Skamil
22701.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22711.94Skamil    unrelated_tracer_sees_signalmasked_crash_trap, SIGTRAP)
22721.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22731.94Skamil    unrelated_tracer_sees_signalmasked_crash_segv, SIGSEGV)
22741.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22751.94Skamil    unrelated_tracer_sees_signalmasked_crash_ill, SIGILL)
22761.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22771.94Skamil    unrelated_tracer_sees_signalmasked_crash_fpe, SIGFPE)
22781.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22791.94Skamil    unrelated_tracer_sees_signalmasked_crash_bus, SIGBUS)
22801.94Skamil
22811.94Skamil#define UNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(test, sig)		\
22821.94SkamilATF_TC(test);								\
22831.94SkamilATF_TC_HEAD(test, tc)							\
22841.94Skamil{									\
22851.94Skamil	atf_tc_set_md_var(tc, "descr",					\
22861.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
22871.94Skamil	    "the debuggee with signal ignored");			\
22881.94Skamil}									\
22891.94Skamil									\
22901.94SkamilATF_TC_BODY(test, tc)							\
22911.94Skamil{									\
22921.94Skamil									\
22931.94Skamil	unrelated_tracer_sees_crash(sig, false, true);			\
22941.94Skamil}
22951.94Skamil
22961.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
22971.94Skamil    unrelated_tracer_sees_signalignored_crash_trap, SIGTRAP)
22981.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
22991.94Skamil    unrelated_tracer_sees_signalignored_crash_segv, SIGSEGV)
23001.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23011.94Skamil    unrelated_tracer_sees_signalignored_crash_ill, SIGILL)
23021.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23031.94Skamil    unrelated_tracer_sees_signalignored_crash_fpe, SIGFPE)
23041.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23051.94Skamil    unrelated_tracer_sees_signalignored_crash_bus, SIGBUS)
23061.59Skamil#endif
23071.59Skamil
23081.59Skamil/// ----------------------------------------------------------------------------
23091.59Skamil
23101.59Skamil#if defined(TWAIT_HAVE_PID)
23111.59Skamilstatic void
23121.67Skamiltracer_sees_terminaton_before_the_parent_raw(bool notimeout, bool unrelated,
23131.67Skamil                                             bool stopped)
23141.1Skamil{
23151.51Skamil	/*
23161.51Skamil	 * notimeout - disable timeout in await zombie function
23171.51Skamil	 * unrelated - attach from unrelated tracer reparented to initproc
23181.67Skamil	 * stopped - attach to a stopped process
23191.51Skamil	 */
23201.1Skamil
23211.1Skamil	struct msg_fds parent_tracee, parent_tracer;
23221.1Skamil	const int exitval_tracee = 5;
23231.1Skamil	const int exitval_tracer = 10;
23241.1Skamil	pid_t tracee, tracer, wpid;
23251.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
23261.1Skamil#if defined(TWAIT_HAVE_STATUS)
23271.1Skamil	int status;
23281.1Skamil#endif
23291.1Skamil
23301.67Skamil	/*
23311.67Skamil	 * Only a subset of options are supported.
23321.67Skamil	 */
23331.67Skamil	ATF_REQUIRE((!notimeout && !unrelated && !stopped) ||
23341.67Skamil	            (!notimeout && unrelated && !stopped) ||
23351.67Skamil	            (notimeout && !unrelated && !stopped) ||
23361.67Skamil	            (!notimeout && unrelated && stopped));
23371.67Skamil
23381.13Schristos	DPRINTF("Spawn tracee\n");
23391.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
23401.1Skamil	tracee = atf_utils_fork();
23411.1Skamil	if (tracee == 0) {
23421.67Skamil		if (stopped) {
23431.67Skamil			DPRINTF("Stop self PID %d\n", getpid());
23441.67Skamil			raise(SIGSTOP);
23451.67Skamil		}
23461.67Skamil
23471.1Skamil		// Wait for parent to let us exit
23481.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
23491.1Skamil		_exit(exitval_tracee);
23501.1Skamil	}
23511.1Skamil
23521.13Schristos	DPRINTF("Spawn debugger\n");
23531.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
23541.1Skamil	tracer = atf_utils_fork();
23551.1Skamil	if (tracer == 0) {
23561.51Skamil		if(unrelated) {
23571.51Skamil			/* Fork again and drop parent to reattach to PID 1 */
23581.51Skamil			tracer = atf_utils_fork();
23591.51Skamil			if (tracer != 0)
23601.51Skamil				_exit(exitval_tracer);
23611.51Skamil		}
23621.51Skamil
23631.67Skamil		if (stopped) {
23641.67Skamil			DPRINTF("Await for a stopped parent PID %d\n", tracee);
23651.67Skamil			await_stopped(tracee);
23661.67Skamil		}
23671.67Skamil
23681.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
23691.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
23701.1Skamil
23711.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
23721.1Skamil		FORKEE_REQUIRE_SUCCESS(
23731.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
23741.1Skamil
23751.1Skamil		forkee_status_stopped(status, SIGSTOP);
23761.1Skamil
23771.1Skamil		/* Resume tracee with PT_CONTINUE */
23781.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
23791.1Skamil
23801.1Skamil		/* Inform parent that tracer has attached to tracee */
23811.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
23821.1Skamil
23831.1Skamil		/* Wait for parent to tell use that tracee should have exited */
23841.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
23851.1Skamil
23861.1Skamil		/* Wait for tracee and assert that it exited */
23871.1Skamil		FORKEE_REQUIRE_SUCCESS(
23881.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
23891.1Skamil
23901.1Skamil		forkee_status_exited(status, exitval_tracee);
23911.13Schristos		DPRINTF("Tracee %d exited with %d\n", tracee, exitval_tracee);
23921.1Skamil
23931.13Schristos		DPRINTF("Before exiting of the tracer process\n");
23941.51Skamil		_exit(unrelated ? 0 /* collect by initproc */ : exitval_tracer);
23951.51Skamil	}
23961.51Skamil
23971.51Skamil	if (unrelated) {
23981.51Skamil		DPRINTF("Wait for the tracer process (direct child) to exit "
23991.51Skamil		    "calling %s()\n", TWAIT_FNAME);
24001.51Skamil		TWAIT_REQUIRE_SUCCESS(
24011.51Skamil		    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
24021.51Skamil
24031.51Skamil		validate_status_exited(status, exitval_tracer);
24041.51Skamil
24051.51Skamil		DPRINTF("Wait for the non-exited tracee process with %s()\n",
24061.51Skamil		    TWAIT_FNAME);
24071.51Skamil		TWAIT_REQUIRE_SUCCESS(
24081.51Skamil		    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
24091.1Skamil	}
24101.1Skamil
24111.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
24121.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
24131.1Skamil
24141.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
24151.1Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
24161.1Skamil
24171.13Schristos	DPRINTF("Detect that tracee is zombie\n");
24181.51Skamil	if (notimeout)
24191.26Skamil		await_zombie_raw(tracee, 0);
24201.26Skamil	else
24211.26Skamil		await_zombie(tracee);
24221.1Skamil
24231.13Schristos	DPRINTF("Assert that there is no status about tracee %d - "
24241.1Skamil	    "Tracer must detect zombie first - calling %s()\n", tracee,
24251.1Skamil	    TWAIT_FNAME);
24261.1Skamil	TWAIT_REQUIRE_SUCCESS(
24271.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
24281.1Skamil
24291.51Skamil	if (unrelated) {
24301.51Skamil		DPRINTF("Resume the tracer and let it detect exited tracee\n");
24311.51Skamil		PARENT_TO_CHILD("Message 2", parent_tracer, msg);
24321.51Skamil	} else {
24331.51Skamil		DPRINTF("Tell the tracer child should have exited\n");
24341.51Skamil		PARENT_TO_CHILD("wait for tracee exit", parent_tracer,  msg);
24351.51Skamil		DPRINTF("Wait for tracer to finish its job and exit - calling "
24361.59Skamil			"%s()\n", TWAIT_FNAME);
24371.51Skamil
24381.51Skamil		DPRINTF("Wait from tracer child to complete waiting for "
24391.59Skamil			"tracee\n");
24401.51Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
24411.51Skamil		    tracer);
24421.1Skamil
24431.51Skamil		validate_status_exited(status, exitval_tracer);
24441.51Skamil	}
24451.1Skamil
24461.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
24471.1Skamil	    TWAIT_FNAME);
24481.51Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
24491.1Skamil
24501.1Skamil	validate_status_exited(status, exitval_tracee);
24511.1Skamil
24521.1Skamil	msg_close(&parent_tracer);
24531.1Skamil	msg_close(&parent_tracee);
24541.1Skamil}
24551.26Skamil
24561.51SkamilATF_TC(tracer_sees_terminaton_before_the_parent);
24571.51SkamilATF_TC_HEAD(tracer_sees_terminaton_before_the_parent, tc)
24581.51Skamil{
24591.51Skamil	atf_tc_set_md_var(tc, "descr",
24601.51Skamil	    "Assert that tracer sees process termination before the parent");
24611.51Skamil}
24621.51Skamil
24631.51SkamilATF_TC_BODY(tracer_sees_terminaton_before_the_parent, tc)
24641.26Skamil{
24651.26Skamil
24661.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, false, false);
24671.26Skamil}
24681.26Skamil
24691.51SkamilATF_TC(tracer_sysctl_lookup_without_duplicates);
24701.51SkamilATF_TC_HEAD(tracer_sysctl_lookup_without_duplicates, tc)
24711.1Skamil{
24721.164Skamil	atf_tc_set_md_var(tc, "timeout", "15");
24731.1Skamil	atf_tc_set_md_var(tc, "descr",
24741.51Skamil	    "Assert that await_zombie() in attach1 always finds a single "
24751.51Skamil	    "process and no other error is reported");
24761.1Skamil}
24771.1Skamil
24781.51SkamilATF_TC_BODY(tracer_sysctl_lookup_without_duplicates, tc)
24791.1Skamil{
24801.51Skamil	time_t start, end;
24811.51Skamil	double diff;
24821.51Skamil	unsigned long N = 0;
24831.1Skamil
24841.51Skamil	/*
24851.51Skamil	 * Reuse this test with tracer_sees_terminaton_before_the_parent_raw().
24861.51Skamil	 * This test body isn't specific to this race, however it's just good
24871.51Skamil	 * enough for this purposes, no need to invent a dedicated code flow.
24881.51Skamil	 */
24891.1Skamil
24901.51Skamil	start = time(NULL);
24911.51Skamil	while (true) {
24921.51Skamil		DPRINTF("Step: %lu\n", N);
24931.67Skamil		tracer_sees_terminaton_before_the_parent_raw(true, false,
24941.67Skamil		                                             false);
24951.51Skamil		end = time(NULL);
24961.51Skamil		diff = difftime(end, start);
24971.51Skamil		if (diff >= 5.0)
24981.51Skamil			break;
24991.51Skamil		++N;
25001.1Skamil	}
25011.51Skamil	DPRINTF("Iterations: %lu\n", N);
25021.51Skamil}
25031.1Skamil
25041.51SkamilATF_TC(unrelated_tracer_sees_terminaton_before_the_parent);
25051.51SkamilATF_TC_HEAD(unrelated_tracer_sees_terminaton_before_the_parent, tc)
25061.51Skamil{
25071.51Skamil	atf_tc_set_md_var(tc, "descr",
25081.51Skamil	    "Assert that tracer sees process termination before the parent");
25091.51Skamil}
25101.1Skamil
25111.51SkamilATF_TC_BODY(unrelated_tracer_sees_terminaton_before_the_parent, tc)
25121.51Skamil{
25131.1Skamil
25141.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, false);
25151.67Skamil}
25161.67Skamil
25171.67SkamilATF_TC(tracer_attach_to_unrelated_stopped_process);
25181.67SkamilATF_TC_HEAD(tracer_attach_to_unrelated_stopped_process, tc)
25191.67Skamil{
25201.67Skamil	atf_tc_set_md_var(tc, "descr",
25211.67Skamil	    "Assert that tracer can attach to an unrelated stopped process");
25221.67Skamil}
25231.67Skamil
25241.67SkamilATF_TC_BODY(tracer_attach_to_unrelated_stopped_process, tc)
25251.67Skamil{
25261.67Skamil
25271.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, true);
25281.1Skamil}
25291.1Skamil#endif
25301.1Skamil
25311.51Skamil/// ----------------------------------------------------------------------------
25321.51Skamil
25331.66Skamilstatic void
25341.66Skamilparent_attach_to_its_child(bool stopped)
25351.1Skamil{
25361.1Skamil	struct msg_fds parent_tracee;
25371.1Skamil	const int exitval_tracee = 5;
25381.1Skamil	pid_t tracee, wpid;
25391.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
25401.1Skamil#if defined(TWAIT_HAVE_STATUS)
25411.1Skamil	int status;
25421.1Skamil#endif
25431.1Skamil
25441.13Schristos	DPRINTF("Spawn tracee\n");
25451.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
25461.1Skamil	tracee = atf_utils_fork();
25471.1Skamil	if (tracee == 0) {
25481.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
25491.13Schristos		DPRINTF("Parent should now attach to tracee\n");
25501.1Skamil
25511.66Skamil		if (stopped) {
25521.66Skamil			DPRINTF("Stop self PID %d\n", getpid());
25531.66Skamil			SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
25541.66Skamil		}
25551.66Skamil
25561.1Skamil		CHILD_FROM_PARENT("Message 2", parent_tracee, msg);
25571.1Skamil		/* Wait for message from the parent */
25581.1Skamil		_exit(exitval_tracee);
25591.1Skamil	}
25601.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
25611.57Skamil
25621.66Skamil	if (stopped) {
25631.66Skamil		DPRINTF("Await for a stopped tracee PID %d\n", tracee);
25641.66Skamil		await_stopped(tracee);
25651.66Skamil	}
25661.66Skamil
25671.13Schristos	DPRINTF("Before calling PT_ATTACH for tracee %d\n", tracee);
25681.13Schristos	SYSCALL_REQUIRE(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
25691.1Skamil
25701.13Schristos	DPRINTF("Wait for the stopped tracee process with %s()\n",
25711.1Skamil	    TWAIT_FNAME);
25721.1Skamil	TWAIT_REQUIRE_SUCCESS(
25731.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
25741.1Skamil
25751.1Skamil	validate_status_stopped(status, SIGSTOP);
25761.1Skamil
25771.13Schristos	DPRINTF("Resume tracee with PT_CONTINUE\n");
25781.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
25791.1Skamil
25801.13Schristos	DPRINTF("Let the tracee exit now\n");
25811.1Skamil	PARENT_TO_CHILD("Message 2", parent_tracee, msg);
25821.1Skamil
25831.13Schristos	DPRINTF("Wait for tracee to exit with %s()\n", TWAIT_FNAME);
25841.1Skamil	TWAIT_REQUIRE_SUCCESS(
25851.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
25861.1Skamil
25871.1Skamil	validate_status_exited(status, exitval_tracee);
25881.1Skamil
25891.13Schristos	DPRINTF("Before calling %s() for tracee\n", TWAIT_FNAME);
25901.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
25911.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0));
25921.1Skamil
25931.1Skamil	msg_close(&parent_tracee);
25941.1Skamil}
25951.1Skamil
25961.66SkamilATF_TC(parent_attach_to_its_child);
25971.66SkamilATF_TC_HEAD(parent_attach_to_its_child, tc)
25981.66Skamil{
25991.66Skamil	atf_tc_set_md_var(tc, "descr",
26001.66Skamil	    "Assert that tracer parent can PT_ATTACH to its child");
26011.66Skamil}
26021.66Skamil
26031.66SkamilATF_TC_BODY(parent_attach_to_its_child, tc)
26041.66Skamil{
26051.66Skamil
26061.66Skamil	parent_attach_to_its_child(false);
26071.66Skamil}
26081.66Skamil
26091.66SkamilATF_TC(parent_attach_to_its_stopped_child);
26101.66SkamilATF_TC_HEAD(parent_attach_to_its_stopped_child, tc)
26111.66Skamil{
26121.66Skamil	atf_tc_set_md_var(tc, "descr",
26131.66Skamil	    "Assert that tracer parent can PT_ATTACH to its stopped child");
26141.66Skamil}
26151.66Skamil
26161.66SkamilATF_TC_BODY(parent_attach_to_its_stopped_child, tc)
26171.66Skamil{
26181.66Skamil
26191.66Skamil	parent_attach_to_its_child(true);
26201.66Skamil}
26211.66Skamil
26221.51Skamil/// ----------------------------------------------------------------------------
26231.51Skamil
26241.65Skamilstatic void
26251.65Skamilchild_attach_to_its_parent(bool stopped)
26261.1Skamil{
26271.1Skamil	struct msg_fds parent_tracee;
26281.1Skamil	const int exitval_tracer = 5;
26291.1Skamil	pid_t tracer, wpid;
26301.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
26311.1Skamil#if defined(TWAIT_HAVE_STATUS)
26321.1Skamil	int status;
26331.1Skamil#endif
26341.1Skamil
26351.13Schristos	DPRINTF("Spawn tracer\n");
26361.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
26371.1Skamil	tracer = atf_utils_fork();
26381.1Skamil	if (tracer == 0) {
26391.1Skamil		/* Wait for message from the parent */
26401.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
26411.1Skamil
26421.65Skamil		if (stopped) {
26431.65Skamil			DPRINTF("Await for a stopped parent PID %d\n",
26441.65Skamil			        getppid());
26451.65Skamil			await_stopped(getppid());
26461.65Skamil		}
26471.65Skamil
26481.13Schristos		DPRINTF("Attach to parent PID %d with PT_ATTACH from child\n",
26491.1Skamil		    getppid());
26501.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, getppid(), NULL, 0) != -1);
26511.1Skamil
26521.13Schristos		DPRINTF("Wait for the stopped parent process with %s()\n",
26531.1Skamil		    TWAIT_FNAME);
26541.1Skamil		FORKEE_REQUIRE_SUCCESS(
26551.1Skamil		    wpid = TWAIT_GENERIC(getppid(), &status, 0), getppid());
26561.1Skamil
26571.1Skamil		forkee_status_stopped(status, SIGSTOP);
26581.1Skamil
26591.13Schristos		DPRINTF("Resume parent with PT_DETACH\n");
26601.1Skamil		FORKEE_ASSERT(ptrace(PT_DETACH, getppid(), (void *)1, 0)
26611.1Skamil		    != -1);
26621.1Skamil
26631.1Skamil		/* Tell parent we are ready */
26641.1Skamil		CHILD_TO_PARENT("Message 1", parent_tracee, msg);
26651.1Skamil
26661.1Skamil		_exit(exitval_tracer);
26671.1Skamil	}
26681.1Skamil
26691.13Schristos	DPRINTF("Wait for the tracer to become ready\n");
26701.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
26711.65Skamil
26721.65Skamil	if (stopped) {
26731.65Skamil		DPRINTF("Stop self PID %d\n", getpid());
26741.65Skamil		SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
26751.65Skamil	}
26761.65Skamil
26771.13Schristos	DPRINTF("Allow the tracer to exit now\n");
26781.1Skamil	PARENT_FROM_CHILD("Message 1", parent_tracee, msg);
26791.1Skamil
26801.13Schristos	DPRINTF("Wait for tracer to exit with %s()\n", TWAIT_FNAME);
26811.1Skamil	TWAIT_REQUIRE_SUCCESS(
26821.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
26831.1Skamil
26841.1Skamil	validate_status_exited(status, exitval_tracer);
26851.1Skamil
26861.13Schristos	DPRINTF("Before calling %s() for tracer\n", TWAIT_FNAME);
26871.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
26881.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0));
26891.1Skamil
26901.1Skamil	msg_close(&parent_tracee);
26911.1Skamil}
26921.1Skamil
26931.65SkamilATF_TC(child_attach_to_its_parent);
26941.65SkamilATF_TC_HEAD(child_attach_to_its_parent, tc)
26951.65Skamil{
26961.65Skamil	atf_tc_set_md_var(tc, "descr",
26971.65Skamil	    "Assert that tracer child can PT_ATTACH to its parent");
26981.65Skamil}
26991.65Skamil
27001.65SkamilATF_TC_BODY(child_attach_to_its_parent, tc)
27011.65Skamil{
27021.65Skamil
27031.65Skamil	child_attach_to_its_parent(false);
27041.65Skamil}
27051.65Skamil
27061.65SkamilATF_TC(child_attach_to_its_stopped_parent);
27071.65SkamilATF_TC_HEAD(child_attach_to_its_stopped_parent, tc)
27081.65Skamil{
27091.65Skamil	atf_tc_set_md_var(tc, "descr",
27101.65Skamil	    "Assert that tracer child can PT_ATTACH to its stopped parent");
27111.65Skamil}
27121.65Skamil
27131.65SkamilATF_TC_BODY(child_attach_to_its_stopped_parent, tc)
27141.65Skamil{
27151.65Skamil	/*
27161.65Skamil	 * The ATF framework (atf-run) does not tolerate raise(SIGSTOP), as
27171.65Skamil	 * this causes a pipe (established from atf-run) to be broken.
27181.65Skamil	 * atf-run uses this mechanism to monitor whether a test is alive.
27191.65Skamil	 *
27201.65Skamil	 * As a workaround spawn this test as a subprocess.
27211.65Skamil	 */
27221.65Skamil
27231.65Skamil	const int exitval = 15;
27241.65Skamil	pid_t child, wpid;
27251.65Skamil#if defined(TWAIT_HAVE_STATUS)
27261.65Skamil	int status;
27271.65Skamil#endif
27281.65Skamil
27291.65Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
27301.65Skamil	if (child == 0) {
27311.65Skamil		child_attach_to_its_parent(true);
27321.65Skamil		_exit(exitval);
27331.65Skamil	} else {
27341.65Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
27351.65Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
27361.65Skamil
27371.65Skamil		validate_status_exited(status, exitval);
27381.65Skamil
27391.65Skamil		DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
27401.65Skamil		TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
27411.65Skamil	}
27421.65Skamil}
27431.65Skamil
27441.51Skamil/// ----------------------------------------------------------------------------
27451.51Skamil
27461.1Skamil#if defined(TWAIT_HAVE_PID)
27471.1Skamil
27481.51Skamilenum tracee_sees_its_original_parent_type {
27491.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
27501.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
27511.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS
27521.51Skamil};
27531.51Skamil
27541.51Skamilstatic void
27551.51Skamiltracee_sees_its_original_parent(enum tracee_sees_its_original_parent_type type)
27561.1Skamil{
27571.1Skamil	struct msg_fds parent_tracer, parent_tracee;
27581.1Skamil	const int exitval_tracee = 5;
27591.1Skamil	const int exitval_tracer = 10;
27601.1Skamil	pid_t parent, tracee, tracer, wpid;
27611.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
27621.1Skamil#if defined(TWAIT_HAVE_STATUS)
27631.1Skamil	int status;
27641.1Skamil#endif
27651.51Skamil	/* sysctl(3) - kinfo_proc2 */
27661.51Skamil	int name[CTL_MAXNAME];
27671.51Skamil	struct kinfo_proc2 kp;
27681.51Skamil	size_t len = sizeof(kp);
27691.51Skamil	unsigned int namelen;
27701.51Skamil
27711.51Skamil	/* procfs - status  */
27721.51Skamil	FILE *fp;
27731.51Skamil	struct stat st;
27741.51Skamil	const char *fname = "/proc/curproc/status";
27751.51Skamil	char s_executable[MAXPATHLEN];
27761.51Skamil	int s_pid, s_ppid;
27771.51Skamil	int rv;
27781.51Skamil
27791.51Skamil	if (type == TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS) {
27801.61Skre		SYSCALL_REQUIRE(
27811.61Skre		    (rv = stat(fname, &st)) == 0 || (errno == ENOENT));
27821.61Skre		if (rv != 0)
27831.51Skamil			atf_tc_skip("/proc/curproc/status not found");
27841.51Skamil	}
27851.1Skamil
27861.13Schristos	DPRINTF("Spawn tracee\n");
27871.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
27881.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
27891.1Skamil	tracee = atf_utils_fork();
27901.1Skamil	if (tracee == 0) {
27911.1Skamil		parent = getppid();
27921.1Skamil
27931.1Skamil		/* Emit message to the parent */
27941.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
27951.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
27961.1Skamil
27971.51Skamil		switch (type) {
27981.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID:
27991.51Skamil			FORKEE_ASSERT_EQ(parent, getppid());
28001.51Skamil			break;
28011.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2:
28021.51Skamil			namelen = 0;
28031.51Skamil			name[namelen++] = CTL_KERN;
28041.51Skamil			name[namelen++] = KERN_PROC2;
28051.51Skamil			name[namelen++] = KERN_PROC_PID;
28061.51Skamil			name[namelen++] = getpid();
28071.51Skamil			name[namelen++] = len;
28081.51Skamil			name[namelen++] = 1;
28091.51Skamil
28101.61Skre			FORKEE_ASSERT_EQ(
28111.61Skre			    sysctl(name, namelen, &kp, &len, NULL, 0), 0);
28121.51Skamil			FORKEE_ASSERT_EQ(parent, kp.p_ppid);
28131.51Skamil			break;
28141.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS:
28151.51Skamil			/*
28161.51Skamil			 * Format:
28171.51Skamil			 *  EXECUTABLE PID PPID ...
28181.51Skamil			 */
28191.51Skamil			FORKEE_ASSERT((fp = fopen(fname, "r")) != NULL);
28201.51Skamil			fscanf(fp, "%s %d %d", s_executable, &s_pid, &s_ppid);
28211.51Skamil			FORKEE_ASSERT_EQ(fclose(fp), 0);
28221.51Skamil			FORKEE_ASSERT_EQ(parent, s_ppid);
28231.51Skamil			break;
28241.51Skamil		}
28251.1Skamil
28261.1Skamil		_exit(exitval_tracee);
28271.1Skamil	}
28281.13Schristos	DPRINTF("Wait for child to record its parent identifier (pid)\n");
28291.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
28301.1Skamil
28311.13Schristos	DPRINTF("Spawn debugger\n");
28321.1Skamil	tracer = atf_utils_fork();
28331.1Skamil	if (tracer == 0) {
28341.1Skamil		/* No IPC to communicate with the child */
28351.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
28361.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
28371.1Skamil
28381.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
28391.1Skamil		FORKEE_REQUIRE_SUCCESS(
28401.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
28411.1Skamil
28421.1Skamil		forkee_status_stopped(status, SIGSTOP);
28431.1Skamil
28441.1Skamil		/* Resume tracee with PT_CONTINUE */
28451.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
28461.1Skamil
28471.1Skamil		/* Inform parent that tracer has attached to tracee */
28481.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
28491.1Skamil
28501.1Skamil		/* Wait for parent to tell use that tracee should have exited */
28511.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
28521.1Skamil
28531.1Skamil		/* Wait for tracee and assert that it exited */
28541.1Skamil		FORKEE_REQUIRE_SUCCESS(
28551.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
28561.1Skamil
28571.1Skamil		forkee_status_exited(status, exitval_tracee);
28581.1Skamil
28591.13Schristos		DPRINTF("Before exiting of the tracer process\n");
28601.1Skamil		_exit(exitval_tracer);
28611.1Skamil	}
28621.1Skamil
28631.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
28641.1Skamil	PARENT_FROM_CHILD("tracer ready",  parent_tracer, msg);
28651.1Skamil
28661.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
28671.1Skamil	PARENT_TO_CHILD("exit tracee",  parent_tracee, msg);
28681.1Skamil
28691.13Schristos	DPRINTF("Detect that tracee is zombie\n");
28701.1Skamil	await_zombie(tracee);
28711.1Skamil
28721.13Schristos	DPRINTF("Assert that there is no status about tracee - "
28731.1Skamil	    "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
28741.1Skamil	TWAIT_REQUIRE_SUCCESS(
28751.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
28761.1Skamil
28771.13Schristos	DPRINTF("Tell the tracer child should have exited\n");
28781.1Skamil	PARENT_TO_CHILD("wait for tracee exit",  parent_tracer, msg);
28791.1Skamil
28801.13Schristos	DPRINTF("Wait from tracer child to complete waiting for tracee\n");
28811.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
28821.1Skamil	    tracer);
28831.1Skamil
28841.1Skamil	validate_status_exited(status, exitval_tracer);
28851.1Skamil
28861.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
28871.1Skamil	    TWAIT_FNAME);
28881.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
28891.1Skamil	    tracee);
28901.1Skamil
28911.1Skamil	validate_status_exited(status, exitval_tracee);
28921.1Skamil
28931.1Skamil	msg_close(&parent_tracer);
28941.1Skamil	msg_close(&parent_tracee);
28951.1Skamil}
28961.1Skamil
28971.61Skre#define TRACEE_SEES_ITS_ORIGINAL_PARENT(test, type, descr)		\
28981.61SkreATF_TC(test);								\
28991.61SkreATF_TC_HEAD(test, tc)							\
29001.61Skre{									\
29011.61Skre	atf_tc_set_md_var(tc, "descr",					\
29021.61Skre	    "Assert that tracee sees its original parent when being traced " \
29031.61Skre	    "(check " descr ")");					\
29041.61Skre}									\
29051.61Skre									\
29061.61SkreATF_TC_BODY(test, tc)							\
29071.61Skre{									\
29081.61Skre									\
29091.61Skre	tracee_sees_its_original_parent(type);				\
29101.1Skamil}
29111.1Skamil
29121.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29131.51Skamil	tracee_sees_its_original_parent_getppid,
29141.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
29151.51Skamil	"getppid(2)");
29161.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29171.51Skamil	tracee_sees_its_original_parent_sysctl_kinfo_proc2,
29181.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
29191.51Skamil	"sysctl(3) and kinfo_proc2");
29201.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29211.51Skamil	tracee_sees_its_original_parent_procfs_status,
29221.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS,
29231.51Skamil	"the status file in procfs");
29241.1Skamil#endif
29251.1Skamil
29261.51Skamil/// ----------------------------------------------------------------------------
29271.1Skamil
29281.53Skamilstatic void
29291.53Skamileventmask_preserved(int event)
29301.1Skamil{
29311.1Skamil	const int exitval = 5;
29321.1Skamil	const int sigval = SIGSTOP;
29331.1Skamil	pid_t child, wpid;
29341.1Skamil#if defined(TWAIT_HAVE_STATUS)
29351.1Skamil	int status;
29361.1Skamil#endif
29371.1Skamil	ptrace_event_t set_event, get_event;
29381.1Skamil	const int len = sizeof(ptrace_event_t);
29391.1Skamil
29401.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
29411.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
29421.1Skamil	if (child == 0) {
29431.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
29441.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
29451.1Skamil
29461.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
29471.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
29481.1Skamil
29491.13Schristos		DPRINTF("Before exiting of the child process\n");
29501.1Skamil		_exit(exitval);
29511.1Skamil	}
29521.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
29531.1Skamil
29541.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29551.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
29561.1Skamil
29571.1Skamil	validate_status_stopped(status, sigval);
29581.1Skamil
29591.53Skamil	set_event.pe_set_event = event;
29601.61Skre	SYSCALL_REQUIRE(
29611.61Skre	    ptrace(PT_SET_EVENT_MASK, child, &set_event, len) != -1);
29621.61Skre	SYSCALL_REQUIRE(
29631.61Skre	    ptrace(PT_GET_EVENT_MASK, child, &get_event, len) != -1);
29641.125Skamil	DPRINTF("set_event=%#x get_event=%#x\n", set_event.pe_set_event,
29651.125Skamil	    get_event.pe_set_event);
29661.1Skamil	ATF_REQUIRE(memcmp(&set_event, &get_event, len) == 0);
29671.1Skamil
29681.13Schristos	DPRINTF("Before resuming the child process where it left off and "
29691.1Skamil	    "without signal to be sent\n");
29701.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
29711.1Skamil
29721.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29731.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
29741.1Skamil
29751.1Skamil	validate_status_exited(status, exitval);
29761.1Skamil
29771.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29781.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
29791.1Skamil}
29801.1Skamil
29811.61Skre#define EVENTMASK_PRESERVED(test, event)				\
29821.61SkreATF_TC(test);								\
29831.61SkreATF_TC_HEAD(test, tc)							\
29841.61Skre{									\
29851.61Skre	atf_tc_set_md_var(tc, "descr",					\
29861.61Skre	    "Verify that eventmask " #event " is preserved");		\
29871.61Skre}									\
29881.61Skre									\
29891.61SkreATF_TC_BODY(test, tc)							\
29901.61Skre{									\
29911.61Skre									\
29921.61Skre	eventmask_preserved(event);					\
29931.1Skamil}
29941.1Skamil
29951.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_empty, 0)
29961.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_fork, PTRACE_FORK)
29971.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_vfork, PTRACE_VFORK)
29981.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_vfork_done, PTRACE_VFORK_DONE)
29991.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_lwp_create, PTRACE_LWP_CREATE)
30001.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_lwp_exit, PTRACE_LWP_EXIT)
30011.125SkamilEVENTMASK_PRESERVED(eventmask_preserved_posix_spawn, PTRACE_POSIX_SPAWN)
30021.1Skamil
30031.53Skamil/// ----------------------------------------------------------------------------
30041.1Skamil
30051.28Skamilstatic void
30061.125Skamilfork_body(const char *fn, bool trackspawn, bool trackfork, bool trackvfork,
30071.105Skamil    bool trackvforkdone)
30081.1Skamil{
30091.1Skamil	const int exitval = 5;
30101.125Skamil	const int exitval2 = 0; /* This matched exit status from /bin/echo */
30111.1Skamil	const int sigval = SIGSTOP;
30121.31Skamil	pid_t child, child2 = 0, wpid;
30131.1Skamil#if defined(TWAIT_HAVE_STATUS)
30141.1Skamil	int status;
30151.1Skamil#endif
30161.1Skamil	ptrace_state_t state;
30171.1Skamil	const int slen = sizeof(state);
30181.1Skamil	ptrace_event_t event;
30191.1Skamil	const int elen = sizeof(event);
30201.1Skamil
30211.124Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
30221.124Skamil
30231.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
30241.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
30251.1Skamil	if (child == 0) {
30261.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
30271.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
30281.1Skamil
30291.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
30301.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
30311.1Skamil
30321.125Skamil		if (strcmp(fn, "spawn") == 0) {
30331.124Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
30341.124Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
30351.125Skamil		} else {
30361.125Skamil			if (strcmp(fn, "fork") == 0) {
30371.125Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
30381.125Skamil			} else if (strcmp(fn, "vfork") == 0) {
30391.125Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
30401.125Skamil			}
30411.1Skamil
30421.124Skamil			if (child2 == 0)
30431.124Skamil				_exit(exitval2);
30441.124Skamil		}
30451.1Skamil		FORKEE_REQUIRE_SUCCESS
30461.1Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
30471.1Skamil
30481.1Skamil		forkee_status_exited(status, exitval2);
30491.1Skamil
30501.13Schristos		DPRINTF("Before exiting of the child process\n");
30511.1Skamil		_exit(exitval);
30521.1Skamil	}
30531.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
30541.1Skamil
30551.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
30561.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
30571.1Skamil
30581.1Skamil	validate_status_stopped(status, sigval);
30591.1Skamil
30601.125Skamil	DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
30611.125Skamil	    trackspawn ? "|PTRACE_POSIX_SPAWN" : "",
30621.61Skre	    trackfork ? "|PTRACE_FORK" : "",
30631.61Skre	    trackvfork ? "|PTRACE_VFORK" : "",
30641.61Skre	    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", child);
30651.30Skamil	event.pe_set_event = 0;
30661.125Skamil	if (trackspawn)
30671.125Skamil		event.pe_set_event |= PTRACE_POSIX_SPAWN;
30681.30Skamil	if (trackfork)
30691.30Skamil		event.pe_set_event |= PTRACE_FORK;
30701.30Skamil	if (trackvfork)
30711.30Skamil		event.pe_set_event |= PTRACE_VFORK;
30721.30Skamil	if (trackvforkdone)
30731.30Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
30741.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
30751.1Skamil
30761.13Schristos	DPRINTF("Before resuming the child process where it left off and "
30771.1Skamil	    "without signal to be sent\n");
30781.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
30791.1Skamil
30801.29Skamil#if defined(TWAIT_HAVE_PID)
30811.125Skamil	if ((trackspawn && strcmp(fn, "spawn") == 0) ||
30821.125Skamil	    (trackfork && strcmp(fn, "fork") == 0) ||
30831.125Skamil	    (trackvfork && strcmp(fn, "vfork") == 0)) {
30841.29Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
30851.61Skre		    child);
30861.29Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
30871.61Skre		    child);
30881.1Skamil
30891.29Skamil		validate_status_stopped(status, SIGTRAP);
30901.1Skamil
30911.61Skre		SYSCALL_REQUIRE(
30921.61Skre		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
30931.125Skamil		if (trackspawn && strcmp(fn, "spawn") == 0) {
30941.125Skamil			ATF_REQUIRE_EQ(
30951.125Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
30961.125Skamil			       PTRACE_POSIX_SPAWN);
30971.125Skamil		}
30981.125Skamil		if (trackfork && strcmp(fn, "fork") == 0) {
30991.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
31001.30Skamil			       PTRACE_FORK);
31011.30Skamil		}
31021.125Skamil		if (trackvfork && strcmp(fn, "vfork") == 0) {
31031.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
31041.30Skamil			       PTRACE_VFORK);
31051.30Skamil		}
31061.29Skamil
31071.29Skamil		child2 = state.pe_other_pid;
31081.30Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
31091.29Skamil
31101.29Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
31111.61Skre		    "%d\n", TWAIT_FNAME, child2, child);
31121.29Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
31131.29Skamil		    child2);
31141.1Skamil
31151.29Skamil		validate_status_stopped(status, SIGTRAP);
31161.1Skamil
31171.61Skre		SYSCALL_REQUIRE(
31181.61Skre		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
31191.125Skamil		if (trackspawn && strcmp(fn, "spawn") == 0) {
31201.125Skamil			ATF_REQUIRE_EQ(
31211.125Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
31221.125Skamil			       PTRACE_POSIX_SPAWN);
31231.125Skamil		}
31241.125Skamil		if (trackfork && strcmp(fn, "fork") == 0) {
31251.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
31261.30Skamil			       PTRACE_FORK);
31271.30Skamil		}
31281.125Skamil		if (trackvfork && strcmp(fn, "vfork") == 0) {
31291.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
31301.30Skamil			       PTRACE_VFORK);
31311.30Skamil		}
31321.30Skamil
31331.29Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
31341.29Skamil
31351.29Skamil		DPRINTF("Before resuming the forkee process where it left off "
31361.29Skamil		    "and without signal to be sent\n");
31371.61Skre		SYSCALL_REQUIRE(
31381.61Skre		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
31391.29Skamil
31401.29Skamil		DPRINTF("Before resuming the child process where it left off "
31411.61Skre		    "and without signal to be sent\n");
31421.29Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31431.30Skamil	}
31441.30Skamil#endif
31451.30Skamil
31461.125Skamil	if (trackvforkdone && strcmp(fn, "vfork") == 0) {
31471.30Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
31481.61Skre		    child);
31491.61Skre		TWAIT_REQUIRE_SUCCESS(
31501.61Skre		    wpid = TWAIT_GENERIC(child, &status, 0), child);
31511.30Skamil
31521.30Skamil		validate_status_stopped(status, SIGTRAP);
31531.30Skamil
31541.61Skre		SYSCALL_REQUIRE(
31551.61Skre		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
31561.30Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
31571.30Skamil
31581.30Skamil		child2 = state.pe_other_pid;
31591.30Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
31601.61Skre		    child2);
31611.30Skamil
31621.30Skamil		DPRINTF("Before resuming the child process where it left off "
31631.61Skre		    "and without signal to be sent\n");
31641.30Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31651.30Skamil	}
31661.29Skamil
31671.30Skamil#if defined(TWAIT_HAVE_PID)
31681.125Skamil	if ((trackspawn && strcmp(fn, "spawn") == 0) ||
31691.125Skamil	    (trackfork && strcmp(fn, "fork") == 0) ||
31701.125Skamil	    (trackvfork && strcmp(fn, "vfork") == 0)) {
31711.29Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
31721.61Skre		    "\n", TWAIT_FNAME);
31731.61Skre		TWAIT_REQUIRE_SUCCESS(
31741.61Skre		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
31751.29Skamil
31761.29Skamil		validate_status_exited(status, exitval2);
31771.29Skamil
31781.29Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
31791.61Skre		    "process\n", TWAIT_FNAME);
31801.29Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
31811.29Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
31821.29Skamil	}
31831.29Skamil#endif
31841.1Skamil
31851.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
31861.1Skamil	    "SIGCHLD\n", TWAIT_FNAME);
31871.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
31881.1Skamil
31891.1Skamil	validate_status_stopped(status, SIGCHLD);
31901.1Skamil
31911.13Schristos	DPRINTF("Before resuming the child process where it left off and "
31921.1Skamil	    "without signal to be sent\n");
31931.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31941.1Skamil
31951.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
31961.1Skamil	    TWAIT_FNAME);
31971.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
31981.1Skamil
31991.1Skamil	validate_status_exited(status, exitval);
32001.1Skamil
32011.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
32021.1Skamil	    TWAIT_FNAME);
32031.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
32041.1Skamil}
32051.28Skamil
32061.125Skamil#define FORK_TEST(name,fun,tspawn,tfork,tvfork,tvforkdone)		\
32071.61SkreATF_TC(name);								\
32081.61SkreATF_TC_HEAD(name, tc)							\
32091.61Skre{									\
32101.125Skamil	atf_tc_set_md_var(tc, "descr", "Verify " fun "() "		\
32111.125Skamil	    "called with 0%s%s%s%s in EVENT_MASK",			\
32121.126Skamil	    tspawn ? "|PTRACE_POSIX_SPAWN" : "",			\
32131.105Skamil	    tfork ? "|PTRACE_FORK" : "",				\
32141.105Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
32151.105Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
32161.61Skre}									\
32171.61Skre									\
32181.61SkreATF_TC_BODY(name, tc)							\
32191.61Skre{									\
32201.61Skre									\
32211.125Skamil	fork_body(fun, tspawn, tfork, tvfork, tvforkdone);		\
32221.32Skamil}
32231.32Skamil
32241.125SkamilFORK_TEST(fork1, "fork", false, false, false, false)
32251.31Skamil#if defined(TWAIT_HAVE_PID)
32261.125SkamilFORK_TEST(fork2, "fork", false, true, false, false)
32271.125SkamilFORK_TEST(fork3, "fork", false, false, true, false)
32281.125SkamilFORK_TEST(fork4, "fork", false, true, true, false)
32291.31Skamil#endif
32301.125SkamilFORK_TEST(fork5, "fork", false, false, false, true)
32311.31Skamil#if defined(TWAIT_HAVE_PID)
32321.125SkamilFORK_TEST(fork6, "fork", false, true, false, true)
32331.125SkamilFORK_TEST(fork7, "fork", false, false, true, true)
32341.125SkamilFORK_TEST(fork8, "fork", false, true, true, true)
32351.125Skamil#endif
32361.125SkamilFORK_TEST(fork9, "fork", true, false, false, false)
32371.125Skamil#if defined(TWAIT_HAVE_PID)
32381.125SkamilFORK_TEST(fork10, "fork", true, true, false, false)
32391.125SkamilFORK_TEST(fork11, "fork", true, false, true, false)
32401.125SkamilFORK_TEST(fork12, "fork", true, true, true, false)
32411.125Skamil#endif
32421.125SkamilFORK_TEST(fork13, "fork", true, false, false, true)
32431.125Skamil#if defined(TWAIT_HAVE_PID)
32441.125SkamilFORK_TEST(fork14, "fork", true, true, false, true)
32451.125SkamilFORK_TEST(fork15, "fork", true, false, true, true)
32461.125SkamilFORK_TEST(fork16, "fork", true, true, true, true)
32471.31Skamil#endif
32481.1Skamil
32491.125SkamilFORK_TEST(vfork1, "vfork", false, false, false, false)
32501.31Skamil#if defined(TWAIT_HAVE_PID)
32511.125SkamilFORK_TEST(vfork2, "vfork", false, true, false, false)
32521.125SkamilFORK_TEST(vfork3, "vfork", false, false, true, false)
32531.125SkamilFORK_TEST(vfork4, "vfork", false, true, true, false)
32541.31Skamil#endif
32551.125SkamilFORK_TEST(vfork5, "vfork", false, false, false, true)
32561.31Skamil#if defined(TWAIT_HAVE_PID)
32571.125SkamilFORK_TEST(vfork6, "vfork", false, true, false, true)
32581.125SkamilFORK_TEST(vfork7, "vfork", false, false, true, true)
32591.125SkamilFORK_TEST(vfork8, "vfork", false, true, true, true)
32601.31Skamil#endif
32611.125SkamilFORK_TEST(vfork9, "vfork", true, false, false, false)
32621.125Skamil#if defined(TWAIT_HAVE_PID)
32631.125SkamilFORK_TEST(vfork10, "vfork", true, true, false, false)
32641.125SkamilFORK_TEST(vfork11, "vfork", true, false, true, false)
32651.125SkamilFORK_TEST(vfork12, "vfork", true, true, true, false)
32661.110Skamil#endif
32671.125SkamilFORK_TEST(vfork13, "vfork", true, false, false, true)
32681.124Skamil#if defined(TWAIT_HAVE_PID)
32691.125SkamilFORK_TEST(vfork14, "vfork", true, true, false, true)
32701.125SkamilFORK_TEST(vfork15, "vfork", true, false, true, true)
32711.125SkamilFORK_TEST(vfork16, "vfork", true, true, true, true)
32721.124Skamil#endif
32731.125Skamil
32741.125SkamilFORK_TEST(posix_spawn1, "spawn", false, false, false, false)
32751.125SkamilFORK_TEST(posix_spawn2, "spawn", false, true, false, false)
32761.125SkamilFORK_TEST(posix_spawn3, "spawn", false, false, true, false)
32771.125SkamilFORK_TEST(posix_spawn4, "spawn", false, true, true, false)
32781.125SkamilFORK_TEST(posix_spawn5, "spawn", false, false, false, true)
32791.125SkamilFORK_TEST(posix_spawn6, "spawn", false, true, false, true)
32801.125SkamilFORK_TEST(posix_spawn7, "spawn", false, false, true, true)
32811.125SkamilFORK_TEST(posix_spawn8, "spawn", false, true, true, true)
32821.124Skamil#if defined(TWAIT_HAVE_PID)
32831.125SkamilFORK_TEST(posix_spawn9, "spawn", true, false, false, false)
32841.125SkamilFORK_TEST(posix_spawn10, "spawn", true, true, false, false)
32851.125SkamilFORK_TEST(posix_spawn11, "spawn", true, false, true, false)
32861.125SkamilFORK_TEST(posix_spawn12, "spawn", true, true, true, false)
32871.125SkamilFORK_TEST(posix_spawn13, "spawn", true, false, false, true)
32881.125SkamilFORK_TEST(posix_spawn14, "spawn", true, true, false, true)
32891.125SkamilFORK_TEST(posix_spawn15, "spawn", true, false, true, true)
32901.125SkamilFORK_TEST(posix_spawn16, "spawn", true, true, true, true)
32911.124Skamil#endif
32921.124Skamil
32931.54Skamil/// ----------------------------------------------------------------------------
32941.31Skamil
32951.116Skamil#if defined(TWAIT_HAVE_PID)
32961.116Skamilstatic void
32971.149Skamilunrelated_tracer_fork_body(const char *fn, bool trackspawn, bool trackfork,
32981.149Skamil    bool trackvfork, bool trackvforkdone)
32991.149Skamil{
33001.149Skamil	const int sigval = SIGSTOP;
33011.149Skamil	struct msg_fds parent_tracee, parent_tracer;
33021.149Skamil	const int exitval = 10;
33031.149Skamil	const int exitval2 = 0; /* This matched exit status from /bin/echo */
33041.149Skamil	pid_t tracee, tracer, wpid;
33051.149Skamil	pid_t tracee2 = 0;
33061.149Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
33071.149Skamil#if defined(TWAIT_HAVE_STATUS)
33081.149Skamil	int status;
33091.149Skamil#endif
33101.149Skamil
33111.149Skamil	struct ptrace_siginfo info;
33121.149Skamil	ptrace_state_t state;
33131.149Skamil	const int slen = sizeof(state);
33141.149Skamil	ptrace_event_t event;
33151.149Skamil	const int elen = sizeof(event);
33161.149Skamil
33171.149Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
33181.149Skamil
33191.149Skamil	DPRINTF("Spawn tracee\n");
33201.149Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
33211.149Skamil	tracee = atf_utils_fork();
33221.149Skamil	if (tracee == 0) {
33231.149Skamil		// Wait for parent to let us crash
33241.149Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
33251.149Skamil
33261.149Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
33271.149Skamil		FORKEE_ASSERT(raise(sigval) == 0);
33281.149Skamil
33291.149Skamil		if (strcmp(fn, "spawn") == 0) {
33301.149Skamil			FORKEE_ASSERT_EQ(posix_spawn(&tracee2,
33311.149Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
33321.149Skamil		} else {
33331.149Skamil			if (strcmp(fn, "fork") == 0) {
33341.149Skamil				FORKEE_ASSERT((tracee2 = fork()) != -1);
33351.149Skamil			} else if (strcmp(fn, "vfork") == 0) {
33361.149Skamil				FORKEE_ASSERT((tracee2 = vfork()) != -1);
33371.149Skamil			}
33381.149Skamil
33391.149Skamil			if (tracee2 == 0)
33401.149Skamil				_exit(exitval2);
33411.149Skamil		}
33421.149Skamil		FORKEE_REQUIRE_SUCCESS
33431.149Skamil		    (wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
33441.149Skamil
33451.149Skamil		forkee_status_exited(status, exitval2);
33461.149Skamil
33471.149Skamil		DPRINTF("Before exiting of the child process\n");
33481.149Skamil		_exit(exitval);
33491.149Skamil	}
33501.149Skamil
33511.149Skamil	DPRINTF("Spawn debugger\n");
33521.149Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
33531.149Skamil	tracer = atf_utils_fork();
33541.149Skamil	if (tracer == 0) {
33551.149Skamil		/* Fork again and drop parent to reattach to PID 1 */
33561.149Skamil		tracer = atf_utils_fork();
33571.149Skamil		if (tracer != 0)
33581.149Skamil			_exit(exitval);
33591.149Skamil
33601.149Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
33611.149Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
33621.149Skamil
33631.149Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
33641.149Skamil		FORKEE_REQUIRE_SUCCESS(
33651.149Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
33661.149Skamil
33671.149Skamil		forkee_status_stopped(status, SIGSTOP);
33681.149Skamil
33691.149Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
33701.149Skamil		    "traced process\n");
33711.149Skamil		SYSCALL_REQUIRE(
33721.149Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
33731.149Skamil
33741.149Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
33751.149Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
33761.149Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
33771.149Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
33781.149Skamil
33791.149Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
33801.149Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
33811.149Skamil
33821.149Skamil		/* Resume tracee with PT_CONTINUE */
33831.149Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
33841.149Skamil
33851.149Skamil		/* Inform parent that tracer has attached to tracee */
33861.149Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
33871.149Skamil
33881.149Skamil		/* Wait for parent to tell use that tracee should have exited */
33891.149Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
33901.149Skamil
33911.149Skamil		/* Wait for tracee and assert that it exited */
33921.149Skamil		FORKEE_REQUIRE_SUCCESS(
33931.149Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
33941.149Skamil
33951.149Skamil		forkee_status_stopped(status, sigval);
33961.149Skamil
33971.149Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
33981.149Skamil		    "traced process\n");
33991.149Skamil		SYSCALL_REQUIRE(
34001.149Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
34011.149Skamil
34021.149Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
34031.149Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
34041.149Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
34051.149Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
34061.149Skamil
34071.149Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
34081.149Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
34091.149Skamil
34101.149Skamil		DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
34111.149Skamil		    trackspawn ? "|PTRACE_POSIX_SPAWN" : "",
34121.149Skamil		    trackfork ? "|PTRACE_FORK" : "",
34131.149Skamil		    trackvfork ? "|PTRACE_VFORK" : "",
34141.149Skamil		    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", tracee);
34151.149Skamil		event.pe_set_event = 0;
34161.149Skamil		if (trackspawn)
34171.149Skamil			event.pe_set_event |= PTRACE_POSIX_SPAWN;
34181.149Skamil		if (trackfork)
34191.149Skamil			event.pe_set_event |= PTRACE_FORK;
34201.149Skamil		if (trackvfork)
34211.149Skamil			event.pe_set_event |= PTRACE_VFORK;
34221.149Skamil		if (trackvforkdone)
34231.149Skamil			event.pe_set_event |= PTRACE_VFORK_DONE;
34241.149Skamil		SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, tracee, &event, elen)
34251.149Skamil		    != -1);
34261.149Skamil
34271.149Skamil		DPRINTF("Before resuming the child process where it left off "
34281.149Skamil		    "and without signal to be sent\n");
34291.149Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
34301.149Skamil
34311.149Skamil		if ((trackspawn && strcmp(fn, "spawn") == 0) ||
34321.149Skamil		    (trackfork && strcmp(fn, "fork") == 0) ||
34331.149Skamil		    (trackvfork && strcmp(fn, "vfork") == 0)) {
34341.149Skamil			DPRINTF("Before calling %s() for the tracee %d\n", TWAIT_FNAME,
34351.149Skamil			    tracee);
34361.149Skamil			TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0),
34371.149Skamil			    tracee);
34381.149Skamil
34391.149Skamil			validate_status_stopped(status, SIGTRAP);
34401.149Skamil
34411.149Skamil			SYSCALL_REQUIRE(
34421.149Skamil			    ptrace(PT_GET_PROCESS_STATE, tracee, &state, slen) != -1);
34431.149Skamil			if (trackspawn && strcmp(fn, "spawn") == 0) {
34441.149Skamil				ATF_REQUIRE_EQ(
34451.149Skamil				    state.pe_report_event & PTRACE_POSIX_SPAWN,
34461.149Skamil				       PTRACE_POSIX_SPAWN);
34471.149Skamil			}
34481.149Skamil			if (trackfork && strcmp(fn, "fork") == 0) {
34491.149Skamil				ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
34501.149Skamil				       PTRACE_FORK);
34511.149Skamil			}
34521.149Skamil			if (trackvfork && strcmp(fn, "vfork") == 0) {
34531.149Skamil				ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
34541.149Skamil				       PTRACE_VFORK);
34551.149Skamil			}
34561.149Skamil
34571.149Skamil			tracee2 = state.pe_other_pid;
34581.149Skamil			DPRINTF("Reported ptrace event with forkee %d\n", tracee2);
34591.149Skamil
34601.149Skamil			DPRINTF("Before calling %s() for the forkee %d of the tracee "
34611.149Skamil			    "%d\n", TWAIT_FNAME, tracee2, tracee);
34621.149Skamil			TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee2, &status, 0),
34631.149Skamil			    tracee2);
34641.149Skamil
34651.149Skamil			validate_status_stopped(status, SIGTRAP);
34661.149Skamil
34671.149Skamil			SYSCALL_REQUIRE(
34681.149Skamil			    ptrace(PT_GET_PROCESS_STATE, tracee2, &state, slen) != -1);
34691.149Skamil			if (trackspawn && strcmp(fn, "spawn") == 0) {
34701.149Skamil				ATF_REQUIRE_EQ(
34711.149Skamil				    state.pe_report_event & PTRACE_POSIX_SPAWN,
34721.149Skamil				       PTRACE_POSIX_SPAWN);
34731.149Skamil			}
34741.149Skamil			if (trackfork && strcmp(fn, "fork") == 0) {
34751.149Skamil				ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
34761.149Skamil				       PTRACE_FORK);
34771.149Skamil			}
34781.149Skamil			if (trackvfork && strcmp(fn, "vfork") == 0) {
34791.149Skamil				ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
34801.149Skamil				       PTRACE_VFORK);
34811.149Skamil			}
34821.149Skamil
34831.149Skamil			ATF_REQUIRE_EQ(state.pe_other_pid, tracee);
34841.149Skamil
34851.149Skamil			DPRINTF("Before resuming the forkee process where it left off "
34861.149Skamil			    "and without signal to be sent\n");
34871.149Skamil			SYSCALL_REQUIRE(
34881.149Skamil			    ptrace(PT_CONTINUE, tracee2, (void *)1, 0) != -1);
34891.149Skamil
34901.149Skamil			DPRINTF("Before resuming the tracee process where it left off "
34911.149Skamil			    "and without signal to be sent\n");
34921.149Skamil			SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
34931.149Skamil		}
34941.149Skamil
34951.149Skamil		if (trackvforkdone && strcmp(fn, "vfork") == 0) {
34961.149Skamil			DPRINTF("Before calling %s() for the tracee %d\n", TWAIT_FNAME,
34971.149Skamil			    tracee);
34981.149Skamil			TWAIT_REQUIRE_SUCCESS(
34991.149Skamil			    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
35001.149Skamil
35011.149Skamil			validate_status_stopped(status, SIGTRAP);
35021.149Skamil
35031.149Skamil			SYSCALL_REQUIRE(
35041.149Skamil			    ptrace(PT_GET_PROCESS_STATE, tracee, &state, slen) != -1);
35051.149Skamil			ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
35061.149Skamil
35071.149Skamil			tracee2 = state.pe_other_pid;
35081.149Skamil			DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
35091.149Skamil			    tracee2);
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
35171.149Skamil		if ((trackspawn && strcmp(fn, "spawn") == 0) ||
35181.149Skamil		    (trackfork && strcmp(fn, "fork") == 0) ||
35191.149Skamil		    (trackvfork && strcmp(fn, "vfork") == 0)) {
35201.149Skamil			DPRINTF("Before calling %s() for the forkee - expected exited"
35211.149Skamil			    "\n", TWAIT_FNAME);
35221.149Skamil			TWAIT_REQUIRE_SUCCESS(
35231.149Skamil			    wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
35241.149Skamil
35251.149Skamil			validate_status_exited(status, exitval2);
35261.149Skamil
35271.149Skamil			DPRINTF("Before calling %s() for the forkee - expected no "
35281.149Skamil			    "process\n", TWAIT_FNAME);
35291.149Skamil			TWAIT_REQUIRE_FAILURE(ECHILD,
35301.149Skamil			    wpid = TWAIT_GENERIC(tracee2, &status, 0));
35311.149Skamil		}
35321.149Skamil
35331.149Skamil		DPRINTF("Before calling %s() for the tracee - expected stopped "
35341.149Skamil		    "SIGCHLD\n", TWAIT_FNAME);
35351.149Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
35361.149Skamil
35371.149Skamil		validate_status_stopped(status, SIGCHLD);
35381.149Skamil
35391.149Skamil		DPRINTF("Before resuming the tracee process where it left off and "
35401.149Skamil		    "without signal to be sent\n");
35411.149Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
35421.149Skamil
35431.149Skamil		DPRINTF("Before calling %s() for the tracee - expected exited\n",
35441.149Skamil		    TWAIT_FNAME);
35451.149Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
35461.149Skamil
35471.149Skamil		validate_status_exited(status, exitval);
35481.149Skamil
35491.149Skamil		/* Inform parent that tracer is exiting normally */
35501.149Skamil		CHILD_TO_PARENT("tracer done", parent_tracer, msg);
35511.149Skamil
35521.149Skamil		DPRINTF("Before exiting of the tracer process\n");
35531.149Skamil		_exit(0 /* collect by initproc */);
35541.149Skamil	}
35551.149Skamil
35561.149Skamil	DPRINTF("Wait for the tracer process (direct child) to exit "
35571.149Skamil	    "calling %s()\n", TWAIT_FNAME);
35581.149Skamil	TWAIT_REQUIRE_SUCCESS(
35591.149Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
35601.149Skamil
35611.149Skamil	validate_status_exited(status, exitval);
35621.149Skamil
35631.149Skamil	DPRINTF("Wait for the non-exited tracee process with %s()\n",
35641.149Skamil	    TWAIT_FNAME);
35651.149Skamil	TWAIT_REQUIRE_SUCCESS(
35661.149Skamil	    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
35671.149Skamil
35681.149Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
35691.149Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
35701.149Skamil
35711.149Skamil	DPRINTF("Resume the tracee and let it crash\n");
35721.149Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
35731.149Skamil
35741.149Skamil	DPRINTF("Resume the tracer and let it detect crashed tracee\n");
35751.149Skamil	PARENT_TO_CHILD("Message 2", parent_tracer, msg);
35761.149Skamil
35771.149Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
35781.149Skamil	    TWAIT_FNAME);
35791.149Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
35801.149Skamil
35811.149Skamil	validate_status_exited(status, exitval);
35821.149Skamil
35831.149Skamil	DPRINTF("Await normal exit of tracer\n");
35841.149Skamil	PARENT_FROM_CHILD("tracer done", parent_tracer, msg);
35851.149Skamil
35861.149Skamil	msg_close(&parent_tracer);
35871.149Skamil	msg_close(&parent_tracee);
35881.149Skamil}
35891.149Skamil
35901.149Skamil#define UNRELATED_TRACER_FORK_TEST(name,fun,tspawn,tfork,tvfork,tvforkdone)\
35911.149SkamilATF_TC(name);								\
35921.149SkamilATF_TC_HEAD(name, tc)							\
35931.149Skamil{									\
35941.149Skamil	atf_tc_set_md_var(tc, "descr", "Verify " fun "() "		\
35951.149Skamil	    "called with 0%s%s%s%s in EVENT_MASK",			\
35961.149Skamil	    tspawn ? "|PTRACE_POSIX_SPAWN" : "",			\
35971.149Skamil	    tfork ? "|PTRACE_FORK" : "",				\
35981.149Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
35991.149Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
36001.149Skamil}									\
36011.149Skamil									\
36021.149SkamilATF_TC_BODY(name, tc)							\
36031.149Skamil{									\
36041.149Skamil									\
36051.149Skamil	unrelated_tracer_fork_body(fun, tspawn, tfork, tvfork,		\
36061.149Skamil	    tvforkdone);						\
36071.149Skamil}
36081.149Skamil
36091.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork1, "fork", false, false, false, false)
36101.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork2, "fork", false, true, false, false)
36111.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork3, "fork", false, false, true, false)
36121.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork4, "fork", false, true, true, false)
36131.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork5, "fork", false, false, false, true)
36141.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork6, "fork", false, true, false, true)
36151.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork7, "fork", false, false, true, true)
36161.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork8, "fork", false, true, true, true)
36171.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork9, "fork", true, false, false, false)
36181.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork10, "fork", true, true, false, false)
36191.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork11, "fork", true, false, true, false)
36201.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork12, "fork", true, true, true, false)
36211.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork13, "fork", true, false, false, true)
36221.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork14, "fork", true, true, false, true)
36231.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork15, "fork", true, false, true, true)
36241.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork16, "fork", true, true, true, true)
36251.149Skamil
36261.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork1, "vfork", false, false, false, false)
36271.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork2, "vfork", false, true, false, false)
36281.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork3, "vfork", false, false, true, false)
36291.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork4, "vfork", false, true, true, false)
36301.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork5, "vfork", false, false, false, true)
36311.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork6, "vfork", false, true, false, true)
36321.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork7, "vfork", false, false, true, true)
36331.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork8, "vfork", false, true, true, true)
36341.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork9, "vfork", true, false, false, false)
36351.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork10, "vfork", true, true, false, false)
36361.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork11, "vfork", true, false, true, false)
36371.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork12, "vfork", true, true, true, false)
36381.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork13, "vfork", true, false, false, true)
36391.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork14, "vfork", true, true, false, true)
36401.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork15, "vfork", true, false, true, true)
36411.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork16, "vfork", true, true, true, true)
36421.149Skamil
36431.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn1, "spawn", false, false, false, false)
36441.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn2, "spawn", false, true, false, false)
36451.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn3, "spawn", false, false, true, false)
36461.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn4, "spawn", false, true, true, false)
36471.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn5, "spawn", false, false, false, true)
36481.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn6, "spawn", false, true, false, true)
36491.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn7, "spawn", false, false, true, true)
36501.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn8, "spawn", false, true, true, true)
36511.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn9, "spawn", true, false, false, false)
36521.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn10, "spawn", true, true, false, false)
36531.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn11, "spawn", true, false, true, false)
36541.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn12, "spawn", true, true, true, false)
36551.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn13, "spawn", true, false, false, true)
36561.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn14, "spawn", true, true, false, true)
36571.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn15, "spawn", true, false, true, true)
36581.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn16, "spawn", true, true, true, true)
36591.149Skamil#endif
36601.149Skamil
36611.149Skamil/// ----------------------------------------------------------------------------
36621.149Skamil
36631.149Skamil#if defined(TWAIT_HAVE_PID)
36641.149Skamilstatic void
36651.126Skamilfork_detach_forker_body(const char *fn, bool kill_process)
36661.116Skamil{
36671.116Skamil	const int exitval = 5;
36681.126Skamil	const int exitval2 = 0; /* Matches exit value from /bin/echo */
36691.116Skamil	const int sigval = SIGSTOP;
36701.116Skamil	pid_t child, child2 = 0, wpid;
36711.116Skamil#if defined(TWAIT_HAVE_STATUS)
36721.116Skamil	int status;
36731.116Skamil#endif
36741.116Skamil	ptrace_state_t state;
36751.116Skamil	const int slen = sizeof(state);
36761.116Skamil	ptrace_event_t event;
36771.116Skamil	const int elen = sizeof(event);
36781.116Skamil
36791.116Skamil	int op;
36801.116Skamil
36811.126Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
36821.116Skamil
36831.116Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
36841.116Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
36851.116Skamil	if (child == 0) {
36861.116Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
36871.116Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
36881.116Skamil
36891.116Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
36901.116Skamil		FORKEE_ASSERT(raise(sigval) == 0);
36911.116Skamil
36921.126Skamil		if (strcmp(fn, "spawn") == 0) {
36931.126Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
36941.126Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
36951.126Skamil		} else  {
36961.126Skamil			if (strcmp(fn, "fork") == 0) {
36971.126Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
36981.126Skamil			} else {
36991.126Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
37001.126Skamil			}
37011.116Skamil
37021.126Skamil			if (child2 == 0)
37031.126Skamil				_exit(exitval2);
37041.126Skamil		}
37051.116Skamil
37061.116Skamil		FORKEE_REQUIRE_SUCCESS
37071.116Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
37081.116Skamil
37091.116Skamil		forkee_status_exited(status, exitval2);
37101.116Skamil
37111.116Skamil		DPRINTF("Before exiting of the child process\n");
37121.116Skamil		_exit(exitval);
37131.116Skamil	}
37141.116Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
37151.116Skamil
37161.116Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
37171.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
37181.116Skamil
37191.116Skamil	validate_status_stopped(status, sigval);
37201.116Skamil
37211.116Skamil	DPRINTF("Set EVENT_MASK for the child %d\n", child);
37221.126Skamil	event.pe_set_event = PTRACE_POSIX_SPAWN | PTRACE_FORK | PTRACE_VFORK
37231.126Skamil		| PTRACE_VFORK_DONE;
37241.116Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
37251.116Skamil
37261.116Skamil	DPRINTF("Before resuming the child process where it left off and "
37271.116Skamil	    "without signal to be sent\n");
37281.116Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
37291.116Skamil
37301.116Skamil	DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME, child);
37311.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
37321.116Skamil
37331.116Skamil	validate_status_stopped(status, SIGTRAP);
37341.116Skamil
37351.116Skamil	SYSCALL_REQUIRE(
37361.116Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
37371.126Skamil
37381.126Skamil	if (strcmp(fn, "spawn") == 0)
37391.126Skamil		op = PTRACE_POSIX_SPAWN;
37401.126Skamil	else if (strcmp(fn, "fork") == 0)
37411.126Skamil		op = PTRACE_FORK;
37421.126Skamil	else
37431.126Skamil		op = PTRACE_VFORK;
37441.126Skamil
37451.116Skamil	ATF_REQUIRE_EQ(state.pe_report_event & op, op);
37461.116Skamil
37471.116Skamil	child2 = state.pe_other_pid;
37481.116Skamil	DPRINTF("Reported ptrace event with forkee %d\n", child2);
37491.116Skamil
37501.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
37511.126Skamil	    strcmp(fn, "vfork") == 0)
37521.116Skamil		op = kill_process ? PT_KILL : PT_DETACH;
37531.116Skamil	else
37541.116Skamil		op = PT_CONTINUE;
37551.116Skamil	SYSCALL_REQUIRE(ptrace(op, child, (void *)1, 0) != -1);
37561.116Skamil
37571.116Skamil	DPRINTF("Before calling %s() for the forkee %d of the child %d\n",
37581.116Skamil	    TWAIT_FNAME, child2, child);
37591.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0), child2);
37601.116Skamil
37611.116Skamil	validate_status_stopped(status, SIGTRAP);
37621.116Skamil
37631.116Skamil	SYSCALL_REQUIRE(
37641.116Skamil	    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
37651.126Skamil	if (strcmp(fn, "spawn") == 0)
37661.126Skamil		op = PTRACE_POSIX_SPAWN;
37671.126Skamil	else if (strcmp(fn, "fork") == 0)
37681.126Skamil		op = PTRACE_FORK;
37691.126Skamil	else
37701.126Skamil		op = PTRACE_VFORK;
37711.126Skamil
37721.116Skamil	ATF_REQUIRE_EQ(state.pe_report_event & op, op);
37731.116Skamil	ATF_REQUIRE_EQ(state.pe_other_pid, child);
37741.116Skamil
37751.116Skamil	DPRINTF("Before resuming the forkee process where it left off "
37761.116Skamil	    "and without signal to be sent\n");
37771.116Skamil 	SYSCALL_REQUIRE(
37781.116Skamil	    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
37791.116Skamil
37801.126Skamil	if (strcmp(fn, "vforkdone") == 0) {
37811.116Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
37821.116Skamil		    child);
37831.116Skamil		TWAIT_REQUIRE_SUCCESS(
37841.116Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
37851.116Skamil
37861.116Skamil		validate_status_stopped(status, SIGTRAP);
37871.116Skamil
37881.116Skamil		SYSCALL_REQUIRE(
37891.116Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
37901.116Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
37911.116Skamil
37921.116Skamil		child2 = state.pe_other_pid;
37931.116Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
37941.116Skamil		    child2);
37951.116Skamil
37961.116Skamil		op = kill_process ? PT_KILL : PT_DETACH;
37971.116Skamil		DPRINTF("Before resuming the child process where it left off "
37981.116Skamil		    "and without signal to be sent\n");
37991.116Skamil		SYSCALL_REQUIRE(ptrace(op, child, (void *)1, 0) != -1);
38001.116Skamil	}
38011.116Skamil
38021.116Skamil	DPRINTF("Before calling %s() for the forkee - expected exited\n",
38031.116Skamil	    TWAIT_FNAME);
38041.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0), child2);
38051.116Skamil
38061.116Skamil	validate_status_exited(status, exitval2);
38071.116Skamil
38081.116Skamil	DPRINTF("Before calling %s() for the forkee - expected no process\n",
38091.116Skamil	    TWAIT_FNAME);
38101.116Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child2, &status, 0));
38111.116Skamil
38121.116Skamil	DPRINTF("Before calling %s() for the forkee - expected exited\n",
38131.116Skamil	    TWAIT_FNAME);
38141.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
38151.116Skamil
38161.116Skamil	if (kill_process) {
38171.116Skamil		validate_status_signaled(status, SIGKILL, 0);
38181.116Skamil	} else {
38191.116Skamil		validate_status_exited(status, exitval);
38201.116Skamil	}
38211.116Skamil
38221.116Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
38231.116Skamil	    TWAIT_FNAME);
38241.116Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
38251.116Skamil}
38261.116Skamil
38271.126Skamil#define FORK_DETACH_FORKER(name,event,kprocess)				\
38281.116SkamilATF_TC(name);								\
38291.116SkamilATF_TC_HEAD(name, tc)							\
38301.116Skamil{									\
38311.126Skamil	atf_tc_set_md_var(tc, "descr", "Verify %s " event,		\
38321.126Skamil	    kprocess ? "killed" : "detached");				\
38331.116Skamil}									\
38341.116Skamil									\
38351.116SkamilATF_TC_BODY(name, tc)							\
38361.116Skamil{									\
38371.116Skamil									\
38381.126Skamil	fork_detach_forker_body(event, kprocess);			\
38391.116Skamil}
38401.116Skamil
38411.126SkamilFORK_DETACH_FORKER(posix_spawn_detach_spawner, "spawn", false)
38421.126SkamilFORK_DETACH_FORKER(fork_detach_forker, "fork", false)
38431.126SkamilFORK_DETACH_FORKER(vfork_detach_vforker, "vfork", false)
38441.126SkamilFORK_DETACH_FORKER(vfork_detach_vforkerdone, "vforkdone", false)
38451.126Skamil
38461.126SkamilFORK_DETACH_FORKER(posix_spawn_kill_spawner, "spawn", true)
38471.126SkamilFORK_DETACH_FORKER(fork_kill_forker, "fork", true)
38481.126SkamilFORK_DETACH_FORKER(vfork_kill_vforker, "vfork", true)
38491.126SkamilFORK_DETACH_FORKER(vfork_kill_vforkerdone, "vforkdone", true)
38501.116Skamil#endif
38511.116Skamil
38521.116Skamil/// ----------------------------------------------------------------------------
38531.116Skamil
38541.150Skamil#if defined(TWAIT_HAVE_PID)
38551.150Skamilstatic void
38561.150Skamilunrelated_tracer_fork_detach_forker_body(const char *fn, bool kill_process)
38571.150Skamil{
38581.150Skamil	const int sigval = SIGSTOP;
38591.150Skamil	struct msg_fds parent_tracee, parent_tracer;
38601.150Skamil	const int exitval = 10;
38611.150Skamil	const int exitval2 = 0; /* This matched exit status from /bin/echo */
38621.150Skamil	pid_t tracee, tracer, wpid;
38631.150Skamil	pid_t tracee2 = 0;
38641.150Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
38651.150Skamil#if defined(TWAIT_HAVE_STATUS)
38661.150Skamil	int status;
38671.150Skamil#endif
38681.150Skamil	int op;
38691.150Skamil
38701.150Skamil	struct ptrace_siginfo info;
38711.150Skamil	ptrace_state_t state;
38721.150Skamil	const int slen = sizeof(state);
38731.150Skamil	ptrace_event_t event;
38741.150Skamil	const int elen = sizeof(event);
38751.150Skamil
38761.150Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
38771.150Skamil
38781.150Skamil	DPRINTF("Spawn tracee\n");
38791.150Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
38801.150Skamil	tracee = atf_utils_fork();
38811.150Skamil	if (tracee == 0) {
38821.150Skamil		// Wait for parent to let us crash
38831.150Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
38841.150Skamil
38851.150Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
38861.150Skamil		FORKEE_ASSERT(raise(sigval) == 0);
38871.150Skamil
38881.150Skamil		if (strcmp(fn, "spawn") == 0) {
38891.150Skamil			FORKEE_ASSERT_EQ(posix_spawn(&tracee2,
38901.150Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
38911.150Skamil		} else  {
38921.150Skamil			if (strcmp(fn, "fork") == 0) {
38931.150Skamil				FORKEE_ASSERT((tracee2 = fork()) != -1);
38941.150Skamil			} else {
38951.150Skamil				FORKEE_ASSERT((tracee2 = vfork()) != -1);
38961.150Skamil			}
38971.150Skamil
38981.150Skamil			if (tracee2 == 0)
38991.150Skamil				_exit(exitval2);
39001.150Skamil		}
39011.150Skamil
39021.150Skamil		FORKEE_REQUIRE_SUCCESS
39031.150Skamil		    (wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
39041.150Skamil
39051.150Skamil		forkee_status_exited(status, exitval2);
39061.150Skamil
39071.150Skamil		DPRINTF("Before exiting of the child process\n");
39081.150Skamil		_exit(exitval);
39091.150Skamil	}
39101.150Skamil
39111.150Skamil	DPRINTF("Spawn debugger\n");
39121.150Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
39131.150Skamil	tracer = atf_utils_fork();
39141.150Skamil	if (tracer == 0) {
39151.150Skamil		/* Fork again and drop parent to reattach to PID 1 */
39161.150Skamil		tracer = atf_utils_fork();
39171.150Skamil		if (tracer != 0)
39181.150Skamil			_exit(exitval);
39191.150Skamil
39201.150Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
39211.150Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
39221.150Skamil
39231.150Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
39241.150Skamil		FORKEE_REQUIRE_SUCCESS(
39251.150Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
39261.150Skamil
39271.150Skamil		forkee_status_stopped(status, SIGSTOP);
39281.150Skamil
39291.150Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
39301.150Skamil		    "traced process\n");
39311.150Skamil		SYSCALL_REQUIRE(
39321.150Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
39331.150Skamil
39341.150Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
39351.150Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
39361.150Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
39371.150Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
39381.150Skamil
39391.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
39401.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
39411.150Skamil
39421.150Skamil		/* Resume tracee with PT_CONTINUE */
39431.150Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
39441.150Skamil
39451.150Skamil		/* Inform parent that tracer has attached to tracee */
39461.150Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
39471.150Skamil
39481.150Skamil		/* Wait for parent to tell use that tracee should have exited */
39491.150Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
39501.150Skamil
39511.150Skamil		/* Wait for tracee and assert that it exited */
39521.150Skamil		FORKEE_REQUIRE_SUCCESS(
39531.150Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
39541.150Skamil
39551.150Skamil		forkee_status_stopped(status, sigval);
39561.150Skamil
39571.150Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
39581.150Skamil		    "traced process\n");
39591.150Skamil		SYSCALL_REQUIRE(
39601.150Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
39611.150Skamil
39621.150Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
39631.150Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
39641.150Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
39651.150Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
39661.150Skamil
39671.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
39681.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
39691.150Skamil
39701.150Skamil		DPRINTF("Set EVENT_MASK for the child %d\n", tracee);
39711.150Skamil		event.pe_set_event = PTRACE_POSIX_SPAWN | PTRACE_FORK | PTRACE_VFORK
39721.150Skamil			| PTRACE_VFORK_DONE;
39731.150Skamil		SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, tracee, &event, elen) != -1);
39741.150Skamil
39751.150Skamil		DPRINTF("Before resuming the child process where it left off and "
39761.150Skamil		    "without signal to be sent\n");
39771.150Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
39781.150Skamil
39791.150Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME, tracee);
39801.150Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
39811.150Skamil
39821.150Skamil		validate_status_stopped(status, SIGTRAP);
39831.150Skamil
39841.150Skamil		SYSCALL_REQUIRE(
39851.150Skamil		    ptrace(PT_GET_PROCESS_STATE, tracee, &state, slen) != -1);
39861.150Skamil
39871.150Skamil		if (strcmp(fn, "spawn") == 0)
39881.150Skamil			op = PTRACE_POSIX_SPAWN;
39891.150Skamil		else if (strcmp(fn, "fork") == 0)
39901.150Skamil			op = PTRACE_FORK;
39911.150Skamil		else
39921.150Skamil			op = PTRACE_VFORK;
39931.150Skamil
39941.150Skamil		ATF_REQUIRE_EQ(state.pe_report_event & op, op);
39951.150Skamil
39961.150Skamil		tracee2 = state.pe_other_pid;
39971.150Skamil		DPRINTF("Reported ptrace event with forkee %d\n", tracee2);
39981.150Skamil		if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
39991.150Skamil		    strcmp(fn, "vfork") == 0)
40001.150Skamil			op = kill_process ? PT_KILL : PT_DETACH;
40011.150Skamil		else
40021.150Skamil			op = PT_CONTINUE;
40031.150Skamil		SYSCALL_REQUIRE(ptrace(op, tracee, (void *)1, 0) != -1);
40041.150Skamil
40051.150Skamil		DPRINTF("Before calling %s() for the forkee %d of the tracee %d\n",
40061.150Skamil		    TWAIT_FNAME, tracee2, tracee);
40071.150Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
40081.150Skamil
40091.150Skamil		validate_status_stopped(status, SIGTRAP);
40101.150Skamil
40111.150Skamil		SYSCALL_REQUIRE(
40121.150Skamil		    ptrace(PT_GET_PROCESS_STATE, tracee2, &state, slen) != -1);
40131.150Skamil		if (strcmp(fn, "spawn") == 0)
40141.150Skamil			op = PTRACE_POSIX_SPAWN;
40151.150Skamil		else if (strcmp(fn, "fork") == 0)
40161.150Skamil			op = PTRACE_FORK;
40171.150Skamil		else
40181.150Skamil			op = PTRACE_VFORK;
40191.150Skamil
40201.150Skamil		ATF_REQUIRE_EQ(state.pe_report_event & op, op);
40211.150Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, tracee);
40221.150Skamil
40231.150Skamil		DPRINTF("Before resuming the forkee process where it left off "
40241.150Skamil		    "and without signal to be sent\n");
40251.150Skamil		SYSCALL_REQUIRE(
40261.150Skamil		    ptrace(PT_CONTINUE, tracee2, (void *)1, 0) != -1);
40271.150Skamil
40281.150Skamil		if (strcmp(fn, "vforkdone") == 0) {
40291.150Skamil			DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
40301.150Skamil			    tracee);
40311.150Skamil			TWAIT_REQUIRE_SUCCESS(
40321.150Skamil			    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
40331.150Skamil
40341.150Skamil			validate_status_stopped(status, SIGTRAP);
40351.150Skamil
40361.150Skamil			SYSCALL_REQUIRE(
40371.150Skamil			    ptrace(PT_GET_PROCESS_STATE, tracee, &state, slen) != -1);
40381.150Skamil			ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
40391.150Skamil
40401.150Skamil			tracee2 = state.pe_other_pid;
40411.150Skamil			DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
40421.150Skamil			    tracee2);
40431.150Skamil
40441.150Skamil			op = kill_process ? PT_KILL : PT_DETACH;
40451.150Skamil			DPRINTF("Before resuming the child process where it left off "
40461.150Skamil			    "and without signal to be sent\n");
40471.150Skamil			SYSCALL_REQUIRE(ptrace(op, tracee, (void *)1, 0) != -1);
40481.150Skamil		}
40491.150Skamil
40501.150Skamil		DPRINTF("Before calling %s() for the forkee - expected exited\n",
40511.150Skamil		    TWAIT_FNAME);
40521.150Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
40531.150Skamil
40541.150Skamil		validate_status_exited(status, exitval2);
40551.150Skamil
40561.150Skamil		DPRINTF("Before calling %s() for the forkee - expected no process\n",
40571.150Skamil		    TWAIT_FNAME);
40581.150Skamil		TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(tracee2, &status, 0));
40591.150Skamil
40601.150Skamil		if (kill_process) {
40611.150Skamil			DPRINTF("Before calling %s() for the forkee - expected signaled\n",
40621.150Skamil			    TWAIT_FNAME);
40631.150Skamil			TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
40641.150Skamil
40651.150Skamil			validate_status_signaled(status, SIGKILL, 0);
40661.150Skamil		}
40671.150Skamil
40681.150Skamil		/* Inform parent that tracer is exiting normally */
40691.150Skamil		CHILD_TO_PARENT("tracer done", parent_tracer, msg);
40701.150Skamil
40711.150Skamil		DPRINTF("Before exiting of the tracer process\n");
40721.150Skamil		_exit(0 /* collect by initproc */);
40731.150Skamil	}
40741.150Skamil
40751.150Skamil	DPRINTF("Wait for the tracer process (direct child) to exit "
40761.150Skamil	    "calling %s()\n", TWAIT_FNAME);
40771.150Skamil	TWAIT_REQUIRE_SUCCESS(
40781.150Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
40791.150Skamil
40801.150Skamil	validate_status_exited(status, exitval);
40811.150Skamil
40821.150Skamil	DPRINTF("Wait for the non-exited tracee process with %s()\n",
40831.150Skamil	    TWAIT_FNAME);
40841.150Skamil	TWAIT_REQUIRE_SUCCESS(
40851.150Skamil	    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
40861.150Skamil
40871.150Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
40881.150Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
40891.150Skamil
40901.150Skamil	DPRINTF("Resume the tracee and let it crash\n");
40911.150Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
40921.150Skamil
40931.150Skamil	DPRINTF("Resume the tracer and let it detect crashed tracee\n");
40941.150Skamil	PARENT_TO_CHILD("Message 2", parent_tracer, msg);
40951.150Skamil
40961.150Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
40971.150Skamil	    TWAIT_FNAME);
40981.150Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
40991.150Skamil
41001.150Skamil	if (kill_process) {
41011.150Skamil		validate_status_signaled(status, SIGKILL, 0);
41021.150Skamil	} else {
41031.150Skamil		validate_status_exited(status, exitval);
41041.150Skamil	}
41051.150Skamil
41061.150Skamil	DPRINTF("Await normal exit of tracer\n");
41071.150Skamil	PARENT_FROM_CHILD("tracer done", parent_tracer, msg);
41081.150Skamil
41091.150Skamil	msg_close(&parent_tracer);
41101.150Skamil	msg_close(&parent_tracee);
41111.150Skamil}
41121.150Skamil
41131.150Skamil#define UNRELATED_TRACER_FORK_DETACH_FORKER(name,event,kprocess)	\
41141.150SkamilATF_TC(name);								\
41151.150SkamilATF_TC_HEAD(name, tc)							\
41161.150Skamil{									\
41171.150Skamil	atf_tc_set_md_var(tc, "descr", "Verify %s " event,		\
41181.150Skamil	    kprocess ? "killed" : "detached");				\
41191.150Skamil}									\
41201.150Skamil									\
41211.150SkamilATF_TC_BODY(name, tc)							\
41221.150Skamil{									\
41231.150Skamil									\
41241.150Skamil	unrelated_tracer_fork_detach_forker_body(event, kprocess);	\
41251.150Skamil}
41261.150Skamil
41271.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_posix_spawn_detach_spawner, "spawn", false)
41281.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_fork_detach_forker, "fork", false)
41291.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_vfork_detach_vforker, "vfork", false)
41301.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_vfork_detach_vforkerdone, "vforkdone", false)
41311.150Skamil
41321.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_posix_spawn_kill_spawner, "spawn", true)
41331.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_fork_kill_forker, "fork", true)
41341.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_vfork_kill_vforker, "vfork", true)
41351.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_vfork_kill_vforkerdone, "vforkdone", true)
41361.150Skamil#endif
41371.150Skamil
41381.150Skamil/// ----------------------------------------------------------------------------
41391.150Skamil
41401.108Skamilstatic void
41411.108Skamiltraceme_vfork_fork_body(pid_t (*fn)(void))
41421.108Skamil{
41431.108Skamil	const int exitval = 5;
41441.108Skamil	const int exitval2 = 15;
41451.108Skamil	pid_t child, child2 = 0, wpid;
41461.108Skamil#if defined(TWAIT_HAVE_STATUS)
41471.108Skamil	int status;
41481.108Skamil#endif
41491.108Skamil
41501.108Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
41511.108Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
41521.108Skamil	if (child == 0) {
41531.108Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
41541.108Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
41551.108Skamil
41561.108Skamil		FORKEE_ASSERT((child2 = (fn)()) != -1);
41571.108Skamil
41581.108Skamil		if (child2 == 0)
41591.108Skamil			_exit(exitval2);
41601.108Skamil
41611.108Skamil		FORKEE_REQUIRE_SUCCESS
41621.108Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
41631.108Skamil
41641.108Skamil		forkee_status_exited(status, exitval2);
41651.108Skamil
41661.108Skamil		DPRINTF("Before exiting of the child process\n");
41671.108Skamil		_exit(exitval);
41681.108Skamil	}
41691.108Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
41701.108Skamil
41711.108Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
41721.108Skamil	    TWAIT_FNAME);
41731.108Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
41741.108Skamil
41751.108Skamil	validate_status_exited(status, exitval);
41761.108Skamil
41771.108Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
41781.108Skamil	    TWAIT_FNAME);
41791.108Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
41801.108Skamil}
41811.108Skamil
41821.108Skamil#define TRACEME_VFORK_FORK_TEST(name,fun)				\
41831.108SkamilATF_TC(name);								\
41841.108SkamilATF_TC_HEAD(name, tc)							\
41851.108Skamil{									\
41861.108Skamil	atf_tc_set_md_var(tc, "descr", "Verify " #fun "(2) "		\
41871.108Skamil	    "called from vfork(2)ed child");				\
41881.108Skamil}									\
41891.108Skamil									\
41901.108SkamilATF_TC_BODY(name, tc)							\
41911.108Skamil{									\
41921.108Skamil									\
41931.108Skamil	traceme_vfork_fork_body(fun);					\
41941.108Skamil}
41951.108Skamil
41961.108SkamilTRACEME_VFORK_FORK_TEST(traceme_vfork_fork, fork)
41971.108SkamilTRACEME_VFORK_FORK_TEST(traceme_vfork_vfork, vfork)
41981.108Skamil
41991.108Skamil/// ----------------------------------------------------------------------------
42001.108Skamil
42011.54Skamilenum bytes_transfer_type {
42021.54Skamil	BYTES_TRANSFER_DATA,
42031.54Skamil	BYTES_TRANSFER_DATAIO,
42041.54Skamil	BYTES_TRANSFER_TEXT,
42051.54Skamil	BYTES_TRANSFER_TEXTIO,
42061.54Skamil	BYTES_TRANSFER_AUXV
42071.54Skamil};
42081.31Skamil
42091.54Skamilstatic int __used
42101.54Skamilbytes_transfer_dummy(int a, int b, int c, int d)
42111.54Skamil{
42121.54Skamil	int e, f, g, h;
42131.1Skamil
42141.54Skamil	a *= 4;
42151.54Skamil	b += 3;
42161.54Skamil	c -= 2;
42171.54Skamil	d /= 1;
42181.1Skamil
42191.54Skamil	e = strtol("10", NULL, 10);
42201.54Skamil	f = strtol("20", NULL, 10);
42211.54Skamil	g = strtol("30", NULL, 10);
42221.54Skamil	h = strtol("40", NULL, 10);
42231.1Skamil
42241.54Skamil	return (a + b * c - d) + (e * f - g / h);
42251.1Skamil}
42261.1Skamil
42271.54Skamilstatic void
42281.55Schristosbytes_transfer(int operation, size_t size, enum bytes_transfer_type type)
42291.1Skamil{
42301.1Skamil	const int exitval = 5;
42311.1Skamil	const int sigval = SIGSTOP;
42321.1Skamil	pid_t child, wpid;
42331.54Skamil	bool skip = false;
42341.1Skamil
42351.54Skamil	int lookup_me = 0;
42361.54Skamil	uint8_t lookup_me8 = 0;
42371.54Skamil	uint16_t lookup_me16 = 0;
42381.54Skamil	uint32_t lookup_me32 = 0;
42391.54Skamil	uint64_t lookup_me64 = 0;
42401.1Skamil
42411.54Skamil	int magic = 0x13579246;
42421.54Skamil	uint8_t magic8 = 0xab;
42431.54Skamil	uint16_t magic16 = 0x1234;
42441.54Skamil	uint32_t magic32 = 0x98765432;
42451.54Skamil	uint64_t magic64 = 0xabcdef0123456789;
42461.1Skamil
42471.54Skamil	struct ptrace_io_desc io;
42481.1Skamil#if defined(TWAIT_HAVE_STATUS)
42491.1Skamil	int status;
42501.1Skamil#endif
42511.60Skre	/* 513 is just enough, for the purposes of ATF it's good enough */
42521.60Skre	AuxInfo ai[513], *aip;
42531.55Schristos
42541.55Schristos	ATF_REQUIRE(size < sizeof(ai));
42551.1Skamil
42561.54Skamil	/* Prepare variables for .TEXT transfers */
42571.54Skamil	switch (type) {
42581.54Skamil	case BYTES_TRANSFER_TEXT:
42591.54Skamil		memcpy(&magic, bytes_transfer_dummy, sizeof(magic));
42601.54Skamil		break;
42611.54Skamil	case BYTES_TRANSFER_TEXTIO:
42621.54Skamil		switch (size) {
42631.54Skamil		case 8:
42641.54Skamil			memcpy(&magic8, bytes_transfer_dummy, sizeof(magic8));
42651.54Skamil			break;
42661.54Skamil		case 16:
42671.54Skamil			memcpy(&magic16, bytes_transfer_dummy, sizeof(magic16));
42681.54Skamil			break;
42691.54Skamil		case 32:
42701.54Skamil			memcpy(&magic32, bytes_transfer_dummy, sizeof(magic32));
42711.54Skamil			break;
42721.54Skamil		case 64:
42731.54Skamil			memcpy(&magic64, bytes_transfer_dummy, sizeof(magic64));
42741.54Skamil			break;
42751.54Skamil		}
42761.54Skamil		break;
42771.54Skamil	default:
42781.54Skamil		break;
42791.54Skamil	}
42801.1Skamil
42811.54Skamil	/* Prepare variables for PIOD and AUXV transfers */
42821.54Skamil	switch (type) {
42831.54Skamil	case BYTES_TRANSFER_TEXTIO:
42841.54Skamil	case BYTES_TRANSFER_DATAIO:
42851.54Skamil		io.piod_op = operation;
42861.54Skamil		switch (size) {
42871.54Skamil		case 8:
42881.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
42891.54Skamil			               (void *)bytes_transfer_dummy :
42901.54Skamil			               &lookup_me8;
42911.54Skamil			io.piod_addr = &lookup_me8;
42921.54Skamil			io.piod_len = sizeof(lookup_me8);
42931.54Skamil			break;
42941.54Skamil		case 16:
42951.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
42961.54Skamil			               (void *)bytes_transfer_dummy :
42971.54Skamil			               &lookup_me16;
42981.54Skamil			io.piod_addr = &lookup_me16;
42991.54Skamil			io.piod_len = sizeof(lookup_me16);
43001.54Skamil			break;
43011.54Skamil		case 32:
43021.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
43031.54Skamil			               (void *)bytes_transfer_dummy :
43041.54Skamil			               &lookup_me32;
43051.54Skamil			io.piod_addr = &lookup_me32;
43061.54Skamil			io.piod_len = sizeof(lookup_me32);
43071.54Skamil			break;
43081.54Skamil		case 64:
43091.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
43101.54Skamil			               (void *)bytes_transfer_dummy :
43111.54Skamil			               &lookup_me64;
43121.54Skamil			io.piod_addr = &lookup_me64;
43131.54Skamil			io.piod_len = sizeof(lookup_me64);
43141.54Skamil			break;
43151.54Skamil		default:
43161.54Skamil			break;
43171.54Skamil		}
43181.54Skamil		break;
43191.54Skamil	case BYTES_TRANSFER_AUXV:
43201.54Skamil		io.piod_op = operation;
43211.54Skamil		io.piod_offs = 0;
43221.54Skamil		io.piod_addr = ai;
43231.54Skamil		io.piod_len = size;
43241.54Skamil		break;
43251.54Skamil	default:
43261.54Skamil		break;
43271.1Skamil	}
43281.1Skamil
43291.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
43301.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
43311.1Skamil	if (child == 0) {
43321.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
43331.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
43341.1Skamil
43351.54Skamil		switch (type) {
43361.54Skamil		case BYTES_TRANSFER_DATA:
43371.54Skamil			switch (operation) {
43381.54Skamil			case PT_READ_D:
43391.54Skamil			case PT_READ_I:
43401.54Skamil				lookup_me = magic;
43411.54Skamil				break;
43421.54Skamil			default:
43431.54Skamil				break;
43441.54Skamil			}
43451.54Skamil			break;
43461.54Skamil		case BYTES_TRANSFER_DATAIO:
43471.54Skamil			switch (operation) {
43481.54Skamil			case PIOD_READ_D:
43491.54Skamil			case PIOD_READ_I:
43501.54Skamil				switch (size) {
43511.54Skamil				case 8:
43521.54Skamil					lookup_me8 = magic8;
43531.54Skamil					break;
43541.54Skamil				case 16:
43551.54Skamil					lookup_me16 = magic16;
43561.54Skamil					break;
43571.54Skamil				case 32:
43581.54Skamil					lookup_me32 = magic32;
43591.54Skamil					break;
43601.54Skamil				case 64:
43611.54Skamil					lookup_me64 = magic64;
43621.54Skamil					break;
43631.54Skamil				default:
43641.54Skamil					break;
43651.54Skamil				}
43661.54Skamil				break;
43671.54Skamil			default:
43681.54Skamil				break;
43691.54Skamil			}
43701.54Skamil		default:
43711.54Skamil			break;
43721.54Skamil		}
43731.54Skamil
43741.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
43751.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
43761.1Skamil
43771.54Skamil		/* Handle PIOD and PT separately as operation values overlap */
43781.54Skamil		switch (type) {
43791.54Skamil		case BYTES_TRANSFER_DATA:
43801.54Skamil			switch (operation) {
43811.54Skamil			case PT_WRITE_D:
43821.54Skamil			case PT_WRITE_I:
43831.54Skamil				FORKEE_ASSERT_EQ(lookup_me, magic);
43841.54Skamil				break;
43851.54Skamil			default:
43861.54Skamil				break;
43871.54Skamil			}
43881.54Skamil			break;
43891.54Skamil		case BYTES_TRANSFER_DATAIO:
43901.54Skamil			switch (operation) {
43911.54Skamil			case PIOD_WRITE_D:
43921.54Skamil			case PIOD_WRITE_I:
43931.54Skamil				switch (size) {
43941.54Skamil				case 8:
43951.54Skamil					FORKEE_ASSERT_EQ(lookup_me8, magic8);
43961.54Skamil					break;
43971.54Skamil				case 16:
43981.54Skamil					FORKEE_ASSERT_EQ(lookup_me16, magic16);
43991.54Skamil					break;
44001.54Skamil				case 32:
44011.54Skamil					FORKEE_ASSERT_EQ(lookup_me32, magic32);
44021.54Skamil					break;
44031.54Skamil				case 64:
44041.54Skamil					FORKEE_ASSERT_EQ(lookup_me64, magic64);
44051.54Skamil					break;
44061.54Skamil				default:
44071.54Skamil					break;
44081.54Skamil				}
44091.54Skamil				break;
44101.54Skamil			default:
44111.54Skamil				break;
44121.54Skamil			}
44131.54Skamil			break;
44141.54Skamil		case BYTES_TRANSFER_TEXT:
44151.54Skamil			FORKEE_ASSERT(memcmp(&magic, bytes_transfer_dummy,
44161.54Skamil			                     sizeof(magic)) == 0);
44171.54Skamil			break;
44181.54Skamil		case BYTES_TRANSFER_TEXTIO:
44191.54Skamil			switch (size) {
44201.54Skamil			case 8:
44211.54Skamil				FORKEE_ASSERT(memcmp(&magic8,
44221.54Skamil				                     bytes_transfer_dummy,
44231.54Skamil				                     sizeof(magic8)) == 0);
44241.54Skamil				break;
44251.54Skamil			case 16:
44261.54Skamil				FORKEE_ASSERT(memcmp(&magic16,
44271.54Skamil				                     bytes_transfer_dummy,
44281.54Skamil				                     sizeof(magic16)) == 0);
44291.54Skamil				break;
44301.54Skamil			case 32:
44311.54Skamil				FORKEE_ASSERT(memcmp(&magic32,
44321.54Skamil				                     bytes_transfer_dummy,
44331.54Skamil				                     sizeof(magic32)) == 0);
44341.54Skamil				break;
44351.54Skamil			case 64:
44361.54Skamil				FORKEE_ASSERT(memcmp(&magic64,
44371.54Skamil				                     bytes_transfer_dummy,
44381.54Skamil				                     sizeof(magic64)) == 0);
44391.54Skamil				break;
44401.54Skamil			}
44411.54Skamil			break;
44421.54Skamil		default:
44431.54Skamil			break;
44441.54Skamil		}
44451.54Skamil
44461.13Schristos		DPRINTF("Before exiting of the child process\n");
44471.1Skamil		_exit(exitval);
44481.1Skamil	}
44491.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
44501.1Skamil
44511.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
44521.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
44531.1Skamil
44541.1Skamil	validate_status_stopped(status, sigval);
44551.1Skamil
44561.54Skamil	/* Check PaX MPROTECT */
44571.54Skamil	if (!can_we_write_to_text(child)) {
44581.54Skamil		switch (type) {
44591.54Skamil		case BYTES_TRANSFER_TEXTIO:
44601.54Skamil			switch (operation) {
44611.54Skamil			case PIOD_WRITE_D:
44621.54Skamil			case PIOD_WRITE_I:
44631.54Skamil				skip = true;
44641.54Skamil				break;
44651.54Skamil			default:
44661.54Skamil				break;
44671.54Skamil			}
44681.54Skamil			break;
44691.54Skamil		case BYTES_TRANSFER_TEXT:
44701.54Skamil			switch (operation) {
44711.54Skamil			case PT_WRITE_D:
44721.54Skamil			case PT_WRITE_I:
44731.54Skamil				skip = true;
44741.54Skamil				break;
44751.54Skamil			default:
44761.54Skamil				break;
44771.54Skamil			}
44781.54Skamil			break;
44791.54Skamil		default:
44801.54Skamil			break;
44811.54Skamil		}
44821.54Skamil	}
44831.1Skamil
44841.54Skamil	/* Bailout cleanly killing the child process */
44851.54Skamil	if (skip) {
44861.54Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
44871.54Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
44881.54Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
44891.54Skamil		                      child);
44901.1Skamil
44911.54Skamil		validate_status_signaled(status, SIGKILL, 0);
44921.1Skamil
44931.54Skamil		atf_tc_skip("PaX MPROTECT setup prevents writes to .text");
44941.54Skamil	}
44951.1Skamil
44961.54Skamil	DPRINTF("Calling operation to transfer bytes between child=%d and "
44971.54Skamil	       "parent=%d\n", child, getpid());
44981.1Skamil
44991.54Skamil	switch (type) {
45001.54Skamil	case BYTES_TRANSFER_TEXTIO:
45011.54Skamil	case BYTES_TRANSFER_DATAIO:
45021.54Skamil	case BYTES_TRANSFER_AUXV:
45031.54Skamil		switch (operation) {
45041.54Skamil		case PIOD_WRITE_D:
45051.54Skamil		case PIOD_WRITE_I:
45061.54Skamil			switch (size) {
45071.54Skamil			case 8:
45081.54Skamil				lookup_me8 = magic8;
45091.54Skamil				break;
45101.54Skamil			case 16:
45111.54Skamil				lookup_me16 = magic16;
45121.54Skamil				break;
45131.54Skamil			case 32:
45141.54Skamil				lookup_me32 = magic32;
45151.54Skamil				break;
45161.54Skamil			case 64:
45171.54Skamil				lookup_me64 = magic64;
45181.54Skamil				break;
45191.54Skamil			default:
45201.54Skamil				break;
45211.54Skamil			}
45221.54Skamil			break;
45231.54Skamil		default:
45241.54Skamil			break;
45251.54Skamil		}
45261.54Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
45271.54Skamil		switch (operation) {
45281.54Skamil		case PIOD_READ_D:
45291.54Skamil		case PIOD_READ_I:
45301.54Skamil			switch (size) {
45311.54Skamil			case 8:
45321.54Skamil				ATF_REQUIRE_EQ(lookup_me8, magic8);
45331.54Skamil				break;
45341.54Skamil			case 16:
45351.54Skamil				ATF_REQUIRE_EQ(lookup_me16, magic16);
45361.54Skamil				break;
45371.54Skamil			case 32:
45381.54Skamil				ATF_REQUIRE_EQ(lookup_me32, magic32);
45391.54Skamil				break;
45401.54Skamil			case 64:
45411.54Skamil				ATF_REQUIRE_EQ(lookup_me64, magic64);
45421.54Skamil				break;
45431.54Skamil			default:
45441.54Skamil				break;
45451.54Skamil			}
45461.54Skamil			break;
45471.54Skamil		case PIOD_READ_AUXV:
45481.54Skamil			DPRINTF("Asserting that AUXV length (%zu) is > 0\n",
45491.54Skamil			        io.piod_len);
45501.54Skamil			ATF_REQUIRE(io.piod_len > 0);
45511.54Skamil			for (aip = ai; aip->a_type != AT_NULL; aip++)
45521.54Skamil				DPRINTF("a_type=%#llx a_v=%#llx\n",
45531.54Skamil				    (long long int)aip->a_type,
45541.54Skamil				    (long long int)aip->a_v);
45551.54Skamil			break;
45561.54Skamil		default:
45571.54Skamil			break;
45581.54Skamil		}
45591.54Skamil		break;
45601.54Skamil	case BYTES_TRANSFER_TEXT:
45611.54Skamil		switch (operation) {
45621.54Skamil		case PT_READ_D:
45631.54Skamil		case PT_READ_I:
45641.54Skamil			errno = 0;
45651.54Skamil			lookup_me = ptrace(operation, child,
45661.54Skamil			                   bytes_transfer_dummy, 0);
45671.54Skamil			ATF_REQUIRE_EQ(lookup_me, magic);
45681.54Skamil			SYSCALL_REQUIRE_ERRNO(errno, 0);
45691.54Skamil			break;
45701.54Skamil		case PT_WRITE_D:
45711.54Skamil		case PT_WRITE_I:
45721.54Skamil			SYSCALL_REQUIRE(ptrace(operation, child,
45731.54Skamil			                       bytes_transfer_dummy, magic)
45741.54Skamil			                != -1);
45751.54Skamil			break;
45761.54Skamil		default:
45771.54Skamil			break;
45781.54Skamil		}
45791.54Skamil		break;
45801.54Skamil	case BYTES_TRANSFER_DATA:
45811.54Skamil		switch (operation) {
45821.54Skamil		case PT_READ_D:
45831.54Skamil		case PT_READ_I:
45841.54Skamil			errno = 0;
45851.54Skamil			lookup_me = ptrace(operation, child, &lookup_me, 0);
45861.54Skamil			ATF_REQUIRE_EQ(lookup_me, magic);
45871.54Skamil			SYSCALL_REQUIRE_ERRNO(errno, 0);
45881.54Skamil			break;
45891.54Skamil		case PT_WRITE_D:
45901.54Skamil		case PT_WRITE_I:
45911.54Skamil			lookup_me = magic;
45921.54Skamil			SYSCALL_REQUIRE(ptrace(operation, child, &lookup_me,
45931.54Skamil			                       magic) != -1);
45941.54Skamil			break;
45951.54Skamil		default:
45961.54Skamil			break;
45971.54Skamil		}
45981.54Skamil		break;
45991.54Skamil	default:
46001.54Skamil		break;
46011.54Skamil	}
46021.1Skamil
46031.13Schristos	DPRINTF("Before resuming the child process where it left off and "
46041.1Skamil	    "without signal to be sent\n");
46051.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
46061.1Skamil
46071.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46081.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
46091.1Skamil
46101.1Skamil	validate_status_exited(status, exitval);
46111.1Skamil
46121.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46131.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
46141.1Skamil}
46151.1Skamil
46161.61Skre#define BYTES_TRANSFER(test, operation, size, type)			\
46171.61SkreATF_TC(test);								\
46181.61SkreATF_TC_HEAD(test, tc)							\
46191.61Skre{									\
46201.61Skre	atf_tc_set_md_var(tc, "descr",					\
46211.61Skre	    "Verify bytes transfer operation" #operation " and size " #size \
46221.61Skre	    " of type " #type);						\
46231.61Skre}									\
46241.61Skre									\
46251.61SkreATF_TC_BODY(test, tc)							\
46261.61Skre{									\
46271.61Skre									\
46281.61Skre	bytes_transfer(operation, size, BYTES_TRANSFER_##type);		\
46291.1Skamil}
46301.1Skamil
46311.54Skamil// DATA
46321.1Skamil
46331.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_8, PIOD_READ_D, 8, DATAIO)
46341.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_16, PIOD_READ_D, 16, DATAIO)
46351.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_32, PIOD_READ_D, 32, DATAIO)
46361.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_64, PIOD_READ_D, 64, DATAIO)
46371.54Skamil
46381.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_8, PIOD_READ_I, 8, DATAIO)
46391.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_16, PIOD_READ_I, 16, DATAIO)
46401.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_32, PIOD_READ_I, 32, DATAIO)
46411.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_64, PIOD_READ_I, 64, DATAIO)
46421.54Skamil
46431.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_8, PIOD_WRITE_D, 8, DATAIO)
46441.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_16, PIOD_WRITE_D, 16, DATAIO)
46451.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_32, PIOD_WRITE_D, 32, DATAIO)
46461.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_64, PIOD_WRITE_D, 64, DATAIO)
46471.54Skamil
46481.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_8, PIOD_WRITE_I, 8, DATAIO)
46491.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_16, PIOD_WRITE_I, 16, DATAIO)
46501.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_32, PIOD_WRITE_I, 32, DATAIO)
46511.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_64, PIOD_WRITE_I, 64, DATAIO)
46521.54Skamil
46531.54SkamilBYTES_TRANSFER(bytes_transfer_read_d, PT_READ_D, 32, DATA)
46541.54SkamilBYTES_TRANSFER(bytes_transfer_read_i, PT_READ_I, 32, DATA)
46551.54SkamilBYTES_TRANSFER(bytes_transfer_write_d, PT_WRITE_D, 32, DATA)
46561.54SkamilBYTES_TRANSFER(bytes_transfer_write_i, PT_WRITE_I, 32, DATA)
46571.54Skamil
46581.54Skamil// TEXT
46591.54Skamil
46601.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_8_text, PIOD_READ_D, 8, TEXTIO)
46611.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_16_text, PIOD_READ_D, 16, TEXTIO)
46621.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_32_text, PIOD_READ_D, 32, TEXTIO)
46631.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_64_text, PIOD_READ_D, 64, TEXTIO)
46641.54Skamil
46651.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_8_text, PIOD_READ_I, 8, TEXTIO)
46661.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_16_text, PIOD_READ_I, 16, TEXTIO)
46671.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_32_text, PIOD_READ_I, 32, TEXTIO)
46681.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_64_text, PIOD_READ_I, 64, TEXTIO)
46691.54Skamil
46701.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_8_text, PIOD_WRITE_D, 8, TEXTIO)
46711.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_16_text, PIOD_WRITE_D, 16, TEXTIO)
46721.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_32_text, PIOD_WRITE_D, 32, TEXTIO)
46731.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_64_text, PIOD_WRITE_D, 64, TEXTIO)
46741.54Skamil
46751.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_8_text, PIOD_WRITE_I, 8, TEXTIO)
46761.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_16_text, PIOD_WRITE_I, 16, TEXTIO)
46771.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_32_text, PIOD_WRITE_I, 32, TEXTIO)
46781.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_64_text, PIOD_WRITE_I, 64, TEXTIO)
46791.54Skamil
46801.54SkamilBYTES_TRANSFER(bytes_transfer_read_d_text, PT_READ_D, 32, TEXT)
46811.54SkamilBYTES_TRANSFER(bytes_transfer_read_i_text, PT_READ_I, 32, TEXT)
46821.54SkamilBYTES_TRANSFER(bytes_transfer_write_d_text, PT_WRITE_D, 32, TEXT)
46831.54SkamilBYTES_TRANSFER(bytes_transfer_write_i_text, PT_WRITE_I, 32, TEXT)
46841.1Skamil
46851.54Skamil// AUXV
46861.1Skamil
46871.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_auxv, PIOD_READ_AUXV, 4096, AUXV)
46881.1Skamil
46891.54Skamil/// ----------------------------------------------------------------------------
46901.1Skamil
46911.101Skamilstatic void
46921.101Skamilbytes_transfer_alignment(const char *operation)
46931.101Skamil{
46941.101Skamil	const int exitval = 5;
46951.101Skamil	const int sigval = SIGSTOP;
46961.101Skamil	pid_t child, wpid;
46971.101Skamil#if defined(TWAIT_HAVE_STATUS)
46981.101Skamil	int status;
46991.101Skamil#endif
47001.101Skamil	char *buffer;
47011.101Skamil	int vector;
47021.101Skamil	size_t len;
47031.101Skamil	size_t i;
47041.101Skamil	int op;
47051.101Skamil
47061.101Skamil	struct ptrace_io_desc io;
47071.101Skamil	struct ptrace_siginfo info;
47081.101Skamil
47091.101Skamil	memset(&io, 0, sizeof(io));
47101.101Skamil	memset(&info, 0, sizeof(info));
47111.101Skamil
47121.101Skamil	/* Testing misaligned byte transfer crossing page boundaries */
47131.101Skamil	len = sysconf(_SC_PAGESIZE) * 2;
47141.101Skamil	buffer = malloc(len);
47151.101Skamil	ATF_REQUIRE(buffer != NULL);
47161.101Skamil
47171.101Skamil	/* Initialize the buffer with random data */
47181.101Skamil	for (i = 0; i < len; i++)
47191.101Skamil		buffer[i] = i & 0xff;
47201.101Skamil
47211.101Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
47221.101Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
47231.101Skamil	if (child == 0) {
47241.101Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
47251.101Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
47261.101Skamil
47271.101Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
47281.101Skamil		FORKEE_ASSERT(raise(sigval) == 0);
47291.101Skamil
47301.101Skamil		DPRINTF("Before exiting of the child process\n");
47311.101Skamil		_exit(exitval);
47321.101Skamil	}
47331.101Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
47341.101Skamil
47351.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
47361.101Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
47371.101Skamil
47381.101Skamil	validate_status_stopped(status, sigval);
47391.101Skamil
47401.101Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
47411.101Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info))
47421.101Skamil		!= -1);
47431.101Skamil
47441.101Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
47451.101Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
47461.101Skamil		"si_errno=%#x\n",
47471.101Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
47481.101Skamil		info.psi_siginfo.si_errno);
47491.101Skamil
47501.101Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
47511.101Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
47521.101Skamil
47531.101Skamil	if (strcmp(operation, "PT_READ_I") == 0 ||
47541.101Skamil	    strcmp(operation, "PT_READ_D") == 0) {
47551.101Skamil		if (strcmp(operation, "PT_READ_I"))
47561.101Skamil			op = PT_READ_I;
47571.101Skamil		else
47581.101Skamil			op = PT_READ_D;
47591.101Skamil
47601.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
47611.101Skamil			errno = 0;
47621.101Skamil			vector = ptrace(op, child, buffer + i, 0);
47631.101Skamil			ATF_REQUIRE_EQ(errno, 0);
47641.101Skamil			ATF_REQUIRE(!memcmp(&vector, buffer + i, sizeof(int)));
47651.101Skamil		}
47661.101Skamil	} else if (strcmp(operation, "PT_WRITE_I") == 0 ||
47671.101Skamil	           strcmp(operation, "PT_WRITE_D") == 0) {
47681.101Skamil		if (strcmp(operation, "PT_WRITE_I"))
47691.101Skamil			op = PT_WRITE_I;
47701.101Skamil		else
47711.101Skamil			op = PT_WRITE_D;
47721.101Skamil
47731.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
47741.101Skamil			memcpy(&vector, buffer + i, sizeof(int));
47751.101Skamil			SYSCALL_REQUIRE(ptrace(op, child, buffer + 1, vector)
47761.101Skamil			    != -1);
47771.101Skamil		}
47781.101Skamil	} else if (strcmp(operation, "PIOD_READ_I") == 0 ||
47791.101Skamil	           strcmp(operation, "PIOD_READ_D") == 0) {
47801.101Skamil		if (strcmp(operation, "PIOD_READ_I"))
47811.101Skamil			op = PIOD_READ_I;
47821.101Skamil		else
47831.101Skamil			op = PIOD_READ_D;
47841.101Skamil
47851.101Skamil		io.piod_op = op;
47861.101Skamil		io.piod_addr = &vector;
47871.101Skamil		io.piod_len = sizeof(int);
47881.101Skamil
47891.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
47901.101Skamil			io.piod_offs = buffer + i;
47911.101Skamil
47921.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
47931.101Skamil			                != -1);
47941.101Skamil			ATF_REQUIRE(!memcmp(&vector, buffer + i, sizeof(int)));
47951.101Skamil		}
47961.101Skamil	} else if (strcmp(operation, "PIOD_WRITE_I") == 0 ||
47971.101Skamil	           strcmp(operation, "PIOD_WRITE_D") == 0) {
47981.101Skamil		if (strcmp(operation, "PIOD_WRITE_I"))
47991.101Skamil			op = PIOD_WRITE_I;
48001.101Skamil		else
48011.101Skamil			op = PIOD_WRITE_D;
48021.101Skamil
48031.101Skamil		io.piod_op = op;
48041.101Skamil		io.piod_addr = &vector;
48051.101Skamil		io.piod_len = sizeof(int);
48061.101Skamil
48071.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
48081.101Skamil			io.piod_offs = buffer + i;
48091.101Skamil
48101.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
48111.101Skamil			                != -1);
48121.101Skamil		}
48131.101Skamil	} else if (strcmp(operation, "PIOD_READ_AUXV") == 0) {
48141.101Skamil		io.piod_op = PIOD_READ_AUXV;
48151.101Skamil		io.piod_addr = &vector;
48161.101Skamil		io.piod_len = sizeof(int);
48171.101Skamil
48181.101Skamil		errno = 0;
48191.101Skamil		i = 0;
48201.101Skamil		/* Read the whole AUXV vector, it has no clear length */
48211.120Skamil		while (io.piod_len > 0) {
48221.101Skamil			io.piod_offs = (void *)(intptr_t)i;
48231.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
48241.120Skamil			                != -1 || (io.piod_len == 0 && i > 0));
48251.101Skamil			++i;
48261.101Skamil		}
48271.101Skamil	}
48281.101Skamil
48291.101Skamil	DPRINTF("Before resuming the child process where it left off "
48301.101Skamil	    "and without signal to be sent\n");
48311.101Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
48321.101Skamil
48331.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48341.101Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
48351.101Skamil	    child);
48361.101Skamil
48371.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48381.101Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
48391.101Skamil}
48401.101Skamil
48411.101Skamil#define BYTES_TRANSFER_ALIGNMENT(test, operation)			\
48421.101SkamilATF_TC(test);								\
48431.101SkamilATF_TC_HEAD(test, tc)							\
48441.101Skamil{									\
48451.101Skamil	atf_tc_set_md_var(tc, "descr",					\
48461.101Skamil	    "Verify bytes transfer for potentially misaligned "		\
48471.101Skamil	    "operation " operation);					\
48481.101Skamil}									\
48491.101Skamil									\
48501.101SkamilATF_TC_BODY(test, tc)							\
48511.101Skamil{									\
48521.101Skamil									\
48531.101Skamil	bytes_transfer_alignment(operation);				\
48541.101Skamil}
48551.101Skamil
48561.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_read_i, "PT_READ_I")
48571.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_read_d, "PT_READ_D")
48581.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_write_i, "PT_WRITE_I")
48591.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_write_d, "PT_WRITE_D")
48601.101Skamil
48611.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_i, "PIOD_READ_I")
48621.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_d, "PIOD_READ_D")
48631.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_write_i, "PIOD_WRITE_I")
48641.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_write_d, "PIOD_WRITE_D")
48651.101Skamil
48661.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_auxv, "PIOD_READ_AUXV")
48671.101Skamil
48681.101Skamil/// ----------------------------------------------------------------------------
48691.101Skamil
48701.115Skamilstatic void
48711.115Skamilbytes_transfer_eof(const char *operation)
48721.115Skamil{
48731.115Skamil	const int exitval = 5;
48741.115Skamil	const int sigval = SIGSTOP;
48751.115Skamil	pid_t child, wpid;
48761.115Skamil#if defined(TWAIT_HAVE_STATUS)
48771.115Skamil	int status;
48781.115Skamil#endif
48791.115Skamil	FILE *fp;
48801.115Skamil	char *p;
48811.115Skamil	int vector;
48821.115Skamil	int op;
48831.115Skamil
48841.115Skamil	struct ptrace_io_desc io;
48851.115Skamil	struct ptrace_siginfo info;
48861.115Skamil
48871.115Skamil	memset(&io, 0, sizeof(io));
48881.115Skamil	memset(&info, 0, sizeof(info));
48891.115Skamil
48901.115Skamil	vector = 0;
48911.115Skamil
48921.115Skamil	fp = tmpfile();
48931.115Skamil	ATF_REQUIRE(fp != NULL);
48941.115Skamil
48951.115Skamil	p = mmap(0, 1, PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(fp), 0);
48961.115Skamil	ATF_REQUIRE(p != MAP_FAILED);
48971.115Skamil
48981.115Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
48991.115Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
49001.115Skamil	if (child == 0) {
49011.115Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
49021.115Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
49031.115Skamil
49041.115Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
49051.115Skamil		FORKEE_ASSERT(raise(sigval) == 0);
49061.115Skamil
49071.115Skamil		DPRINTF("Before exiting of the child process\n");
49081.115Skamil		_exit(exitval);
49091.115Skamil	}
49101.115Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
49111.115Skamil
49121.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
49131.115Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
49141.115Skamil
49151.115Skamil	validate_status_stopped(status, sigval);
49161.115Skamil
49171.115Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
49181.115Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info))
49191.115Skamil		!= -1);
49201.115Skamil
49211.115Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
49221.115Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
49231.115Skamil		"si_errno=%#x\n",
49241.115Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
49251.115Skamil		info.psi_siginfo.si_errno);
49261.115Skamil
49271.115Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
49281.115Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
49291.115Skamil
49301.115Skamil	if (strcmp(operation, "PT_READ_I") == 0 ||
49311.115Skamil	    strcmp(operation, "PT_READ_D") == 0) {
49321.115Skamil		if (strcmp(operation, "PT_READ_I"))
49331.115Skamil			op = PT_READ_I;
49341.115Skamil		else
49351.115Skamil			op = PT_READ_D;
49361.115Skamil
49371.115Skamil		errno = 0;
49381.115Skamil		SYSCALL_REQUIRE(ptrace(op, child, p, 0) == -1);
49391.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
49401.115Skamil	} else if (strcmp(operation, "PT_WRITE_I") == 0 ||
49411.115Skamil	           strcmp(operation, "PT_WRITE_D") == 0) {
49421.115Skamil		if (strcmp(operation, "PT_WRITE_I"))
49431.115Skamil			op = PT_WRITE_I;
49441.115Skamil		else
49451.115Skamil			op = PT_WRITE_D;
49461.115Skamil
49471.115Skamil		errno = 0;
49481.115Skamil		SYSCALL_REQUIRE(ptrace(op, child, p, vector) == -1);
49491.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
49501.115Skamil	} else if (strcmp(operation, "PIOD_READ_I") == 0 ||
49511.115Skamil	           strcmp(operation, "PIOD_READ_D") == 0) {
49521.115Skamil		if (strcmp(operation, "PIOD_READ_I"))
49531.115Skamil			op = PIOD_READ_I;
49541.115Skamil		else
49551.115Skamil			op = PIOD_READ_D;
49561.115Skamil
49571.115Skamil		io.piod_op = op;
49581.115Skamil		io.piod_addr = &vector;
49591.115Skamil		io.piod_len = sizeof(int);
49601.115Skamil		io.piod_offs = p;
49611.115Skamil
49621.115Skamil		errno = 0;
49631.115Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io)) == -1);
49641.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
49651.115Skamil	} else if (strcmp(operation, "PIOD_WRITE_I") == 0 ||
49661.115Skamil	           strcmp(operation, "PIOD_WRITE_D") == 0) {
49671.115Skamil		if (strcmp(operation, "PIOD_WRITE_I"))
49681.115Skamil			op = PIOD_WRITE_I;
49691.115Skamil		else
49701.115Skamil			op = PIOD_WRITE_D;
49711.115Skamil
49721.115Skamil		io.piod_op = op;
49731.115Skamil		io.piod_addr = &vector;
49741.115Skamil		io.piod_len = sizeof(int);
49751.115Skamil		io.piod_offs = p;
49761.115Skamil
49771.115Skamil		errno = 0;
49781.115Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io)) == -1);
49791.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
49801.115Skamil	}
49811.115Skamil
49821.115Skamil	DPRINTF("Before resuming the child process where it left off "
49831.115Skamil	    "and without signal to be sent\n");
49841.115Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
49851.115Skamil
49861.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
49871.115Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
49881.115Skamil	    child);
49891.115Skamil
49901.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
49911.115Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
49921.115Skamil}
49931.115Skamil
49941.115Skamil#define BYTES_TRANSFER_EOF(test, operation)				\
49951.115SkamilATF_TC(test);								\
49961.115SkamilATF_TC_HEAD(test, tc)							\
49971.115Skamil{									\
49981.115Skamil	atf_tc_set_md_var(tc, "descr",					\
49991.115Skamil	    "Verify bytes EOF byte transfer for the " operation		\
50001.115Skamil	    " operation");						\
50011.115Skamil}									\
50021.115Skamil									\
50031.115SkamilATF_TC_BODY(test, tc)							\
50041.115Skamil{									\
50051.115Skamil									\
50061.115Skamil	bytes_transfer_eof(operation);					\
50071.115Skamil}
50081.115Skamil
50091.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_read_i, "PT_READ_I")
50101.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_read_d, "PT_READ_D")
50111.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_write_i, "PT_WRITE_I")
50121.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_write_d, "PT_WRITE_D")
50131.115Skamil
50141.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_read_i, "PIOD_READ_I")
50151.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_read_d, "PIOD_READ_D")
50161.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_i, "PIOD_WRITE_I")
50171.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_d, "PIOD_WRITE_D")
50181.115Skamil
50191.115Skamil/// ----------------------------------------------------------------------------
50201.115Skamil
50211.76Sscole#if defined(HAVE_GPREGS) || defined(HAVE_FPREGS)
50221.72Skamilstatic void
50231.72Skamilaccess_regs(const char *regset, const char *aux)
50241.1Skamil{
50251.1Skamil	const int exitval = 5;
50261.1Skamil	const int sigval = SIGSTOP;
50271.1Skamil	pid_t child, wpid;
50281.1Skamil#if defined(TWAIT_HAVE_STATUS)
50291.1Skamil	int status;
50301.1Skamil#endif
50311.72Skamil#if defined(HAVE_GPREGS)
50321.72Skamil	struct reg gpr;
50331.76Sscole	register_t rgstr;
50341.1Skamil#endif
50351.72Skamil#if defined(HAVE_FPREGS)
50361.72Skamil	struct fpreg fpr;
50371.1Skamil#endif
50381.76Sscole
50391.72Skamil#if !defined(HAVE_GPREGS)
50401.72Skamil	if (strcmp(regset, "regs") == 0)
50411.72Skamil		atf_tc_fail("Impossible test scenario!");
50421.1Skamil#endif
50431.1Skamil
50441.72Skamil#if !defined(HAVE_FPREGS)
50451.72Skamil	if (strcmp(regset, "fpregs") == 0)
50461.72Skamil		atf_tc_fail("Impossible test scenario!");
50471.1Skamil#endif
50481.1Skamil
50491.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
50501.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
50511.1Skamil	if (child == 0) {
50521.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
50531.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
50541.1Skamil
50551.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
50561.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
50571.1Skamil
50581.13Schristos		DPRINTF("Before exiting of the child process\n");
50591.1Skamil		_exit(exitval);
50601.1Skamil	}
50611.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
50621.1Skamil
50631.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
50641.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
50651.1Skamil
50661.1Skamil	validate_status_stopped(status, sigval);
50671.1Skamil
50681.1Skamil#if defined(HAVE_GPREGS)
50691.72Skamil	if (strcmp(regset, "regs") == 0) {
50701.72Skamil		DPRINTF("Call GETREGS for the child process\n");
50711.72Skamil		SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1);
50721.72Skamil
50731.72Skamil		if (strcmp(aux, "none") == 0) {
50741.72Skamil			DPRINTF("Retrieved registers\n");
50751.72Skamil		} else if (strcmp(aux, "pc") == 0) {
50761.72Skamil			rgstr = PTRACE_REG_PC(&gpr);
50771.72Skamil			DPRINTF("Retrieved %" PRIxREGISTER "\n", rgstr);
50781.147Skamil		} else if (strstr(aux, "set_pc") != NULL) {
50791.72Skamil			rgstr = PTRACE_REG_PC(&gpr);
50801.147Skamil			DPRINTF("Retrieved PC %" PRIxREGISTER "\n", rgstr);
50811.147Skamil			if (strstr(aux, "0x1") != NULL) {
50821.147Skamil				rgstr |= 0x1;
50831.147Skamil			} else if (strstr(aux, "0x3") != NULL) {
50841.147Skamil				rgstr |= 0x3;
50851.147Skamil			} else if (strstr(aux, "0x7") != NULL) {
50861.147Skamil				rgstr |= 0x7;
50871.147Skamil			}
50881.147Skamil			DPRINTF("Set PC %" PRIxREGISTER "\n", rgstr);
50891.72Skamil			PTRACE_REG_SET_PC(&gpr, rgstr);
50901.147Skamil			if (strcmp(aux, "set_pc") != 0) {
50911.147Skamil				/* This call can fail with EINVAL or similar. */
50921.147Skamil				ptrace(PT_SETREGS, child, &gpr, 0);
50931.147Skamil			}
50941.72Skamil		} else if (strcmp(aux, "sp") == 0) {
50951.72Skamil			rgstr = PTRACE_REG_SP(&gpr);
50961.72Skamil			DPRINTF("Retrieved %" PRIxREGISTER "\n", rgstr);
50971.72Skamil		} else if (strcmp(aux, "intrv") == 0) {
50981.72Skamil			rgstr = PTRACE_REG_INTRV(&gpr);
50991.72Skamil			DPRINTF("Retrieved %" PRIxREGISTER "\n", rgstr);
51001.72Skamil		} else if (strcmp(aux, "setregs") == 0) {
51011.72Skamil			DPRINTF("Call SETREGS for the child process\n");
51021.72Skamil			SYSCALL_REQUIRE(
51031.147Skamil			    ptrace(PT_SETREGS, child, &gpr, 0) != -1);
51041.72Skamil		}
51051.72Skamil	}
51061.1Skamil#endif
51071.1Skamil
51081.72Skamil#if defined(HAVE_FPREGS)
51091.72Skamil	if (strcmp(regset, "fpregs") == 0) {
51101.72Skamil		DPRINTF("Call GETFPREGS for the child process\n");
51111.72Skamil		SYSCALL_REQUIRE(ptrace(PT_GETFPREGS, child, &fpr, 0) != -1);
51121.72Skamil
51131.72Skamil		if (strcmp(aux, "getfpregs") == 0) {
51141.72Skamil			DPRINTF("Retrieved FP registers\n");
51151.72Skamil		} else if (strcmp(aux, "setfpregs") == 0) {
51161.72Skamil			DPRINTF("Call SETFPREGS for the child\n");
51171.72Skamil			SYSCALL_REQUIRE(
51181.72Skamil			    ptrace(PT_SETFPREGS, child, &fpr, 0) != -1);
51191.72Skamil		}
51201.1Skamil	}
51211.1Skamil#endif
51221.1Skamil
51231.13Schristos	DPRINTF("Before resuming the child process where it left off and "
51241.1Skamil	    "without signal to be sent\n");
51251.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
51261.1Skamil
51271.147Skamil	if (strstr(aux, "unaligned") != NULL) {
51281.147Skamil		DPRINTF("Before resuming the child process where it left off "
51291.147Skamil		    "and without signal to be sent\n");
51301.147Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
51311.147Skamil
51321.147Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
51331.147Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
51341.147Skamil		    child);
51351.147Skamil
51361.147Skamil		validate_status_signaled(status, SIGKILL, 0);
51371.147Skamil
51381.147Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
51391.147Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
51401.147Skamil		    wpid = TWAIT_GENERIC(child, &status, 0));
51411.147Skamil	} else {
51421.147Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
51431.147Skamil		TWAIT_REQUIRE_SUCCESS(
51441.147Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
51451.1Skamil
51461.147Skamil		validate_status_exited(status, exitval);
51471.1Skamil
51481.147Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
51491.147Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
51501.147Skamil		    wpid = TWAIT_GENERIC(child, &status, 0));
51511.147Skamil	}
51521.1Skamil}
51531.1Skamil
51541.72Skamil#define ACCESS_REGS(test, regset, aux)					\
51551.72SkamilATF_TC(test);								\
51561.72SkamilATF_TC_HEAD(test, tc)							\
51571.72Skamil{									\
51581.72Skamil        atf_tc_set_md_var(tc, "descr",					\
51591.72Skamil            "Verify " regset " with auxiliary operation: " aux);	\
51601.72Skamil}									\
51611.72Skamil									\
51621.72SkamilATF_TC_BODY(test, tc)							\
51631.72Skamil{									\
51641.72Skamil									\
51651.72Skamil        access_regs(regset, aux);					\
51661.1Skamil}
51671.1Skamil#endif
51681.1Skamil
51691.72Skamil#if defined(HAVE_GPREGS)
51701.72SkamilACCESS_REGS(access_regs1, "regs", "none")
51711.72SkamilACCESS_REGS(access_regs2, "regs", "pc")
51721.72SkamilACCESS_REGS(access_regs3, "regs", "set_pc")
51731.72SkamilACCESS_REGS(access_regs4, "regs", "sp")
51741.72SkamilACCESS_REGS(access_regs5, "regs", "intrv")
51751.72SkamilACCESS_REGS(access_regs6, "regs", "setregs")
51761.147SkamilACCESS_REGS(access_regs_set_unaligned_pc_0x1, "regs", "set_pc+unaligned+0x1")
51771.147SkamilACCESS_REGS(access_regs_set_unaligned_pc_0x3, "regs", "set_pc+unaligned+0x3")
51781.147SkamilACCESS_REGS(access_regs_set_unaligned_pc_0x7, "regs", "set_pc+unaligned+0x7")
51791.1Skamil#endif
51801.1Skamil#if defined(HAVE_FPREGS)
51811.72SkamilACCESS_REGS(access_fpregs1, "fpregs", "getfpregs")
51821.72SkamilACCESS_REGS(access_fpregs2, "fpregs", "setfpregs")
51831.1Skamil#endif
51841.1Skamil
51851.72Skamil/// ----------------------------------------------------------------------------
51861.1Skamil
51871.1Skamil#if defined(PT_STEP)
51881.1Skamilstatic void
51891.95Skamilptrace_step(int N, int setstep, bool masked, bool ignored)
51901.1Skamil{
51911.1Skamil	const int exitval = 5;
51921.1Skamil	const int sigval = SIGSTOP;
51931.1Skamil	pid_t child, wpid;
51941.1Skamil#if defined(TWAIT_HAVE_STATUS)
51951.1Skamil	int status;
51961.1Skamil#endif
51971.1Skamil	int happy;
51981.95Skamil	struct sigaction sa;
51991.81Skamil	struct ptrace_siginfo info;
52001.95Skamil	sigset_t intmask;
52011.95Skamil	struct kinfo_proc2 kp;
52021.95Skamil	size_t len = sizeof(kp);
52031.95Skamil
52041.95Skamil	int name[6];
52051.95Skamil	const size_t namelen = __arraycount(name);
52061.95Skamil	ki_sigset_t kp_sigmask;
52071.95Skamil	ki_sigset_t kp_sigignore;
52081.1Skamil
52091.1Skamil#if defined(__arm__)
52101.1Skamil	/* PT_STEP not supported on arm 32-bit */
52111.1Skamil	atf_tc_expect_fail("PR kern/52119");
52121.1Skamil#endif
52131.1Skamil
52141.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
52151.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
52161.1Skamil	if (child == 0) {
52171.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
52181.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
52191.1Skamil
52201.95Skamil		if (masked) {
52211.95Skamil			sigemptyset(&intmask);
52221.95Skamil			sigaddset(&intmask, SIGTRAP);
52231.95Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
52241.95Skamil		}
52251.95Skamil
52261.95Skamil		if (ignored) {
52271.95Skamil			memset(&sa, 0, sizeof(sa));
52281.95Skamil			sa.sa_handler = SIG_IGN;
52291.95Skamil			sigemptyset(&sa.sa_mask);
52301.95Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
52311.95Skamil		}
52321.95Skamil
52331.1Skamil		happy = check_happy(999);
52341.1Skamil
52351.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
52361.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
52371.1Skamil
52381.1Skamil		FORKEE_ASSERT_EQ(happy, check_happy(999));
52391.1Skamil
52401.13Schristos		DPRINTF("Before exiting of the child process\n");
52411.1Skamil		_exit(exitval);
52421.1Skamil	}
52431.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
52441.1Skamil
52451.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
52461.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
52471.1Skamil
52481.1Skamil	validate_status_stopped(status, sigval);
52491.1Skamil
52501.81Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
52511.81Skamil	SYSCALL_REQUIRE(
52521.81Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
52531.81Skamil
52541.81Skamil	DPRINTF("Before checking siginfo_t\n");
52551.81Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
52561.81Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
52571.81Skamil
52581.95Skamil	name[0] = CTL_KERN,
52591.95Skamil	name[1] = KERN_PROC2,
52601.95Skamil	name[2] = KERN_PROC_PID;
52611.95Skamil	name[3] = child;
52621.95Skamil	name[4] = sizeof(kp);
52631.95Skamil	name[5] = 1;
52641.95Skamil
52651.95Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
52661.95Skamil
52671.95Skamil	if (masked)
52681.95Skamil		kp_sigmask = kp.p_sigmask;
52691.95Skamil
52701.95Skamil	if (ignored)
52711.95Skamil		kp_sigignore = kp.p_sigignore;
52721.95Skamil
52731.1Skamil	while (N --> 0) {
52741.2Skamil		if (setstep) {
52751.13Schristos			DPRINTF("Before resuming the child process where it "
52761.2Skamil			    "left off and without signal to be sent (use "
52771.9Skamil			    "PT_SETSTEP and PT_CONTINUE)\n");
52781.13Schristos			SYSCALL_REQUIRE(ptrace(PT_SETSTEP, child, 0, 0) != -1);
52791.13Schristos			SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0)
52801.2Skamil			    != -1);
52811.2Skamil		} else {
52821.13Schristos			DPRINTF("Before resuming the child process where it "
52831.2Skamil			    "left off and without signal to be sent (use "
52841.2Skamil			    "PT_STEP)\n");
52851.13Schristos			SYSCALL_REQUIRE(ptrace(PT_STEP, child, (void *)1, 0)
52861.2Skamil			    != -1);
52871.2Skamil		}
52881.1Skamil
52891.13Schristos		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
52901.1Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
52911.1Skamil		    child);
52921.1Skamil
52931.1Skamil		validate_status_stopped(status, SIGTRAP);
52941.2Skamil
52951.81Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
52961.81Skamil		SYSCALL_REQUIRE(
52971.81Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
52981.81Skamil
52991.81Skamil		DPRINTF("Before checking siginfo_t\n");
53001.81Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
53011.81Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_TRACE);
53021.81Skamil
53031.2Skamil		if (setstep) {
53041.13Schristos			SYSCALL_REQUIRE(ptrace(PT_CLEARSTEP, child, 0, 0) != -1);
53051.2Skamil		}
53061.95Skamil
53071.95Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
53081.95Skamil
53091.95Skamil		if (masked) {
53101.95Skamil			DPRINTF("kp_sigmask="
53111.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
53121.95Skamil			    PRIx32 "\n",
53131.95Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
53141.95Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
53151.95Skamil
53161.95Skamil			DPRINTF("kp.p_sigmask="
53171.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
53181.95Skamil			    PRIx32 "\n",
53191.95Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
53201.95Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
53211.95Skamil
53221.95Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
53231.95Skamil			    sizeof(kp_sigmask)));
53241.95Skamil		}
53251.95Skamil
53261.95Skamil		if (ignored) {
53271.95Skamil			DPRINTF("kp_sigignore="
53281.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
53291.95Skamil			    PRIx32 "\n",
53301.95Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
53311.95Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
53321.95Skamil
53331.95Skamil			DPRINTF("kp.p_sigignore="
53341.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
53351.95Skamil			    PRIx32 "\n",
53361.95Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
53371.95Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
53381.95Skamil
53391.95Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
53401.95Skamil			    sizeof(kp_sigignore)));
53411.95Skamil		}
53421.1Skamil	}
53431.1Skamil
53441.13Schristos	DPRINTF("Before resuming the child process where it left off and "
53451.1Skamil	    "without signal to be sent\n");
53461.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
53471.1Skamil
53481.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
53491.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
53501.1Skamil
53511.1Skamil	validate_status_exited(status, exitval);
53521.1Skamil
53531.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
53541.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
53551.1Skamil}
53561.1Skamil
53571.73Skamil#define PTRACE_STEP(test, N, setstep)					\
53581.73SkamilATF_TC(test);								\
53591.73SkamilATF_TC_HEAD(test, tc)							\
53601.73Skamil{									\
53611.73Skamil        atf_tc_set_md_var(tc, "descr",					\
53621.74Skamil            "Verify " #N " (PT_SETSTEP set to: " #setstep ")");		\
53631.73Skamil}									\
53641.73Skamil									\
53651.73SkamilATF_TC_BODY(test, tc)							\
53661.73Skamil{									\
53671.73Skamil									\
53681.95Skamil        ptrace_step(N, setstep, false, false);				\
53691.1Skamil}
53701.1Skamil
53711.73SkamilPTRACE_STEP(step1, 1, 0)
53721.73SkamilPTRACE_STEP(step2, 2, 0)
53731.73SkamilPTRACE_STEP(step3, 3, 0)
53741.73SkamilPTRACE_STEP(step4, 4, 0)
53751.73SkamilPTRACE_STEP(setstep1, 1, 1)
53761.73SkamilPTRACE_STEP(setstep2, 2, 1)
53771.73SkamilPTRACE_STEP(setstep3, 3, 1)
53781.73SkamilPTRACE_STEP(setstep4, 4, 1)
53791.95Skamil
53801.95SkamilATF_TC(step_signalmasked);
53811.95SkamilATF_TC_HEAD(step_signalmasked, tc)
53821.95Skamil{
53831.95Skamil	atf_tc_set_md_var(tc, "descr", "Verify PT_STEP with masked SIGTRAP");
53841.95Skamil}
53851.95Skamil
53861.95SkamilATF_TC_BODY(step_signalmasked, tc)
53871.95Skamil{
53881.95Skamil
53891.95Skamil	ptrace_step(1, 0, true, false);
53901.95Skamil}
53911.95Skamil
53921.95SkamilATF_TC(step_signalignored);
53931.95SkamilATF_TC_HEAD(step_signalignored, tc)
53941.95Skamil{
53951.95Skamil	atf_tc_set_md_var(tc, "descr", "Verify PT_STEP with ignored SIGTRAP");
53961.95Skamil}
53971.95Skamil
53981.95SkamilATF_TC_BODY(step_signalignored, tc)
53991.95Skamil{
54001.95Skamil
54011.95Skamil	ptrace_step(1, 0, false, true);
54021.95Skamil}
54031.1Skamil#endif
54041.1Skamil
54051.73Skamil/// ----------------------------------------------------------------------------
54061.1Skamil
54071.75Skamilstatic void
54081.75Skamilptrace_kill(const char *type)
54091.1Skamil{
54101.75Skamil	const int sigval = SIGSTOP;
54111.1Skamil	pid_t child, wpid;
54121.1Skamil#if defined(TWAIT_HAVE_STATUS)
54131.1Skamil	int status;
54141.1Skamil#endif
54151.1Skamil
54161.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
54171.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
54181.1Skamil	if (child == 0) {
54191.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
54201.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
54211.1Skamil
54221.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
54231.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
54241.1Skamil
54251.1Skamil		/* NOTREACHED */
54261.1Skamil		FORKEE_ASSERTX(0 &&
54271.1Skamil		    "Child should be terminated by a signal from its parent");
54281.1Skamil	}
54291.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
54301.1Skamil
54311.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
54321.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
54331.1Skamil
54341.1Skamil	validate_status_stopped(status, sigval);
54351.1Skamil
54361.75Skamil	DPRINTF("Before killing the child process with %s\n", type);
54371.75Skamil	if (strcmp(type, "ptrace(PT_KILL)") == 0) {
54381.75Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void*)1, 0) != -1);
54391.75Skamil	} else if (strcmp(type, "kill(SIGKILL)") == 0) {
54401.75Skamil		kill(child, SIGKILL);
54411.75Skamil	} else if (strcmp(type, "killpg(SIGKILL)") == 0) {
54421.75Skamil		setpgid(child, 0);
54431.75Skamil		killpg(getpgid(child), SIGKILL);
54441.75Skamil	}
54451.1Skamil
54461.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
54471.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
54481.1Skamil
54491.75Skamil	validate_status_signaled(status, SIGKILL, 0);
54501.1Skamil
54511.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
54521.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
54531.1Skamil}
54541.1Skamil
54551.75Skamil#define PTRACE_KILL(test, type)						\
54561.75SkamilATF_TC(test);								\
54571.75SkamilATF_TC_HEAD(test, tc)							\
54581.75Skamil{									\
54591.75Skamil        atf_tc_set_md_var(tc, "descr",					\
54601.75Skamil            "Verify killing the child with " type);			\
54611.75Skamil}									\
54621.75Skamil									\
54631.75SkamilATF_TC_BODY(test, tc)							\
54641.75Skamil{									\
54651.75Skamil									\
54661.75Skamil        ptrace_kill(type);						\
54671.1Skamil}
54681.1Skamil
54691.75Skamil// PT_CONTINUE with SIGKILL is covered by traceme_sendsignal_simple1
54701.75SkamilPTRACE_KILL(kill1, "ptrace(PT_KILL)")
54711.75SkamilPTRACE_KILL(kill2, "kill(SIGKILL)")
54721.75SkamilPTRACE_KILL(kill3, "killpg(SIGKILL)")
54731.1Skamil
54741.75Skamil/// ----------------------------------------------------------------------------
54751.1Skamil
54761.143Skamilstatic int lwpinfo_thread_sigmask[] = {SIGXCPU, SIGPIPE, SIGALRM, SIGURG};
54771.143Skamil
54781.143Skamilstatic pthread_mutex_t lwpinfo_thread_mtx = PTHREAD_MUTEX_INITIALIZER;
54791.143Skamilstatic pthread_cond_t lwpinfo_thread_cnd = PTHREAD_COND_INITIALIZER;
54801.143Skamilstatic volatile size_t lwpinfo_thread_done;
54811.143Skamil
54821.143Skamilstatic void *
54831.143Skamillwpinfo_thread(void *arg)
54841.143Skamil{
54851.143Skamil	sigset_t s;
54861.143Skamil	volatile void **tcb;
54871.143Skamil
54881.143Skamil	tcb = (volatile void **)arg;
54891.143Skamil
54901.145Skamil	*tcb = _lwp_getprivate();
54911.143Skamil	DPRINTF("Storing tcb[] = %p from thread %d\n", *tcb, _lwp_self());
54921.143Skamil
54931.143Skamil	pthread_setname_np(pthread_self(), "thread %d",
54941.143Skamil	    (void *)(intptr_t)_lwp_self());
54951.143Skamil
54961.143Skamil	sigemptyset(&s);
54971.143Skamil	pthread_mutex_lock(&lwpinfo_thread_mtx);
54981.143Skamil	sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
54991.143Skamil	lwpinfo_thread_done++;
55001.143Skamil	pthread_sigmask(SIG_BLOCK, &s, NULL);
55011.143Skamil	pthread_cond_signal(&lwpinfo_thread_cnd);
55021.143Skamil	pthread_mutex_unlock(&lwpinfo_thread_mtx);
55031.143Skamil
55041.143Skamil	return infinite_thread(NULL);
55051.143Skamil}
55061.143Skamil
55071.77Skamilstatic void
55081.143Skamiltraceme_lwpinfo(const size_t threads, const char *iter)
55091.1Skamil{
55101.1Skamil	const int sigval = SIGSTOP;
55111.77Skamil	const int sigval2 = SIGINT;
55121.1Skamil	pid_t child, wpid;
55131.1Skamil#if defined(TWAIT_HAVE_STATUS)
55141.1Skamil	int status;
55151.1Skamil#endif
55161.77Skamil	struct ptrace_lwpinfo lwp = {0, 0};
55171.143Skamil	struct ptrace_lwpstatus lwpstatus = {0};
55181.77Skamil	struct ptrace_siginfo info;
55191.143Skamil	void *private;
55201.143Skamil	char *name;
55211.143Skamil	char namebuf[PL_LNAMELEN];
55221.143Skamil	volatile void *tcb[4];
55231.143Skamil	bool found;
55241.143Skamil	sigset_t s;
55251.77Skamil
55261.77Skamil	/* Maximum number of supported threads in this test */
55271.143Skamil	pthread_t t[__arraycount(tcb) - 1];
55281.143Skamil	size_t n, m;
55291.143Skamil	int rv;
55301.143Skamil	size_t bytes_read;
55311.143Skamil
55321.143Skamil	struct ptrace_io_desc io;
55331.143Skamil	sigset_t sigmask;
55341.77Skamil
55351.143Skamil	ATF_REQUIRE(__arraycount(t) >= threads);
55361.143Skamil	memset(tcb, 0, sizeof(tcb));
55371.1Skamil
55381.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
55391.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
55401.1Skamil	if (child == 0) {
55411.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
55421.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
55431.1Skamil
55441.145Skamil		tcb[0] = _lwp_getprivate();
55451.143Skamil		DPRINTF("Storing tcb[0] = %p\n", tcb[0]);
55461.143Skamil
55471.143Skamil		pthread_setname_np(pthread_self(), "thread %d",
55481.143Skamil		    (void *)(intptr_t)_lwp_self());
55491.143Skamil
55501.143Skamil		sigemptyset(&s);
55511.143Skamil		sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
55521.143Skamil		pthread_sigmask(SIG_BLOCK, &s, NULL);
55531.143Skamil
55541.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
55551.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
55561.1Skamil
55571.77Skamil		for (n = 0; n < threads; n++) {
55581.143Skamil			rv = pthread_create(&t[n], NULL, lwpinfo_thread,
55591.143Skamil			    &tcb[n + 1]);
55601.77Skamil			FORKEE_ASSERT(rv == 0);
55611.77Skamil		}
55621.77Skamil
55631.143Skamil		pthread_mutex_lock(&lwpinfo_thread_mtx);
55641.143Skamil		while (lwpinfo_thread_done < threads) {
55651.143Skamil			pthread_cond_wait(&lwpinfo_thread_cnd,
55661.143Skamil			    &lwpinfo_thread_mtx);
55671.143Skamil		}
55681.143Skamil		pthread_mutex_unlock(&lwpinfo_thread_mtx);
55691.143Skamil
55701.77Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval2));
55711.77Skamil		FORKEE_ASSERT(raise(sigval2) == 0);
55721.77Skamil
55731.77Skamil		/* NOTREACHED */
55741.77Skamil		FORKEE_ASSERTX(0 && "Not reached");
55751.1Skamil	}
55761.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
55771.1Skamil
55781.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
55791.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
55801.1Skamil
55811.1Skamil	validate_status_stopped(status, sigval);
55821.1Skamil
55831.77Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
55841.77Skamil	SYSCALL_REQUIRE(
55851.77Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
55861.77Skamil
55871.77Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
55881.77Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
55891.77Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
55901.77Skamil	    info.psi_siginfo.si_errno);
55911.77Skamil
55921.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
55931.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
55941.77Skamil
55951.143Skamil	if (strstr(iter, "LWPINFO") != NULL) {
55961.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
55971.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
55981.143Skamil		    != -1);
55991.1Skamil
56001.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
56011.143Skamil		ATF_REQUIRE(lwp.pl_lwpid > 0);
56021.1Skamil
56031.143Skamil		DPRINTF("Assert that lwp thread %d received event "
56041.143Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
56051.143Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
56061.143Skamil
56071.143Skamil		if (strstr(iter, "LWPSTATUS") != NULL) {
56081.143Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPSTATUS "
56091.143Skamil			    "for child\n");
56101.143Skamil			lwpstatus.pl_lwpid = lwp.pl_lwpid;
56111.143Skamil			SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child, &lwpstatus,
56121.143Skamil			    sizeof(lwpstatus)) != -1);
56131.143Skamil		}
56141.1Skamil
56151.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
56161.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
56171.143Skamil		    != -1);
56181.1Skamil
56191.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
56201.143Skamil		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
56211.143Skamil	} else {
56221.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
56231.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
56241.143Skamil		    sizeof(lwpstatus)) != -1);
56251.143Skamil
56261.143Skamil		DPRINTF("Assert that there exists a single thread only %d\n", lwpstatus.pl_lwpid);
56271.143Skamil		ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
56281.143Skamil
56291.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
56301.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
56311.143Skamil		    sizeof(lwpstatus)) != -1);
56321.143Skamil
56331.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
56341.143Skamil		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
56351.143Skamil	}
56361.1Skamil
56371.13Schristos	DPRINTF("Before resuming the child process where it left off and "
56381.1Skamil	    "without signal to be sent\n");
56391.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
56401.1Skamil
56411.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
56421.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
56431.1Skamil
56441.77Skamil	validate_status_stopped(status, sigval2);
56451.77Skamil
56461.77Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
56471.77Skamil	SYSCALL_REQUIRE(
56481.77Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
56491.77Skamil
56501.77Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
56511.77Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
56521.77Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
56531.77Skamil	    info.psi_siginfo.si_errno);
56541.77Skamil
56551.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval2);
56561.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
56571.77Skamil
56581.77Skamil	memset(&lwp, 0, sizeof(lwp));
56591.143Skamil	memset(&lwpstatus, 0, sizeof(lwpstatus));
56601.143Skamil
56611.143Skamil	memset(&io, 0, sizeof(io));
56621.143Skamil
56631.143Skamil	bytes_read = 0;
56641.143Skamil	io.piod_op = PIOD_READ_D;
56651.143Skamil	io.piod_len = sizeof(tcb);
56661.143Skamil
56671.143Skamil	do {
56681.143Skamil		io.piod_addr = (char *)&tcb + bytes_read;
56691.143Skamil		io.piod_offs = io.piod_addr;
56701.143Skamil
56711.143Skamil		rv = ptrace(PT_IO, child, &io, sizeof(io));
56721.143Skamil		ATF_REQUIRE(rv != -1 && io.piod_len != 0);
56731.143Skamil
56741.143Skamil		bytes_read += io.piod_len;
56751.143Skamil		io.piod_len = sizeof(tcb) - bytes_read;
56761.143Skamil	} while (bytes_read < sizeof(tcb));
56771.77Skamil
56781.77Skamil	for (n = 0; n <= threads; n++) {
56791.143Skamil		if (strstr(iter, "LWPINFO") != NULL) {
56801.143Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
56811.143Skamil			    "child\n");
56821.143Skamil			SYSCALL_REQUIRE(
56831.143Skamil			    ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
56841.143Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
56851.143Skamil
56861.143Skamil			DPRINTF("Assert that the thread exists\n");
56871.143Skamil			ATF_REQUIRE(lwp.pl_lwpid > 0);
56881.143Skamil
56891.143Skamil			DPRINTF("Assert that lwp thread %d received expected "
56901.143Skamil			    "event\n", lwp.pl_lwpid);
56911.143Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
56921.143Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
56931.143Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
56941.143Skamil
56951.143Skamil			if (strstr(iter, "LWPSTATUS") != NULL) {
56961.143Skamil				DPRINTF("Before calling ptrace(2) with "
56971.143Skamil				    "PT_LWPSTATUS for child\n");
56981.143Skamil				lwpstatus.pl_lwpid = lwp.pl_lwpid;
56991.143Skamil				SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child,
57001.143Skamil				    &lwpstatus, sizeof(lwpstatus)) != -1);
57011.143Skamil
57021.143Skamil				goto check_lwpstatus;
57031.143Skamil			}
57041.143Skamil		} else {
57051.143Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for "
57061.143Skamil			    "child\n");
57071.143Skamil			SYSCALL_REQUIRE(
57081.143Skamil			    ptrace(PT_LWPNEXT, child, &lwpstatus,
57091.143Skamil			    sizeof(lwpstatus)) != -1);
57101.143Skamil			DPRINTF("LWP=%d\n", lwpstatus.pl_lwpid);
57111.143Skamil
57121.143Skamil			DPRINTF("Assert that the thread exists\n");
57131.143Skamil			ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
57141.143Skamil
57151.143Skamil		check_lwpstatus:
57161.143Skamil
57171.143Skamil			if (strstr(iter, "pl_sigmask") != NULL) {
57181.143Skamil				sigmask = lwpstatus.pl_sigmask;
57191.143Skamil
57201.143Skamil				DPRINTF("Retrieved sigmask: "
57211.143Skamil				    "%02x%02x%02x%02x\n",
57221.143Skamil				    sigmask.__bits[0], sigmask.__bits[1],
57231.143Skamil				    sigmask.__bits[2], sigmask.__bits[3]);
57241.143Skamil
57251.143Skamil				found = false;
57261.143Skamil				for (m = 0;
57271.143Skamil				     m < __arraycount(lwpinfo_thread_sigmask);
57281.143Skamil				     m++) {
57291.143Skamil					if (sigismember(&sigmask,
57301.143Skamil					    lwpinfo_thread_sigmask[m])) {
57311.143Skamil						found = true;
57321.143Skamil						lwpinfo_thread_sigmask[m] = 0;
57331.143Skamil						break;
57341.143Skamil					}
57351.143Skamil				}
57361.143Skamil				ATF_REQUIRE(found == true);
57371.143Skamil			} else if (strstr(iter, "pl_name") != NULL) {
57381.143Skamil				name = lwpstatus.pl_name;
57391.143Skamil
57401.143Skamil				DPRINTF("Retrieved thread name: "
57411.143Skamil				    "%s\n", name);
57421.143Skamil
57431.143Skamil				snprintf(namebuf, sizeof namebuf, "thread %d",
57441.143Skamil				    lwpstatus.pl_lwpid);
57451.143Skamil
57461.143Skamil				ATF_REQUIRE(strcmp(name, namebuf) == 0);
57471.143Skamil			} else if (strstr(iter, "pl_private") != NULL) {
57481.143Skamil				private = lwpstatus.pl_private;
57491.143Skamil
57501.143Skamil				DPRINTF("Retrieved thread private pointer: "
57511.143Skamil				    "%p\n", private);
57521.143Skamil
57531.143Skamil				found = false;
57541.143Skamil				for (m = 0; m < __arraycount(tcb); m++) {
57551.143Skamil					DPRINTF("Comparing %p and %p\n",
57561.143Skamil					    private, tcb[m]);
57571.143Skamil					if (private == tcb[m]) {
57581.143Skamil						found = true;
57591.143Skamil						break;
57601.143Skamil					}
57611.143Skamil				}
57621.143Skamil				ATF_REQUIRE(found == true);
57631.143Skamil			}
57641.143Skamil		}
57651.143Skamil	}
57661.143Skamil
57671.143Skamil	if (strstr(iter, "LWPINFO") != NULL) {
57681.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
57691.143Skamil		    "child\n");
57701.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
57711.143Skamil		    != -1);
57721.77Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
57731.77Skamil
57741.143Skamil		DPRINTF("Assert that there are no more threads\n");
57751.143Skamil		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
57761.143Skamil	} else {
57771.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
57781.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
57791.143Skamil		    sizeof(lwpstatus)) != -1);
57801.77Skamil
57811.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
57821.143Skamil		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
57831.143Skamil	}
57841.77Skamil
57851.77Skamil	DPRINTF("Before resuming the child process where it left off and "
57861.77Skamil	    "without signal to be sent\n");
57871.77Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, SIGKILL) != -1);
57881.77Skamil
57891.77Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
57901.77Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
57911.77Skamil
57921.77Skamil	validate_status_signaled(status, SIGKILL, 0);
57931.1Skamil
57941.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
57951.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
57961.1Skamil}
57971.1Skamil
57981.143Skamil#define TRACEME_LWPINFO(test, threads, iter)				\
57991.77SkamilATF_TC(test);								\
58001.77SkamilATF_TC_HEAD(test, tc)							\
58011.77Skamil{									\
58021.77Skamil	atf_tc_set_md_var(tc, "descr",					\
58031.143Skamil	    "Verify " iter " with the child with " #threads		\
58041.77Skamil	    " spawned extra threads");					\
58051.77Skamil}									\
58061.77Skamil									\
58071.77SkamilATF_TC_BODY(test, tc)							\
58081.77Skamil{									\
58091.77Skamil									\
58101.143Skamil	traceme_lwpinfo(threads, iter);					\
58111.1Skamil}
58121.1Skamil
58131.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0, 0, "LWPINFO")
58141.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1, 1, "LWPINFO")
58151.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2, 2, "LWPINFO")
58161.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3, 3, "LWPINFO")
58171.143Skamil
58181.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus, 0, "LWPINFO+LWPSTATUS")
58191.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus, 1, "LWPINFO+LWPSTATUS")
58201.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus, 2, "LWPINFO+LWPSTATUS")
58211.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus, 3, "LWPINFO+LWPSTATUS")
58221.143Skamil
58231.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_sigmask, 0,
58241.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
58251.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_sigmask, 1,
58261.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
58271.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_sigmask, 2,
58281.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
58291.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_sigmask, 3,
58301.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
58311.143Skamil
58321.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_name, 0,
58331.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
58341.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_name, 1,
58351.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
58361.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_name, 2,
58371.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
58381.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_name, 3,
58391.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
58401.143Skamil
58411.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_private, 0,
58421.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
58431.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_private, 1,
58441.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
58451.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_private, 2,
58461.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
58471.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_private, 3,
58481.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
58491.143Skamil
58501.143SkamilTRACEME_LWPINFO(traceme_lwpnext0, 0, "LWPNEXT")
58511.143SkamilTRACEME_LWPINFO(traceme_lwpnext1, 1, "LWPNEXT")
58521.143SkamilTRACEME_LWPINFO(traceme_lwpnext2, 2, "LWPNEXT")
58531.143SkamilTRACEME_LWPINFO(traceme_lwpnext3, 3, "LWPNEXT")
58541.143Skamil
58551.143SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_sigmask, 0, "LWPNEXT+pl_sigmask")
58561.143SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_sigmask, 1, "LWPNEXT+pl_sigmask")
58571.143SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_sigmask, 2, "LWPNEXT+pl_sigmask")
58581.143SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_sigmask, 3, "LWPNEXT+pl_sigmask")
58591.143Skamil
58601.143SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_name, 0, "LWPNEXT+pl_name")
58611.143SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_name, 1, "LWPNEXT+pl_name")
58621.143SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_name, 2, "LWPNEXT+pl_name")
58631.143SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_name, 3, "LWPNEXT+pl_name")
58641.143Skamil
58651.143SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_private, 0, "LWPNEXT+pl_private")
58661.143SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_private, 1, "LWPNEXT+pl_private")
58671.143SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_private, 2, "LWPNEXT+pl_private")
58681.143SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_private, 3, "LWPNEXT+pl_private")
58691.77Skamil
58701.77Skamil/// ----------------------------------------------------------------------------
58711.77Skamil
58721.77Skamil#if defined(TWAIT_HAVE_PID)
58731.77Skamilstatic void
58741.77Skamilattach_lwpinfo(const int threads)
58751.1Skamil{
58761.77Skamil	const int sigval = SIGINT;
58771.1Skamil	struct msg_fds parent_tracee, parent_tracer;
58781.1Skamil	const int exitval_tracer = 10;
58791.1Skamil	pid_t tracee, tracer, wpid;
58801.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
58811.1Skamil#if defined(TWAIT_HAVE_STATUS)
58821.1Skamil	int status;
58831.1Skamil#endif
58841.77Skamil	struct ptrace_lwpinfo lwp = {0, 0};
58851.77Skamil	struct ptrace_siginfo info;
58861.77Skamil
58871.77Skamil	/* Maximum number of supported threads in this test */
58881.77Skamil	pthread_t t[3];
58891.77Skamil	int n, rv;
58901.1Skamil
58911.13Schristos	DPRINTF("Spawn tracee\n");
58921.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
58931.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
58941.1Skamil	tracee = atf_utils_fork();
58951.1Skamil	if (tracee == 0) {
58961.1Skamil		/* Wait for message from the parent */
58971.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
58981.1Skamil
58991.77Skamil		CHILD_FROM_PARENT("spawn threads", parent_tracee, msg);
59001.77Skamil
59011.77Skamil		for (n = 0; n < threads; n++) {
59021.77Skamil			rv = pthread_create(&t[n], NULL, infinite_thread, NULL);
59031.77Skamil			FORKEE_ASSERT(rv == 0);
59041.77Skamil		}
59051.77Skamil
59061.77Skamil		CHILD_TO_PARENT("tracee exit", parent_tracee, msg);
59071.77Skamil
59081.77Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
59091.77Skamil		FORKEE_ASSERT(raise(sigval) == 0);
59101.77Skamil
59111.77Skamil		/* NOTREACHED */
59121.77Skamil		FORKEE_ASSERTX(0 && "Not reached");
59131.1Skamil	}
59141.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
59151.1Skamil
59161.13Schristos	DPRINTF("Spawn debugger\n");
59171.1Skamil	tracer = atf_utils_fork();
59181.1Skamil	if (tracer == 0) {
59191.1Skamil		/* No IPC to communicate with the child */
59201.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
59211.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
59221.1Skamil
59231.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
59241.1Skamil		FORKEE_REQUIRE_SUCCESS(
59251.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
59261.1Skamil
59271.1Skamil		forkee_status_stopped(status, SIGSTOP);
59281.1Skamil
59291.77Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
59301.77Skamil		    "tracee");
59311.77Skamil		FORKEE_ASSERT(
59321.77Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
59331.77Skamil
59341.77Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
59351.77Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
59361.77Skamil		    "si_errno=%#x\n",
59371.77Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
59381.77Skamil		    info.psi_siginfo.si_errno);
59391.77Skamil
59401.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
59411.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
59421.77Skamil
59431.13Schristos		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
59441.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
59451.1Skamil		    != -1);
59461.1Skamil
59471.13Schristos		DPRINTF("Assert that there exists a thread\n");
59481.77Skamil		FORKEE_ASSERTX(lwp.pl_lwpid > 0);
59491.1Skamil
59501.13Schristos		DPRINTF("Assert that lwp thread %d received event "
59511.77Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
59521.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
59531.1Skamil
59541.77Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
59551.77Skamil		    "tracee\n");
59561.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
59571.1Skamil		    != -1);
59581.1Skamil
59591.77Skamil		DPRINTF("Assert that there are no more lwp threads in "
59601.77Skamil		    "tracee\n");
59611.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
59621.1Skamil
59631.1Skamil		/* Resume tracee with PT_CONTINUE */
59641.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
59651.1Skamil
59661.1Skamil		/* Inform parent that tracer has attached to tracee */
59671.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
59681.77Skamil
59691.1Skamil		/* Wait for parent */
59701.1Skamil		CHILD_FROM_PARENT("tracer wait", parent_tracer, msg);
59711.1Skamil
59721.77Skamil		/* Wait for tracee and assert that it raised a signal */
59731.77Skamil		FORKEE_REQUIRE_SUCCESS(
59741.77Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
59751.77Skamil
59761.77Skamil		forkee_status_stopped(status, SIGINT);
59771.77Skamil
59781.77Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
59791.77Skamil		    "child");
59801.77Skamil		FORKEE_ASSERT(
59811.77Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
59821.77Skamil
59831.77Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
59841.77Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
59851.77Skamil		    "si_errno=%#x\n",
59861.77Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
59871.77Skamil		    info.psi_siginfo.si_errno);
59881.77Skamil
59891.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
59901.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
59911.77Skamil
59921.77Skamil		memset(&lwp, 0, sizeof(lwp));
59931.77Skamil
59941.77Skamil		for (n = 0; n <= threads; n++) {
59951.77Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
59961.77Skamil			    "child\n");
59971.77Skamil			FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp,
59981.77Skamil			    sizeof(lwp)) != -1);
59991.77Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
60001.77Skamil
60011.77Skamil			DPRINTF("Assert that the thread exists\n");
60021.77Skamil			FORKEE_ASSERT(lwp.pl_lwpid > 0);
60031.77Skamil
60041.77Skamil			DPRINTF("Assert that lwp thread %d received expected "
60051.77Skamil			    "event\n", lwp.pl_lwpid);
60061.77Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
60071.77Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
60081.77Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
60091.77Skamil		}
60101.77Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
60111.77Skamil		    "tracee\n");
60121.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
60131.77Skamil		    != -1);
60141.77Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
60151.77Skamil
60161.77Skamil		DPRINTF("Assert that there are no more threads\n");
60171.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
60181.77Skamil
60191.77Skamil		DPRINTF("Before resuming the child process where it left off "
60201.77Skamil		    "and without signal to be sent\n");
60211.77Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, SIGKILL)
60221.77Skamil		    != -1);
60231.77Skamil
60241.1Skamil		/* Wait for tracee and assert that it exited */
60251.1Skamil		FORKEE_REQUIRE_SUCCESS(
60261.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
60271.1Skamil
60281.77Skamil		forkee_status_signaled(status, SIGKILL, 0);
60291.1Skamil
60301.13Schristos		DPRINTF("Before exiting of the tracer process\n");
60311.1Skamil		_exit(exitval_tracer);
60321.1Skamil	}
60331.1Skamil
60341.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
60351.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
60361.1Skamil
60371.77Skamil	DPRINTF("Resume the tracee and spawn threads\n");
60381.77Skamil	PARENT_TO_CHILD("spawn threads", parent_tracee, msg);
60391.77Skamil
60401.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
60411.77Skamil	PARENT_FROM_CHILD("tracee exit", parent_tracee, msg);
60421.1Skamil
60431.77Skamil	DPRINTF("Resume the tracer and let it detect multiple threads\n");
60441.1Skamil	PARENT_TO_CHILD("tracer wait", parent_tracer, msg);
60451.1Skamil
60461.13Schristos	DPRINTF("Wait for tracer to finish its job and exit - calling %s()\n",
60471.1Skamil	    TWAIT_FNAME);
60481.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
60491.1Skamil	    tracer);
60501.1Skamil
60511.1Skamil	validate_status_exited(status, exitval_tracer);
60521.1Skamil
60531.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
60541.1Skamil	    TWAIT_FNAME);
60551.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
60561.1Skamil	    tracee);
60571.1Skamil
60581.77Skamil	validate_status_signaled(status, SIGKILL, 0);
60591.1Skamil
60601.1Skamil	msg_close(&parent_tracer);
60611.1Skamil	msg_close(&parent_tracee);
60621.1Skamil}
60631.77Skamil
60641.77Skamil#define ATTACH_LWPINFO(test, threads)					\
60651.77SkamilATF_TC(test);								\
60661.77SkamilATF_TC_HEAD(test, tc)							\
60671.77Skamil{									\
60681.77Skamil	atf_tc_set_md_var(tc, "descr",					\
60691.77Skamil	    "Verify LWPINFO with the child with " #threads		\
60701.77Skamil	    " spawned extra threads (tracer is not the original "	\
60711.77Skamil	    "parent)");							\
60721.77Skamil}									\
60731.77Skamil									\
60741.77SkamilATF_TC_BODY(test, tc)							\
60751.77Skamil{									\
60761.77Skamil									\
60771.77Skamil	attach_lwpinfo(threads);					\
60781.77Skamil}
60791.77Skamil
60801.77SkamilATTACH_LWPINFO(attach_lwpinfo0, 0)
60811.77SkamilATTACH_LWPINFO(attach_lwpinfo1, 1)
60821.77SkamilATTACH_LWPINFO(attach_lwpinfo2, 2)
60831.77SkamilATTACH_LWPINFO(attach_lwpinfo3, 3)
60841.1Skamil#endif
60851.1Skamil
60861.77Skamil/// ----------------------------------------------------------------------------
60871.77Skamil
60881.1Skamilstatic void
60891.79Skamilptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c), int *signal_caught)
60901.1Skamil{
60911.1Skamil	const int exitval = 5;
60921.1Skamil	const int sigval = SIGINT;
60931.1Skamil	const int sigfaked = SIGTRAP;
60941.1Skamil	const int sicodefaked = TRAP_BRKPT;
60951.1Skamil	pid_t child, wpid;
60961.1Skamil	struct sigaction sa;
60971.1Skamil#if defined(TWAIT_HAVE_STATUS)
60981.1Skamil	int status;
60991.1Skamil#endif
61001.1Skamil	struct ptrace_siginfo info;
61011.1Skamil	memset(&info, 0, sizeof(info));
61021.1Skamil
61031.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
61041.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
61051.1Skamil	if (child == 0) {
61061.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
61071.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
61081.1Skamil
61091.79Skamil		sa.sa_sigaction = sah;
61101.1Skamil		sa.sa_flags = SA_SIGINFO;
61111.1Skamil		sigemptyset(&sa.sa_mask);
61121.1Skamil
61131.79Skamil		FORKEE_ASSERT(sigaction(faked ? sigfaked : sigval, &sa, NULL)
61141.79Skamil		    != -1);
61151.1Skamil
61161.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
61171.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
61181.1Skamil
61191.79Skamil		FORKEE_ASSERT_EQ(*signal_caught, 1);
61201.1Skamil
61211.13Schristos		DPRINTF("Before exiting of the child process\n");
61221.1Skamil		_exit(exitval);
61231.1Skamil	}
61241.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
61251.1Skamil
61261.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
61271.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
61281.1Skamil
61291.1Skamil	validate_status_stopped(status, sigval);
61301.1Skamil
61311.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
61321.61Skre	SYSCALL_REQUIRE(
61331.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
61341.1Skamil
61351.13Schristos	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
61361.13Schristos	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
61371.1Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
61381.1Skamil	    info.psi_siginfo.si_errno);
61391.1Skamil
61401.79Skamil	if (faked) {
61411.79Skamil		DPRINTF("Before setting new faked signal to signo=%d "
61421.79Skamil		    "si_code=%d\n", sigfaked, sicodefaked);
61431.79Skamil		info.psi_siginfo.si_signo = sigfaked;
61441.79Skamil		info.psi_siginfo.si_code = sicodefaked;
61451.79Skamil	}
61461.1Skamil
61471.13Schristos	DPRINTF("Before calling ptrace(2) with PT_SET_SIGINFO for child\n");
61481.61Skre	SYSCALL_REQUIRE(
61491.61Skre	    ptrace(PT_SET_SIGINFO, child, &info, sizeof(info)) != -1);
61501.1Skamil
61511.79Skamil	if (faked) {
61521.79Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
61531.79Skamil		    "child\n");
61541.79Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
61551.79Skamil		    sizeof(info)) != -1);
61561.1Skamil
61571.79Skamil		DPRINTF("Before checking siginfo_t\n");
61581.79Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigfaked);
61591.79Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, sicodefaked);
61601.79Skamil	}
61611.1Skamil
61621.13Schristos	DPRINTF("Before resuming the child process where it left off and "
61631.1Skamil	    "without signal to be sent\n");
61641.79Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
61651.79Skamil	    faked ? sigfaked : sigval) != -1);
61661.1Skamil
61671.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
61681.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
61691.1Skamil
61701.1Skamil	validate_status_exited(status, exitval);
61711.1Skamil
61721.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
61731.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
61741.1Skamil}
61751.1Skamil
61761.79Skamil#define PTRACE_SIGINFO(test, faked)					\
61771.79SkamilATF_TC(test);								\
61781.79SkamilATF_TC_HEAD(test, tc)							\
61791.79Skamil{									\
61801.79Skamil	atf_tc_set_md_var(tc, "descr",					\
61811.79Skamil	    "Verify basic PT_GET_SIGINFO and PT_SET_SIGINFO calls"	\
61821.79Skamil	    "with%s setting signal to new value", faked ? "" : "out");	\
61831.79Skamil}									\
61841.79Skamil									\
61851.79Skamilstatic int test##_caught = 0;						\
61861.79Skamil									\
61871.79Skamilstatic void								\
61881.79Skamiltest##_sighandler(int sig, siginfo_t *info, void *ctx)			\
61891.79Skamil{									\
61901.79Skamil	if (faked) {							\
61911.79Skamil		FORKEE_ASSERT_EQ(sig, SIGTRAP);				\
61921.79Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGTRAP);		\
61931.79Skamil		FORKEE_ASSERT_EQ(info->si_code, TRAP_BRKPT);		\
61941.79Skamil	} else {							\
61951.79Skamil		FORKEE_ASSERT_EQ(sig, SIGINT);				\
61961.79Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGINT);		\
61971.79Skamil		FORKEE_ASSERT_EQ(info->si_code, SI_LWP);		\
61981.79Skamil	}								\
61991.79Skamil									\
62001.79Skamil	++ test##_caught;						\
62011.79Skamil}									\
62021.79Skamil									\
62031.79SkamilATF_TC_BODY(test, tc)							\
62041.79Skamil{									\
62051.79Skamil									\
62061.79Skamil	ptrace_siginfo(faked, test##_sighandler, & test##_caught); 	\
62071.79Skamil}
62081.79Skamil
62091.79SkamilPTRACE_SIGINFO(siginfo_set_unmodified, false)
62101.79SkamilPTRACE_SIGINFO(siginfo_set_faked, true)
62111.79Skamil
62121.79Skamil/// ----------------------------------------------------------------------------
62131.79Skamil
62141.97Skamilstatic void
62151.97Skamiltraceme_exec(bool masked, bool ignored)
62161.1Skamil{
62171.1Skamil	const int sigval = SIGTRAP;
62181.1Skamil	pid_t child, wpid;
62191.1Skamil#if defined(TWAIT_HAVE_STATUS)
62201.1Skamil	int status;
62211.1Skamil#endif
62221.97Skamil	struct sigaction sa;
62231.97Skamil	struct ptrace_siginfo info;
62241.97Skamil	sigset_t intmask;
62251.97Skamil	struct kinfo_proc2 kp;
62261.97Skamil	size_t len = sizeof(kp);
62271.97Skamil
62281.97Skamil	int name[6];
62291.97Skamil	const size_t namelen = __arraycount(name);
62301.97Skamil	ki_sigset_t kp_sigmask;
62311.97Skamil	ki_sigset_t kp_sigignore;
62321.1Skamil
62331.1Skamil	memset(&info, 0, sizeof(info));
62341.1Skamil
62351.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
62361.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
62371.1Skamil	if (child == 0) {
62381.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
62391.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
62401.1Skamil
62411.97Skamil		if (masked) {
62421.97Skamil			sigemptyset(&intmask);
62431.97Skamil			sigaddset(&intmask, sigval);
62441.97Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
62451.97Skamil		}
62461.97Skamil
62471.97Skamil		if (ignored) {
62481.97Skamil			memset(&sa, 0, sizeof(sa));
62491.97Skamil			sa.sa_handler = SIG_IGN;
62501.97Skamil			sigemptyset(&sa.sa_mask);
62511.97Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
62521.97Skamil		}
62531.97Skamil
62541.13Schristos		DPRINTF("Before calling execve(2) from child\n");
62551.1Skamil		execlp("/bin/echo", "/bin/echo", NULL);
62561.1Skamil
62571.1Skamil		FORKEE_ASSERT(0 && "Not reached");
62581.1Skamil	}
62591.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
62601.1Skamil
62611.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
62621.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
62631.1Skamil
62641.1Skamil	validate_status_stopped(status, sigval);
62651.1Skamil
62661.97Skamil	name[0] = CTL_KERN,
62671.97Skamil	name[1] = KERN_PROC2,
62681.97Skamil	name[2] = KERN_PROC_PID;
62691.97Skamil	name[3] = getpid();
62701.97Skamil	name[4] = sizeof(kp);
62711.97Skamil	name[5] = 1;
62721.97Skamil
62731.97Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
62741.97Skamil
62751.97Skamil	if (masked)
62761.97Skamil		kp_sigmask = kp.p_sigmask;
62771.97Skamil
62781.97Skamil	if (ignored)
62791.97Skamil		kp_sigignore = kp.p_sigignore;
62801.97Skamil
62811.97Skamil	name[3] = getpid();
62821.97Skamil
62831.97Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
62841.97Skamil
62851.97Skamil	if (masked) {
62861.97Skamil		DPRINTF("kp_sigmask="
62871.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
62881.97Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
62891.97Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
62901.97Skamil
62911.97Skamil		DPRINTF("kp.p_sigmask="
62921.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
62931.97Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
62941.97Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
62951.97Skamil
62961.97Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
62971.97Skamil		    sizeof(kp_sigmask)));
62981.97Skamil	}
62991.97Skamil
63001.97Skamil	if (ignored) {
63011.97Skamil		DPRINTF("kp_sigignore="
63021.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
63031.97Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
63041.97Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
63051.97Skamil
63061.97Skamil		DPRINTF("kp.p_sigignore="
63071.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
63081.97Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
63091.97Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
63101.97Skamil
63111.97Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
63121.97Skamil		    sizeof(kp_sigignore)));
63131.97Skamil	}
63141.97Skamil
63151.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
63161.61Skre	SYSCALL_REQUIRE(
63171.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
63181.1Skamil
63191.13Schristos	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
63201.13Schristos	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
63211.1Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
63221.1Skamil	    info.psi_siginfo.si_errno);
63231.1Skamil
63241.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
63251.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
63261.1Skamil
63271.13Schristos	DPRINTF("Before resuming the child process where it left off and "
63281.1Skamil	    "without signal to be sent\n");
63291.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
63301.1Skamil
63311.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
63321.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
63331.1Skamil
63341.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
63351.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
63361.1Skamil}
63371.1Skamil
63381.97Skamil#define TRACEME_EXEC(test, masked, ignored)				\
63391.97SkamilATF_TC(test);								\
63401.97SkamilATF_TC_HEAD(test, tc)							\
63411.97Skamil{									\
63421.97Skamil       atf_tc_set_md_var(tc, "descr",					\
63431.97Skamil           "Detect SIGTRAP TRAP_EXEC from "				\
63441.97Skamil           "child%s%s", masked ? " with masked signal" : "",		\
63451.97Skamil           masked ? " with ignored signal" : "");			\
63461.97Skamil}									\
63471.97Skamil									\
63481.97SkamilATF_TC_BODY(test, tc)							\
63491.97Skamil{									\
63501.97Skamil									\
63511.97Skamil       traceme_exec(masked, ignored);					\
63521.97Skamil}
63531.97Skamil
63541.97SkamilTRACEME_EXEC(traceme_exec, false, false)
63551.97SkamilTRACEME_EXEC(traceme_signalmasked_exec, true, false)
63561.97SkamilTRACEME_EXEC(traceme_signalignored_exec, false, true)
63571.97Skamil
63581.82Skamil/// ----------------------------------------------------------------------------
63591.82Skamil
63601.135Skamil#define TRACE_THREADS_NUM 100
63611.135Skamil
63621.83Skamilstatic volatile int done;
63631.137Skamilpthread_mutex_t trace_threads_mtx = PTHREAD_MUTEX_INITIALIZER;
63641.1Skamil
63651.83Skamilstatic void *
63661.83Skamiltrace_threads_cb(void *arg __unused)
63671.1Skamil{
63681.1Skamil
63691.137Skamil	pthread_mutex_lock(&trace_threads_mtx);
63701.83Skamil	done++;
63711.137Skamil	pthread_mutex_unlock(&trace_threads_mtx);
63721.83Skamil
63731.135Skamil	while (done < TRACE_THREADS_NUM)
63741.135Skamil		sched_yield();
63751.83Skamil
63761.83Skamil	return NULL;
63771.1Skamil}
63781.1Skamil
63791.83Skamilstatic void
63801.153Skamiltrace_threads(bool trace_create, bool trace_exit, bool masked)
63811.1Skamil{
63821.1Skamil	const int sigval = SIGSTOP;
63831.1Skamil	pid_t child, wpid;
63841.1Skamil#if defined(TWAIT_HAVE_STATUS)
63851.1Skamil	int status;
63861.1Skamil#endif
63871.1Skamil	ptrace_state_t state;
63881.1Skamil	const int slen = sizeof(state);
63891.1Skamil	ptrace_event_t event;
63901.1Skamil	const int elen = sizeof(event);
63911.83Skamil	struct ptrace_siginfo info;
63921.83Skamil
63931.153Skamil	sigset_t intmask;
63941.153Skamil
63951.135Skamil	pthread_t t[TRACE_THREADS_NUM];
63961.83Skamil	int rv;
63971.83Skamil	size_t n;
63981.1Skamil	lwpid_t lid;
63991.83Skamil
64001.83Skamil	/* Track created and exited threads */
64011.141Skamil	struct lwp_event_count traced_lwps[__arraycount(t)] = {{0, 0}};
64021.83Skamil
64031.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
64041.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
64051.1Skamil	if (child == 0) {
64061.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
64071.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
64081.1Skamil
64091.153Skamil		if (masked) {
64101.153Skamil			sigemptyset(&intmask);
64111.153Skamil			sigaddset(&intmask, SIGTRAP);
64121.153Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
64131.153Skamil		}
64141.153Skamil
64151.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
64161.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
64171.1Skamil
64181.83Skamil		for (n = 0; n < __arraycount(t); n++) {
64191.83Skamil			rv = pthread_create(&t[n], NULL, trace_threads_cb,
64201.83Skamil			    NULL);
64211.83Skamil			FORKEE_ASSERT(rv == 0);
64221.83Skamil		}
64231.1Skamil
64241.83Skamil		for (n = 0; n < __arraycount(t); n++) {
64251.83Skamil			rv = pthread_join(t[n], NULL);
64261.83Skamil			FORKEE_ASSERT(rv == 0);
64271.83Skamil		}
64281.1Skamil
64291.83Skamil		/*
64301.83Skamil		 * There is race between _exit() and pthread_join() detaching
64311.83Skamil		 * a thread. For simplicity kill the process after detecting
64321.83Skamil		 * LWP events.
64331.83Skamil		 */
64341.83Skamil		while (true)
64351.83Skamil			continue;
64361.1Skamil
64371.83Skamil		FORKEE_ASSERT(0 && "Not reached");
64381.1Skamil	}
64391.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
64401.1Skamil
64411.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
64421.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64431.1Skamil
64441.1Skamil	validate_status_stopped(status, sigval);
64451.1Skamil
64461.83Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
64471.83Skamil	SYSCALL_REQUIRE(
64481.83Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
64491.1Skamil
64501.83Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
64511.83Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
64521.83Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
64531.83Skamil	    info.psi_siginfo.si_errno);
64541.1Skamil
64551.83Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
64561.83Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
64571.1Skamil
64581.83Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
64591.83Skamil	memset(&event, 0, sizeof(event));
64601.83Skamil	if (trace_create)
64611.83Skamil		event.pe_set_event |= PTRACE_LWP_CREATE;
64621.83Skamil	if (trace_exit)
64631.83Skamil		event.pe_set_event |= PTRACE_LWP_EXIT;
64641.83Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
64651.1Skamil
64661.13Schristos	DPRINTF("Before resuming the child process where it left off and "
64671.1Skamil	    "without signal to be sent\n");
64681.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
64691.1Skamil
64701.83Skamil	for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
64711.83Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
64721.83Skamil		    "SIGTRAP\n", TWAIT_FNAME);
64731.83Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
64741.83Skamil		    child);
64751.1Skamil
64761.83Skamil		validate_status_stopped(status, SIGTRAP);
64771.1Skamil
64781.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
64791.83Skamil		    "child\n");
64801.83Skamil		SYSCALL_REQUIRE(
64811.83Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
64821.1Skamil
64831.83Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
64841.83Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
64851.83Skamil		    "si_errno=%#x\n",
64861.83Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
64871.83Skamil		    info.psi_siginfo.si_errno);
64881.1Skamil
64891.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
64901.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
64911.1Skamil
64921.83Skamil		SYSCALL_REQUIRE(
64931.83Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
64941.1Skamil
64951.83Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
64961.83Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
64971.1Skamil
64981.83Skamil		lid = state.pe_lwp;
64991.83Skamil		DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
65001.1Skamil
65011.141Skamil		*FIND_EVENT_COUNT(traced_lwps, lid) += 1;
65021.1Skamil
65031.83Skamil		DPRINTF("Before resuming the child process where it left off "
65041.83Skamil		    "and without signal to be sent\n");
65051.83Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
65061.83Skamil	}
65071.1Skamil
65081.83Skamil	for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
65091.83Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
65101.83Skamil		    "SIGTRAP\n", TWAIT_FNAME);
65111.83Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
65121.83Skamil		    child);
65131.1Skamil
65141.83Skamil		validate_status_stopped(status, SIGTRAP);
65151.1Skamil
65161.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
65171.83Skamil		    "child\n");
65181.83Skamil		SYSCALL_REQUIRE(
65191.83Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
65201.1Skamil
65211.83Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
65221.83Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
65231.83Skamil		    "si_errno=%#x\n",
65241.83Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
65251.83Skamil		    info.psi_siginfo.si_errno);
65261.1Skamil
65271.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
65281.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
65291.1Skamil
65301.83Skamil		SYSCALL_REQUIRE(
65311.83Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
65321.1Skamil
65331.83Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
65341.83Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
65351.1Skamil
65361.83Skamil		lid = state.pe_lwp;
65371.83Skamil		DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
65381.1Skamil
65391.83Skamil		if (trace_create) {
65401.141Skamil			int *count = FIND_EVENT_COUNT(traced_lwps, lid);
65411.141Skamil			ATF_REQUIRE_EQ(*count, 1);
65421.141Skamil			*count = 0;
65431.83Skamil		}
65441.1Skamil
65451.83Skamil		DPRINTF("Before resuming the child process where it left off "
65461.83Skamil		    "and without signal to be sent\n");
65471.83Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
65481.83Skamil	}
65491.1Skamil
65501.83Skamil	kill(child, SIGKILL);
65511.1Skamil
65521.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
65531.1Skamil	    TWAIT_FNAME);
65541.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
65551.1Skamil
65561.83Skamil	validate_status_signaled(status, SIGKILL, 0);
65571.1Skamil
65581.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
65591.1Skamil	    TWAIT_FNAME);
65601.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
65611.1Skamil}
65621.1Skamil
65631.153Skamil#define TRACE_THREADS(test, trace_create, trace_exit, mask)		\
65641.83SkamilATF_TC(test);								\
65651.83SkamilATF_TC_HEAD(test, tc)							\
65661.83Skamil{									\
65671.83Skamil        atf_tc_set_md_var(tc, "descr",					\
65681.83Skamil            "Verify spawning threads with%s tracing LWP create and"	\
65691.83Skamil	    "with%s tracing LWP exit", trace_create ? "" : "out",	\
65701.83Skamil	    trace_exit ? "" : "out");					\
65711.83Skamil}									\
65721.83Skamil									\
65731.83SkamilATF_TC_BODY(test, tc)							\
65741.83Skamil{									\
65751.83Skamil									\
65761.153Skamil        trace_threads(trace_create, trace_exit, mask);			\
65771.83Skamil}
65781.83Skamil
65791.153SkamilTRACE_THREADS(trace_thread_nolwpevents, false, false, false)
65801.153SkamilTRACE_THREADS(trace_thread_lwpexit, false, true, false)
65811.153SkamilTRACE_THREADS(trace_thread_lwpcreate, true, false, false)
65821.153SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true, false)
65831.153Skamil
65841.153SkamilTRACE_THREADS(trace_thread_lwpexit_masked_sigtrap, false, true, true)
65851.153SkamilTRACE_THREADS(trace_thread_lwpcreate_masked_sigtrap, true, false, true)
65861.153SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit_masked_sigtrap, true, true, true)
65871.83Skamil
65881.83Skamil/// ----------------------------------------------------------------------------
65891.83Skamil
65901.84SkamilATF_TC(signal_mask_unrelated);
65911.84SkamilATF_TC_HEAD(signal_mask_unrelated, tc)
65921.1Skamil{
65931.1Skamil	atf_tc_set_md_var(tc, "descr",
65941.1Skamil	    "Verify that masking single unrelated signal does not stop tracer "
65951.1Skamil	    "from catching other signals");
65961.1Skamil}
65971.1Skamil
65981.84SkamilATF_TC_BODY(signal_mask_unrelated, tc)
65991.1Skamil{
66001.1Skamil	const int exitval = 5;
66011.1Skamil	const int sigval = SIGSTOP;
66021.1Skamil	const int sigmasked = SIGTRAP;
66031.1Skamil	const int signotmasked = SIGINT;
66041.1Skamil	pid_t child, wpid;
66051.1Skamil#if defined(TWAIT_HAVE_STATUS)
66061.1Skamil	int status;
66071.1Skamil#endif
66081.1Skamil	sigset_t intmask;
66091.1Skamil
66101.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
66111.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
66121.1Skamil	if (child == 0) {
66131.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
66141.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
66151.1Skamil
66161.1Skamil		sigemptyset(&intmask);
66171.1Skamil		sigaddset(&intmask, sigmasked);
66181.1Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
66191.1Skamil
66201.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
66211.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
66221.1Skamil
66231.13Schristos		DPRINTF("Before raising %s from child\n",
66241.1Skamil		    strsignal(signotmasked));
66251.1Skamil		FORKEE_ASSERT(raise(signotmasked) == 0);
66261.1Skamil
66271.13Schristos		DPRINTF("Before exiting of the child process\n");
66281.1Skamil		_exit(exitval);
66291.1Skamil	}
66301.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
66311.1Skamil
66321.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
66331.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66341.1Skamil
66351.1Skamil	validate_status_stopped(status, sigval);
66361.1Skamil
66371.13Schristos	DPRINTF("Before resuming the child process where it left off and "
66381.1Skamil	    "without signal to be sent\n");
66391.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
66401.1Skamil
66411.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
66421.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66431.1Skamil
66441.1Skamil	validate_status_stopped(status, signotmasked);
66451.1Skamil
66461.13Schristos	DPRINTF("Before resuming the child process where it left off and "
66471.1Skamil	    "without signal to be sent\n");
66481.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
66491.1Skamil
66501.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
66511.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66521.1Skamil
66531.1Skamil	validate_status_exited(status, exitval);
66541.1Skamil
66551.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
66561.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
66571.1Skamil}
66581.1Skamil
66591.84Skamil/// ----------------------------------------------------------------------------
66601.84Skamil
66611.1Skamil#if defined(TWAIT_HAVE_PID)
66621.99Skamilstatic void
66631.126Skamilfork2_body(const char *fn, bool masked, bool ignored)
66641.1Skamil{
66651.1Skamil	const int exitval = 5;
66661.126Skamil	const int exitval2 = 0; /* Match exit status from /bin/echo */
66671.1Skamil	const int sigval = SIGSTOP;
66681.99Skamil	pid_t child, child2 = 0, wpid;
66691.1Skamil#if defined(TWAIT_HAVE_STATUS)
66701.1Skamil	int status;
66711.1Skamil#endif
66721.1Skamil	ptrace_state_t state;
66731.1Skamil	const int slen = sizeof(state);
66741.1Skamil	ptrace_event_t event;
66751.1Skamil	const int elen = sizeof(event);
66761.99Skamil	struct sigaction sa;
66771.99Skamil	struct ptrace_siginfo info;
66781.99Skamil	sigset_t intmask;
66791.99Skamil	struct kinfo_proc2 kp;
66801.99Skamil	size_t len = sizeof(kp);
66811.99Skamil
66821.99Skamil	int name[6];
66831.99Skamil	const size_t namelen = __arraycount(name);
66841.99Skamil	ki_sigset_t kp_sigmask;
66851.99Skamil	ki_sigset_t kp_sigignore;
66861.1Skamil
66871.126Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
66881.14Schristos
66891.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
66901.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
66911.1Skamil	if (child == 0) {
66921.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
66931.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
66941.1Skamil
66951.99Skamil		if (masked) {
66961.99Skamil			sigemptyset(&intmask);
66971.99Skamil			sigaddset(&intmask, SIGTRAP);
66981.99Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
66991.99Skamil		}
67001.99Skamil
67011.99Skamil		if (ignored) {
67021.99Skamil			memset(&sa, 0, sizeof(sa));
67031.99Skamil			sa.sa_handler = SIG_IGN;
67041.99Skamil			sigemptyset(&sa.sa_mask);
67051.99Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
67061.99Skamil		}
67071.1Skamil
67081.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
67091.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
67101.1Skamil
67111.126Skamil		if (strcmp(fn, "spawn") == 0) {
67121.126Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
67131.126Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
67141.126Skamil		} else  {
67151.126Skamil			if (strcmp(fn, "fork") == 0) {
67161.126Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
67171.126Skamil			} else {
67181.126Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
67191.126Skamil			}
67201.126Skamil			if (child2 == 0)
67211.126Skamil				_exit(exitval2);
67221.126Skamil		}
67231.1Skamil
67241.1Skamil		FORKEE_REQUIRE_SUCCESS
67251.99Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
67261.1Skamil
67271.1Skamil		forkee_status_exited(status, exitval2);
67281.1Skamil
67291.13Schristos		DPRINTF("Before exiting of the child process\n");
67301.1Skamil		_exit(exitval);
67311.1Skamil	}
67321.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
67331.1Skamil
67341.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
67351.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
67361.1Skamil
67371.1Skamil	validate_status_stopped(status, sigval);
67381.1Skamil
67391.99Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
67401.99Skamil	SYSCALL_REQUIRE(
67411.99Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
67421.99Skamil
67431.99Skamil	DPRINTF("Before checking siginfo_t\n");
67441.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
67451.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
67461.1Skamil
67471.99Skamil	name[0] = CTL_KERN,
67481.99Skamil	name[1] = KERN_PROC2,
67491.99Skamil	name[2] = KERN_PROC_PID;
67501.99Skamil	name[3] = child;
67511.99Skamil	name[4] = sizeof(kp);
67521.99Skamil	name[5] = 1;
67531.1Skamil
67541.99Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
67551.1Skamil
67561.99Skamil	if (masked)
67571.99Skamil		kp_sigmask = kp.p_sigmask;
67581.1Skamil
67591.99Skamil	if (ignored)
67601.99Skamil		kp_sigignore = kp.p_sigignore;
67611.1Skamil
67621.126Skamil	DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
67631.126Skamil	    strcmp(fn, "spawn") == 0 ? "|PTRACE_POSIX_SPAWN" : "",
67641.126Skamil	    strcmp(fn, "fork") == 0 ? "|PTRACE_FORK" : "",
67651.126Skamil	    strcmp(fn, "vfork") == 0 ? "|PTRACE_VFORK" : "",
67661.126Skamil	    strcmp(fn, "vforkdone") == 0 ? "|PTRACE_VFORK_DONE" : "", child);
67671.99Skamil	event.pe_set_event = 0;
67681.126Skamil	if (strcmp(fn, "spawn") == 0)
67691.126Skamil		event.pe_set_event |= PTRACE_POSIX_SPAWN;
67701.126Skamil	if (strcmp(fn, "fork") == 0)
67711.99Skamil		event.pe_set_event |= PTRACE_FORK;
67721.126Skamil	if (strcmp(fn, "vfork") == 0)
67731.99Skamil		event.pe_set_event |= PTRACE_VFORK;
67741.126Skamil	if (strcmp(fn, "vforkdone") == 0)
67751.99Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
67761.99Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
67771.1Skamil
67781.99Skamil	DPRINTF("Before resuming the child process where it left off and "
67791.99Skamil	    "without signal to be sent\n");
67801.99Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
67811.1Skamil
67821.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
67831.126Skamil	    strcmp(fn, "vfork") == 0) {
67841.99Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
67851.99Skamil		    child);
67861.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
67871.99Skamil		    child);
67881.1Skamil
67891.99Skamil		validate_status_stopped(status, SIGTRAP);
67901.1Skamil
67911.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
67921.1Skamil
67931.99Skamil		if (masked) {
67941.99Skamil			DPRINTF("kp_sigmask="
67951.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
67961.99Skamil			    PRIx32 "\n",
67971.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
67981.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
67991.1Skamil
68001.99Skamil			DPRINTF("kp.p_sigmask="
68011.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
68021.99Skamil			    PRIx32 "\n",
68031.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
68041.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
68051.1Skamil
68061.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
68071.99Skamil			    sizeof(kp_sigmask)));
68081.99Skamil		}
68091.1Skamil
68101.99Skamil		if (ignored) {
68111.99Skamil			DPRINTF("kp_sigignore="
68121.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
68131.99Skamil			    PRIx32 "\n",
68141.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
68151.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
68161.1Skamil
68171.99Skamil			DPRINTF("kp.p_sigignore="
68181.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
68191.99Skamil			    PRIx32 "\n",
68201.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
68211.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
68221.1Skamil
68231.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
68241.99Skamil			    sizeof(kp_sigignore)));
68251.99Skamil		}
68261.1Skamil
68271.99Skamil		SYSCALL_REQUIRE(
68281.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
68291.126Skamil		if (strcmp(fn, "spawn") == 0) {
68301.126Skamil			ATF_REQUIRE_EQ(
68311.126Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
68321.126Skamil			       PTRACE_POSIX_SPAWN);
68331.126Skamil		}
68341.126Skamil		if (strcmp(fn, "fork") == 0) {
68351.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
68361.99Skamil			       PTRACE_FORK);
68371.99Skamil		}
68381.126Skamil		if (strcmp(fn, "vfork") == 0) {
68391.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
68401.99Skamil			       PTRACE_VFORK);
68411.99Skamil		}
68421.1Skamil
68431.99Skamil		child2 = state.pe_other_pid;
68441.99Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
68451.1Skamil
68461.99Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
68471.99Skamil		    "%d\n", TWAIT_FNAME, child2, child);
68481.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
68491.99Skamil		    child2);
68501.1Skamil
68511.99Skamil		validate_status_stopped(status, SIGTRAP);
68521.1Skamil
68531.99Skamil		name[3] = child2;
68541.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
68551.1Skamil
68561.99Skamil		if (masked) {
68571.99Skamil			DPRINTF("kp_sigmask="
68581.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
68591.99Skamil			    PRIx32 "\n",
68601.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
68611.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
68621.1Skamil
68631.99Skamil			DPRINTF("kp.p_sigmask="
68641.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
68651.99Skamil			    PRIx32 "\n",
68661.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
68671.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
68681.14Schristos
68691.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
68701.99Skamil			    sizeof(kp_sigmask)));
68711.99Skamil		}
68721.1Skamil
68731.99Skamil		if (ignored) {
68741.99Skamil			DPRINTF("kp_sigignore="
68751.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
68761.99Skamil			    PRIx32 "\n",
68771.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
68781.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
68791.1Skamil
68801.99Skamil			DPRINTF("kp.p_sigignore="
68811.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
68821.99Skamil			    PRIx32 "\n",
68831.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
68841.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
68851.1Skamil
68861.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
68871.99Skamil			    sizeof(kp_sigignore)));
68881.99Skamil		}
68891.1Skamil
68901.99Skamil		SYSCALL_REQUIRE(
68911.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
68921.126Skamil		if (strcmp(fn, "spawn") == 0) {
68931.126Skamil			ATF_REQUIRE_EQ(
68941.126Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
68951.126Skamil			       PTRACE_POSIX_SPAWN);
68961.126Skamil		}
68971.126Skamil		if (strcmp(fn, "fork") == 0) {
68981.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
68991.99Skamil			       PTRACE_FORK);
69001.99Skamil		}
69011.126Skamil		if (strcmp(fn, "vfork") == 0) {
69021.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
69031.99Skamil			       PTRACE_VFORK);
69041.99Skamil		}
69051.1Skamil
69061.99Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
69071.1Skamil
69081.99Skamil		DPRINTF("Before resuming the forkee process where it left off "
69091.99Skamil		    "and without signal to be sent\n");
69101.99Skamil		SYSCALL_REQUIRE(
69111.99Skamil		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
69121.1Skamil
69131.99Skamil		DPRINTF("Before resuming the child process where it left off "
69141.99Skamil		    "and without signal to be sent\n");
69151.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
69161.1Skamil	}
69171.1Skamil
69181.126Skamil	if (strcmp(fn, "vforkdone") == 0) {
69191.99Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
69201.99Skamil		    child);
69211.99Skamil		TWAIT_REQUIRE_SUCCESS(
69221.99Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
69231.1Skamil
69241.99Skamil		validate_status_stopped(status, SIGTRAP);
69251.1Skamil
69261.99Skamil		name[3] = child;
69271.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
69281.1Skamil
69291.102Skamil		/*
69301.102Skamil		 * SIGCHLD is now pending in the signal queue and
69311.102Skamil		 * the kernel presents it to userland as a masked signal.
69321.102Skamil		 */
69331.102Skamil		sigdelset((sigset_t *)&kp.p_sigmask, SIGCHLD);
69341.102Skamil
69351.99Skamil		if (masked) {
69361.99Skamil			DPRINTF("kp_sigmask="
69371.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
69381.99Skamil			    PRIx32 "\n",
69391.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
69401.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
69411.1Skamil
69421.99Skamil			DPRINTF("kp.p_sigmask="
69431.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
69441.99Skamil			    PRIx32 "\n",
69451.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
69461.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
69471.1Skamil
69481.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
69491.99Skamil			    sizeof(kp_sigmask)));
69501.99Skamil		}
69511.1Skamil
69521.99Skamil		if (ignored) {
69531.99Skamil			DPRINTF("kp_sigignore="
69541.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
69551.99Skamil			    PRIx32 "\n",
69561.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
69571.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
69581.1Skamil
69591.99Skamil			DPRINTF("kp.p_sigignore="
69601.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
69611.99Skamil			    PRIx32 "\n",
69621.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
69631.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
69641.1Skamil
69651.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
69661.99Skamil			    sizeof(kp_sigignore)));
69671.99Skamil		}
69681.1Skamil
69691.99Skamil		SYSCALL_REQUIRE(
69701.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
69711.99Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
69721.1Skamil
69731.99Skamil		child2 = state.pe_other_pid;
69741.99Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
69751.99Skamil		    child2);
69761.1Skamil
69771.99Skamil		DPRINTF("Before resuming the child process where it left off "
69781.99Skamil		    "and without signal to be sent\n");
69791.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
69801.99Skamil	}
69811.1Skamil
69821.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
69831.126Skamil	    strcmp(fn, "vfork") == 0) {
69841.99Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
69851.99Skamil		    "\n", TWAIT_FNAME);
69861.99Skamil		TWAIT_REQUIRE_SUCCESS(
69871.99Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
69881.1Skamil
69891.99Skamil		validate_status_exited(status, exitval2);
69901.1Skamil
69911.99Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
69921.99Skamil		    "process\n", TWAIT_FNAME);
69931.99Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
69941.99Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
69951.99Skamil	}
69961.1Skamil
69971.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
69981.1Skamil	    "SIGCHLD\n", TWAIT_FNAME);
69991.57Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
70001.1Skamil
70011.1Skamil	validate_status_stopped(status, SIGCHLD);
70021.1Skamil
70031.57Skamil	DPRINTF("Before resuming the child process where it left off and "
70041.1Skamil	    "without signal to be sent\n");
70051.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
70061.1Skamil
70071.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
70081.1Skamil	    TWAIT_FNAME);
70091.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
70101.1Skamil
70111.1Skamil	validate_status_exited(status, exitval);
70121.1Skamil
70131.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
70141.57Skamil	    TWAIT_FNAME);
70151.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
70161.1Skamil}
70171.1Skamil
70181.126Skamil#define FORK2_TEST(name,fn,masked,ignored)				\
70191.99SkamilATF_TC(name);								\
70201.99SkamilATF_TC_HEAD(name, tc)							\
70211.99Skamil{									\
70221.126Skamil	atf_tc_set_md_var(tc, "descr", "Verify that " fn " is caught "	\
70231.99Skamil	    "regardless of signal %s%s", 				\
70241.99Skamil	    masked ? "masked" : "", ignored ? "ignored" : "");		\
70251.99Skamil}									\
70261.99Skamil									\
70271.99SkamilATF_TC_BODY(name, tc)							\
70281.99Skamil{									\
70291.99Skamil									\
70301.126Skamil	fork2_body(fn, masked, ignored);				\
70311.1Skamil}
70321.1Skamil
70331.126SkamilFORK2_TEST(posix_spawn_singalmasked, "spawn", true, false)
70341.126SkamilFORK2_TEST(posix_spawn_singalignored, "spawn", false, true)
70351.126SkamilFORK2_TEST(fork_singalmasked, "fork", true, false)
70361.126SkamilFORK2_TEST(fork_singalignored, "fork", false, true)
70371.126SkamilFORK2_TEST(vfork_singalmasked, "vfork", true, false)
70381.126SkamilFORK2_TEST(vfork_singalignored, "vfork", false, true)
70391.126SkamilFORK2_TEST(vforkdone_singalmasked, "vforkdone", true, false)
70401.126SkamilFORK2_TEST(vforkdone_singalignored, "vforkdone", false, true)
70411.1Skamil#endif
70421.1Skamil
70431.99Skamil/// ----------------------------------------------------------------------------
70441.1Skamil
70451.151Skamilstatic void *
70461.151Skamilthread_and_exec_thread_cb(void *arg __unused)
70471.151Skamil{
70481.151Skamil
70491.151Skamil	execlp("/bin/echo", "/bin/echo", NULL);
70501.151Skamil
70511.151Skamil	abort();
70521.151Skamil}
70531.151Skamil
70541.151Skamilstatic void
70551.151Skamilthreads_and_exec(void)
70561.151Skamil{
70571.151Skamil	const int sigval = SIGSTOP;
70581.151Skamil	pid_t child, wpid;
70591.151Skamil#if defined(TWAIT_HAVE_STATUS)
70601.151Skamil	int status;
70611.151Skamil#endif
70621.151Skamil	ptrace_state_t state;
70631.151Skamil	const int slen = sizeof(state);
70641.151Skamil	ptrace_event_t event;
70651.151Skamil	const int elen = sizeof(event);
70661.151Skamil	struct ptrace_siginfo info;
70671.151Skamil
70681.151Skamil	pthread_t t;
70691.151Skamil	lwpid_t lid;
70701.151Skamil
70711.151Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
70721.151Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
70731.151Skamil	if (child == 0) {
70741.151Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
70751.151Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
70761.151Skamil
70771.151Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
70781.151Skamil		FORKEE_ASSERT(raise(sigval) == 0);
70791.151Skamil
70801.151Skamil		FORKEE_ASSERT(pthread_create(&t, NULL,
70811.151Skamil		    thread_and_exec_thread_cb, NULL) == 0);
70821.151Skamil
70831.151Skamil		for (;;)
70841.151Skamil			continue;
70851.151Skamil
70861.151Skamil		FORKEE_ASSERT(0 && "Not reached");
70871.151Skamil	}
70881.151Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
70891.151Skamil
70901.151Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
70911.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
70921.151Skamil
70931.151Skamil	validate_status_stopped(status, sigval);
70941.151Skamil
70951.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
70961.151Skamil	SYSCALL_REQUIRE(
70971.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
70981.151Skamil
70991.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
71001.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
71011.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
71021.151Skamil	    info.psi_siginfo.si_errno);
71031.151Skamil
71041.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
71051.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
71061.151Skamil
71071.151Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
71081.151Skamil	memset(&event, 0, sizeof(event));
71091.151Skamil	event.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
71101.151Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
71111.151Skamil
71121.151Skamil	DPRINTF("Before resuming the child process where it left off and "
71131.151Skamil	    "without signal to be sent\n");
71141.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
71151.151Skamil
71161.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
71171.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
71181.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
71191.151Skamil	    child);
71201.151Skamil
71211.151Skamil	validate_status_stopped(status, SIGTRAP);
71221.151Skamil
71231.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
71241.151Skamil	    "child\n");
71251.151Skamil	SYSCALL_REQUIRE(
71261.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
71271.151Skamil
71281.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
71291.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
71301.151Skamil	    "si_errno=%#x\n",
71311.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
71321.151Skamil	    info.psi_siginfo.si_errno);
71331.151Skamil
71341.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
71351.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
71361.151Skamil
71371.151Skamil	SYSCALL_REQUIRE(
71381.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
71391.151Skamil
71401.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
71411.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
71421.151Skamil
71431.151Skamil	lid = state.pe_lwp;
71441.151Skamil	DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
71451.151Skamil
71461.151Skamil	DPRINTF("Before resuming the child process where it left off "
71471.151Skamil	    "and without signal to be sent\n");
71481.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
71491.151Skamil
71501.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
71511.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
71521.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
71531.151Skamil	    child);
71541.151Skamil
71551.151Skamil	validate_status_stopped(status, SIGTRAP);
71561.151Skamil
71571.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
71581.151Skamil	    "child\n");
71591.151Skamil	SYSCALL_REQUIRE(
71601.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
71611.151Skamil
71621.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
71631.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
71641.151Skamil	    "si_errno=%#x\n",
71651.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
71661.151Skamil	    info.psi_siginfo.si_errno);
71671.151Skamil
71681.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
71691.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
71701.151Skamil
71711.151Skamil	SYSCALL_REQUIRE(
71721.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
71731.151Skamil
71741.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
71751.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
71761.151Skamil
71771.151Skamil	lid = state.pe_lwp;
71781.151Skamil	DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
71791.151Skamil
71801.151Skamil	DPRINTF("Before resuming the child process where it left off "
71811.151Skamil	    "and without signal to be sent\n");
71821.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
71831.151Skamil
71841.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
71851.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
71861.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
71871.151Skamil	    child);
71881.151Skamil
71891.151Skamil	validate_status_stopped(status, SIGTRAP);
71901.151Skamil
71911.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
71921.151Skamil	    "child\n");
71931.151Skamil	SYSCALL_REQUIRE(
71941.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
71951.151Skamil
71961.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
71971.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
71981.151Skamil	    "si_errno=%#x\n",
71991.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
72001.151Skamil	    info.psi_siginfo.si_errno);
72011.151Skamil
72021.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
72031.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
72041.151Skamil
72051.151Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
72061.151Skamil
72071.151Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
72081.151Skamil	    TWAIT_FNAME);
72091.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
72101.151Skamil
72111.151Skamil	validate_status_signaled(status, SIGKILL, 0);
72121.151Skamil
72131.151Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
72141.151Skamil	    TWAIT_FNAME);
72151.151Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
72161.151Skamil}
72171.151Skamil
72181.151SkamilATF_TC(threads_and_exec);
72191.151SkamilATF_TC_HEAD(threads_and_exec, tc)
72201.151Skamil{
72211.151Skamil        atf_tc_set_md_var(tc, "descr",
72221.151Skamil            "Verify that multithreaded application on exec() will report "
72231.151Skamil	    "LWP_EXIT events");
72241.151Skamil}
72251.151Skamil
72261.151SkamilATF_TC_BODY(threads_and_exec, tc)
72271.151Skamil{
72281.151Skamil
72291.151Skamil        threads_and_exec();
72301.151Skamil}
72311.151Skamil
72321.151Skamil/// ----------------------------------------------------------------------------
72331.151Skamil
72341.154SkamilATF_TC(suspend_no_deadlock);
72351.154SkamilATF_TC_HEAD(suspend_no_deadlock, tc)
72361.1Skamil{
72371.1Skamil	atf_tc_set_md_var(tc, "descr",
72381.1Skamil	    "Verify that the while the only thread within a process is "
72391.1Skamil	    "suspended, the whole process cannot be unstopped");
72401.1Skamil}
72411.1Skamil
72421.154SkamilATF_TC_BODY(suspend_no_deadlock, tc)
72431.1Skamil{
72441.1Skamil	const int exitval = 5;
72451.1Skamil	const int sigval = SIGSTOP;
72461.1Skamil	pid_t child, wpid;
72471.1Skamil#if defined(TWAIT_HAVE_STATUS)
72481.1Skamil	int status;
72491.1Skamil#endif
72501.1Skamil	struct ptrace_siginfo psi;
72511.1Skamil
72521.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
72531.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
72541.1Skamil	if (child == 0) {
72551.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
72561.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
72571.1Skamil
72581.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
72591.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
72601.1Skamil
72611.13Schristos		DPRINTF("Before exiting of the child process\n");
72621.1Skamil		_exit(exitval);
72631.1Skamil	}
72641.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
72651.1Skamil
72661.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
72671.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
72681.1Skamil
72691.1Skamil	validate_status_stopped(status, sigval);
72701.1Skamil
72711.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
72721.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
72731.1Skamil
72741.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
72751.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
72761.1Skamil
72771.13Schristos	DPRINTF("Before resuming the child process where it left off and "
72781.1Skamil	    "without signal to be sent\n");
72791.1Skamil	ATF_REQUIRE_ERRNO(EDEADLK,
72801.1Skamil	    ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
72811.1Skamil
72821.13Schristos	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
72831.13Schristos	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
72841.1Skamil
72851.13Schristos	DPRINTF("Before resuming the child process where it left off and "
72861.1Skamil	    "without signal to be sent\n");
72871.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
72881.1Skamil
72891.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
72901.1Skamil	    TWAIT_FNAME);
72911.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
72921.1Skamil
72931.1Skamil	validate_status_exited(status, exitval);
72941.1Skamil
72951.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
72961.1Skamil	    TWAIT_FNAME);
72971.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
72981.1Skamil}
72991.1Skamil
73001.154Skamil/// ----------------------------------------------------------------------------
73011.154Skamil
73021.155Skamilstatic pthread_barrier_t barrier1_resume;
73031.155Skamilstatic pthread_barrier_t barrier2_resume;
73041.154Skamil
73051.155Skamilstatic void *
73061.155Skamilresume_thread(void *arg)
73071.154Skamil{
73081.154Skamil
73091.155Skamil	raise(SIGUSR1);
73101.155Skamil
73111.155Skamil	pthread_barrier_wait(&barrier1_resume);
73121.155Skamil
73131.155Skamil	/* Debugger will suspend the process here */
73141.155Skamil
73151.155Skamil	pthread_barrier_wait(&barrier2_resume);
73161.154Skamil
73171.155Skamil	raise(SIGUSR2);
73181.155Skamil
73191.155Skamil	return infinite_thread(arg);
73201.154Skamil}
73211.154Skamil
73221.155SkamilATF_TC(resume);
73231.155SkamilATF_TC_HEAD(resume, tc)
73241.1Skamil{
73251.1Skamil	atf_tc_set_md_var(tc, "descr",
73261.1Skamil	    "Verify that a thread can be suspended by a debugger and later "
73271.1Skamil	    "resumed by the debugger");
73281.1Skamil}
73291.1Skamil
73301.155SkamilATF_TC_BODY(resume, tc)
73311.1Skamil{
73321.1Skamil	const int sigval = SIGSTOP;
73331.1Skamil	pid_t child, wpid;
73341.1Skamil#if defined(TWAIT_HAVE_STATUS)
73351.1Skamil	int status;
73361.1Skamil#endif
73371.1Skamil	lwpid_t lid;
73381.1Skamil	struct ptrace_siginfo psi;
73391.155Skamil	pthread_t t;
73401.1Skamil
73411.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
73421.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
73431.1Skamil	if (child == 0) {
73441.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
73451.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
73461.1Skamil
73471.155Skamil		pthread_barrier_init(&barrier1_resume, NULL, 2);
73481.155Skamil		pthread_barrier_init(&barrier2_resume, NULL, 2);
73491.155Skamil
73501.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
73511.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
73521.1Skamil
73531.155Skamil		DPRINTF("Before creating new thread in child\n");
73541.155Skamil		FORKEE_ASSERT(pthread_create(&t, NULL, resume_thread, NULL) == 0);
73551.1Skamil
73561.155Skamil		pthread_barrier_wait(&barrier1_resume);
73571.1Skamil
73581.155Skamil		pthread_barrier_wait(&barrier2_resume);
73591.1Skamil
73601.155Skamil		infinite_thread(NULL);
73611.1Skamil	}
73621.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
73631.1Skamil
73641.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
73651.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
73661.1Skamil
73671.1Skamil	validate_status_stopped(status, sigval);
73681.1Skamil
73691.13Schristos	DPRINTF("Before resuming the child process where it left off and "
73701.1Skamil	    "without signal to be sent\n");
73711.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
73721.1Skamil
73731.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
73741.155Skamil	    "SIGUSR1\n", TWAIT_FNAME);
73751.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
73761.1Skamil
73771.155Skamil	validate_status_stopped(status, SIGUSR1);
73781.1Skamil
73791.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
73801.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
73811.1Skamil
73821.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
73831.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
73841.1Skamil
73851.155Skamil	lid = psi.psi_lwpid;
73861.1Skamil
73871.13Schristos	DPRINTF("Before resuming the child process where it left off and "
73881.1Skamil	    "without signal to be sent\n");
73891.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
73901.1Skamil
73911.155Skamil	DPRINTF("Before suspending the parent for 1 second, we expect no signals\n");
73921.155Skamil	SYSCALL_REQUIRE(sleep(1) == 0);
73931.155Skamil
73941.155Skamil#if defined(TWAIT_HAVE_OPTIONS)
73951.155Skamil	DPRINTF("Before calling %s() for the child - expected no status\n",
73961.155Skamil	    TWAIT_FNAME);
73971.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, WNOHANG), 0);
73981.155Skamil#endif
73991.155Skamil
74001.155Skamil	DPRINTF("Before resuming the child process where it left off and "
74011.155Skamil	    "without signal to be sent\n");
74021.155Skamil	SYSCALL_REQUIRE(ptrace(PT_STOP, child, NULL, 0) != -1);
74031.155Skamil
74041.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
74051.155Skamil	    "SIGSTOP\n", TWAIT_FNAME);
74061.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74071.1Skamil
74081.155Skamil	validate_status_stopped(status, SIGSTOP);
74091.1Skamil
74101.155Skamil	DPRINTF("Before resuming LWP %d\n", lid);
74111.155Skamil	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, lid) != -1);
74121.155Skamil
74131.155Skamil	DPRINTF("Before resuming the child process where it left off and "
74141.155Skamil	    "without signal to be sent\n");
74151.155Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
74161.1Skamil
74171.155Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
74181.155Skamil	    "SIGUSR2\n", TWAIT_FNAME);
74191.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74201.1Skamil
74211.155Skamil	validate_status_stopped(status, SIGUSR2);
74221.1Skamil
74231.13Schristos	DPRINTF("Before resuming the child process where it left off and "
74241.1Skamil	    "without signal to be sent\n");
74251.155Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
74261.1Skamil
74271.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
74281.1Skamil	    TWAIT_FNAME);
74291.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74301.1Skamil
74311.155Skamil	validate_status_signaled(status, SIGKILL, 0);
74321.1Skamil
74331.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
74341.1Skamil	    TWAIT_FNAME);
74351.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
74361.155Skamil}
74371.1Skamil
74381.155Skamil/// ----------------------------------------------------------------------------
74391.1Skamil
74401.167Skamilstatic int test_syscall_caught;
74411.167Skamil
74421.167Skamilstatic void
74431.167Skamilsyscall_sighand(int arg)
74441.167Skamil{
74451.167Skamil
74461.167Skamil	DPRINTF("Caught a signal %d in process %d\n", arg, getpid());
74471.167Skamil
74481.167Skamil	FORKEE_ASSERT_EQ(arg, SIGINFO);
74491.167Skamil
74501.167Skamil	++test_syscall_caught;
74511.167Skamil
74521.167Skamil	FORKEE_ASSERT_EQ(test_syscall_caught, 1);
74531.167Skamil}
74541.167Skamil
74551.166Skamilstatic void
74561.167Skamilsyscall_body(const char *op)
74571.1Skamil{
74581.1Skamil	const int exitval = 5;
74591.1Skamil	const int sigval = SIGSTOP;
74601.1Skamil	pid_t child, wpid;
74611.1Skamil#if defined(TWAIT_HAVE_STATUS)
74621.1Skamil	int status;
74631.1Skamil#endif
74641.1Skamil	struct ptrace_siginfo info;
74651.167Skamil
74661.1Skamil	memset(&info, 0, sizeof(info));
74671.1Skamil
74681.167Skamil#if defined(TWAIT_HAVE_STATUS)
74691.167Skamil	if (strstr(op, "signal") != NULL) {
74701.167Skamil		atf_tc_expect_fail("XXX: behavior under investigation");
74711.167Skamil	}
74721.167Skamil#endif
74731.167Skamil
74741.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
74751.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
74761.1Skamil	if (child == 0) {
74771.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
74781.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
74791.1Skamil
74801.167Skamil		signal(SIGINFO, syscall_sighand);
74811.167Skamil
74821.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
74831.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
74841.1Skamil
74851.1Skamil		syscall(SYS_getpid);
74861.1Skamil
74871.167Skamil		if (strstr(op, "signal") != NULL) {
74881.167Skamil			FORKEE_ASSERT_EQ(test_syscall_caught, 1);
74891.167Skamil		}
74901.167Skamil
74911.13Schristos		DPRINTF("Before exiting of the child process\n");
74921.1Skamil		_exit(exitval);
74931.1Skamil	}
74941.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
74951.1Skamil
74961.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
74971.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74981.1Skamil
74991.1Skamil	validate_status_stopped(status, sigval);
75001.1Skamil
75011.13Schristos	DPRINTF("Before resuming the child process where it left off and "
75021.1Skamil	    "without signal to be sent\n");
75031.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
75041.1Skamil
75051.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
75061.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
75071.1Skamil
75081.1Skamil	validate_status_stopped(status, SIGTRAP);
75091.1Skamil
75101.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
75111.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
75121.1Skamil
75131.38Skamil	DPRINTF("Before checking siginfo_t and lwpid\n");
75141.38Skamil	ATF_REQUIRE_EQ(info.psi_lwpid, 1);
75151.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
75161.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_SCE);
75171.1Skamil
75181.167Skamil	if (strstr(op, "killed") != NULL) {
75191.166Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
75201.166Skamil
75211.166Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
75221.166Skamil		TWAIT_REQUIRE_SUCCESS(
75231.166Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
75241.166Skamil
75251.166Skamil		validate_status_signaled(status, SIGKILL, 0);
75261.166Skamil	} else {
75271.167Skamil		if (strstr(op, "signal") != NULL) {
75281.167Skamil			DPRINTF("Before resuming the child %d and sending a "
75291.167Skamil			    "signal SIGINFO\n", child);
75301.167Skamil			SYSCALL_REQUIRE(
75311.167Skamil			    ptrace(PT_CONTINUE, child, (void *)1, SIGINFO)
75321.167Skamil			    != -1);
75331.167Skamil		} else if (strstr(op, "detach") != NULL) {
75341.167Skamil			DPRINTF("Before detaching the child %d\n", child);
75351.167Skamil			SYSCALL_REQUIRE(
75361.167Skamil			    ptrace(PT_DETACH, child, (void *)1, 0) != -1);
75371.167Skamil		} else {
75381.167Skamil			DPRINTF("Before resuming the child process where it "
75391.167Skamil			    "left off and without signal to be sent\n");
75401.167Skamil			SYSCALL_REQUIRE(
75411.167Skamil			    ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
75421.166Skamil
75431.167Skamil			DPRINTF("Before calling %s() for the child\n",
75441.167Skamil			    TWAIT_FNAME);
75451.167Skamil			TWAIT_REQUIRE_SUCCESS(
75461.167Skamil			    wpid = TWAIT_GENERIC(child, &status, 0), child);
75471.1Skamil
75481.167Skamil			validate_status_stopped(status, SIGTRAP);
75491.1Skamil
75501.167Skamil			DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO "
75511.167Skamil			    "for child\n");
75521.167Skamil			SYSCALL_REQUIRE(
75531.167Skamil			    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info))
75541.167Skamil			    != -1);
75551.1Skamil
75561.167Skamil			DPRINTF("Before checking siginfo_t and lwpid\n");
75571.167Skamil			ATF_REQUIRE_EQ(info.psi_lwpid, 1);
75581.167Skamil			ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
75591.167Skamil			ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_SCX);
75601.1Skamil
75611.167Skamil			DPRINTF("Before resuming the child process where it "
75621.167Skamil			    "left off and without signal to be sent\n");
75631.167Skamil			SYSCALL_REQUIRE(
75641.167Skamil			    ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
75651.167Skamil		}
75661.1Skamil
75671.166Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
75681.166Skamil		TWAIT_REQUIRE_SUCCESS(
75691.166Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
75701.1Skamil
75711.166Skamil		validate_status_exited(status, exitval);
75721.166Skamil	}
75731.1Skamil
75741.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
75751.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
75761.1Skamil}
75771.1Skamil
75781.167Skamil#define SYSCALL_TEST(name,op)						\
75791.166SkamilATF_TC(name);								\
75801.166SkamilATF_TC_HEAD(name, tc)							\
75811.166Skamil{									\
75821.170Skamil	atf_tc_set_md_var(tc, "timeout", "15");				\
75831.166Skamil	atf_tc_set_md_var(tc, "descr",					\
75841.166Skamil	    "Verify that getpid(2) can be traced with PT_SYSCALL %s",	\
75851.167Skamil	   #op );							\
75861.166Skamil}									\
75871.166Skamil									\
75881.166SkamilATF_TC_BODY(name, tc)							\
75891.166Skamil{									\
75901.166Skamil									\
75911.167Skamil	syscall_body(op);						\
75921.166Skamil}
75931.166Skamil
75941.167SkamilSYSCALL_TEST(syscall, "")
75951.167SkamilSYSCALL_TEST(syscall_killed_on_sce, "and killed")
75961.167SkamilSYSCALL_TEST(syscall_signal_on_sce, "and signaled")
75971.167SkamilSYSCALL_TEST(syscall_detach_on_sce, "and detached")
75981.166Skamil
75991.164Skamil/// ----------------------------------------------------------------------------
76001.164Skamil
76011.1SkamilATF_TC(syscallemu1);
76021.1SkamilATF_TC_HEAD(syscallemu1, tc)
76031.1Skamil{
76041.1Skamil	atf_tc_set_md_var(tc, "descr",
76051.1Skamil	    "Verify that exit(2) can be intercepted with PT_SYSCALLEMU");
76061.1Skamil}
76071.1Skamil
76081.1SkamilATF_TC_BODY(syscallemu1, tc)
76091.1Skamil{
76101.1Skamil	const int exitval = 5;
76111.1Skamil	const int sigval = SIGSTOP;
76121.1Skamil	pid_t child, wpid;
76131.1Skamil#if defined(TWAIT_HAVE_STATUS)
76141.1Skamil	int status;
76151.1Skamil#endif
76161.1Skamil
76171.6Skamil#if defined(__sparc__) && !defined(__sparc64__)
76181.6Skamil	/* syscallemu does not work on sparc (32-bit) */
76191.6Skamil	atf_tc_expect_fail("PR kern/52166");
76201.6Skamil#endif
76211.6Skamil
76221.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
76231.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
76241.1Skamil	if (child == 0) {
76251.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
76261.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
76271.1Skamil
76281.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
76291.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
76301.1Skamil
76311.1Skamil		syscall(SYS_exit, 100);
76321.1Skamil
76331.13Schristos		DPRINTF("Before exiting of the child process\n");
76341.1Skamil		_exit(exitval);
76351.1Skamil	}
76361.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
76371.1Skamil
76381.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76391.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
76401.1Skamil
76411.1Skamil	validate_status_stopped(status, sigval);
76421.1Skamil
76431.13Schristos	DPRINTF("Before resuming the child process where it left off and "
76441.1Skamil	    "without signal to be sent\n");
76451.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
76461.1Skamil
76471.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76481.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
76491.1Skamil
76501.1Skamil	validate_status_stopped(status, SIGTRAP);
76511.1Skamil
76521.13Schristos	DPRINTF("Set SYSCALLEMU for intercepted syscall\n");
76531.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALLEMU, child, (void *)1, 0) != -1);
76541.1Skamil
76551.13Schristos	DPRINTF("Before resuming the child process where it left off and "
76561.1Skamil	    "without signal to be sent\n");
76571.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
76581.1Skamil
76591.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76601.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
76611.1Skamil
76621.1Skamil	validate_status_stopped(status, SIGTRAP);
76631.1Skamil
76641.13Schristos	DPRINTF("Before resuming the child process where it left off and "
76651.1Skamil	    "without signal to be sent\n");
76661.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
76671.1Skamil
76681.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76691.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
76701.1Skamil
76711.1Skamil	validate_status_exited(status, exitval);
76721.1Skamil
76731.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76741.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
76751.1Skamil}
76761.1Skamil
76771.103Skamil/// ----------------------------------------------------------------------------
76781.103Skamil
76791.106Skamilstatic void
76801.106Skamilclone_body(int flags, bool trackfork, bool trackvfork,
76811.106Skamil    bool trackvforkdone)
76821.106Skamil{
76831.106Skamil	const int exitval = 5;
76841.106Skamil	const int exitval2 = 15;
76851.106Skamil	const int sigval = SIGSTOP;
76861.106Skamil	pid_t child, child2 = 0, wpid;
76871.106Skamil#if defined(TWAIT_HAVE_STATUS)
76881.106Skamil	int status;
76891.106Skamil#endif
76901.106Skamil	ptrace_state_t state;
76911.106Skamil	const int slen = sizeof(state);
76921.106Skamil	ptrace_event_t event;
76931.106Skamil	const int elen = sizeof(event);
76941.106Skamil
76951.106Skamil	const size_t stack_size = 1024 * 1024;
76961.106Skamil	void *stack, *stack_base;
76971.106Skamil
76981.106Skamil	stack = malloc(stack_size);
76991.106Skamil	ATF_REQUIRE(stack != NULL);
77001.106Skamil
77011.106Skamil#ifdef __MACHINE_STACK_GROWS_UP
77021.106Skamil	stack_base = stack;
77031.106Skamil#else
77041.106Skamil	stack_base = (char *)stack + stack_size;
77051.106Skamil#endif
77061.106Skamil
77071.106Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
77081.106Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
77091.106Skamil	if (child == 0) {
77101.106Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
77111.106Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
77121.106Skamil
77131.106Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
77141.106Skamil		FORKEE_ASSERT(raise(sigval) == 0);
77151.106Skamil
77161.106Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
77171.106Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
77181.106Skamil
77191.106Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
77201.106Skamil		    child2);
77211.106Skamil
77221.106Skamil		// XXX WALLSIG?
77231.106Skamil		FORKEE_REQUIRE_SUCCESS
77241.106Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
77251.106Skamil
77261.106Skamil		forkee_status_exited(status, exitval2);
77271.106Skamil
77281.106Skamil		DPRINTF("Before exiting of the child process\n");
77291.106Skamil		_exit(exitval);
77301.106Skamil	}
77311.106Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
77321.106Skamil
77331.106Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
77341.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
77351.106Skamil
77361.106Skamil	validate_status_stopped(status, sigval);
77371.106Skamil
77381.106Skamil	DPRINTF("Set 0%s%s%s in EVENT_MASK for the child %d\n",
77391.106Skamil	    trackfork ? "|PTRACE_FORK" : "",
77401.106Skamil	    trackvfork ? "|PTRACE_VFORK" : "",
77411.106Skamil	    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", child);
77421.106Skamil	event.pe_set_event = 0;
77431.106Skamil	if (trackfork)
77441.106Skamil		event.pe_set_event |= PTRACE_FORK;
77451.106Skamil	if (trackvfork)
77461.106Skamil		event.pe_set_event |= PTRACE_VFORK;
77471.106Skamil	if (trackvforkdone)
77481.106Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
77491.106Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
77501.106Skamil
77511.106Skamil	DPRINTF("Before resuming the child process where it left off and "
77521.106Skamil	    "without signal to be sent\n");
77531.106Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
77541.106Skamil
77551.106Skamil#if defined(TWAIT_HAVE_PID)
77561.106Skamil	if ((trackfork && !(flags & CLONE_VFORK)) ||
77571.106Skamil	    (trackvfork && (flags & CLONE_VFORK))) {
77581.106Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
77591.106Skamil		    child);
77601.106Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
77611.106Skamil		    child);
77621.106Skamil
77631.106Skamil		validate_status_stopped(status, SIGTRAP);
77641.106Skamil
77651.106Skamil		SYSCALL_REQUIRE(
77661.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
77671.106Skamil		if (trackfork && !(flags & CLONE_VFORK)) {
77681.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
77691.106Skamil			       PTRACE_FORK);
77701.106Skamil		}
77711.106Skamil		if (trackvfork && (flags & CLONE_VFORK)) {
77721.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
77731.106Skamil			       PTRACE_VFORK);
77741.106Skamil		}
77751.106Skamil
77761.106Skamil		child2 = state.pe_other_pid;
77771.106Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
77781.106Skamil
77791.106Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
77801.106Skamil		    "%d\n", TWAIT_FNAME, child2, child);
77811.106Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
77821.106Skamil		    child2);
77831.106Skamil
77841.106Skamil		validate_status_stopped(status, SIGTRAP);
77851.106Skamil
77861.106Skamil		SYSCALL_REQUIRE(
77871.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
77881.106Skamil		if (trackfork && !(flags & CLONE_VFORK)) {
77891.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
77901.106Skamil			       PTRACE_FORK);
77911.106Skamil		}
77921.106Skamil		if (trackvfork && (flags & CLONE_VFORK)) {
77931.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
77941.106Skamil			       PTRACE_VFORK);
77951.106Skamil		}
77961.106Skamil
77971.106Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
77981.106Skamil
77991.106Skamil		DPRINTF("Before resuming the forkee process where it left off "
78001.106Skamil		    "and without signal to be sent\n");
78011.106Skamil		SYSCALL_REQUIRE(
78021.106Skamil		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
78031.106Skamil
78041.106Skamil		DPRINTF("Before resuming the child process where it left off "
78051.106Skamil		    "and without signal to be sent\n");
78061.106Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
78071.106Skamil	}
78081.106Skamil#endif
78091.106Skamil
78101.106Skamil	if (trackvforkdone && (flags & CLONE_VFORK)) {
78111.106Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
78121.106Skamil		    child);
78131.106Skamil		TWAIT_REQUIRE_SUCCESS(
78141.106Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
78151.106Skamil
78161.106Skamil		validate_status_stopped(status, SIGTRAP);
78171.106Skamil
78181.106Skamil		SYSCALL_REQUIRE(
78191.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
78201.106Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
78211.106Skamil
78221.106Skamil		child2 = state.pe_other_pid;
78231.106Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
78241.106Skamil		    child2);
78251.106Skamil
78261.106Skamil		DPRINTF("Before resuming the child process where it left off "
78271.106Skamil		    "and without signal to be sent\n");
78281.106Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
78291.106Skamil	}
78301.106Skamil
78311.103Skamil#if defined(TWAIT_HAVE_PID)
78321.106Skamil	if ((trackfork && !(flags & CLONE_VFORK)) ||
78331.106Skamil	    (trackvfork && (flags & CLONE_VFORK))) {
78341.106Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
78351.106Skamil		    "\n", TWAIT_FNAME);
78361.106Skamil		TWAIT_REQUIRE_SUCCESS(
78371.106Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
78381.106Skamil
78391.106Skamil		validate_status_exited(status, exitval2);
78401.106Skamil
78411.106Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
78421.106Skamil		    "process\n", TWAIT_FNAME);
78431.106Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
78441.106Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
78451.106Skamil	}
78461.106Skamil#endif
78471.106Skamil
78481.106Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
78491.106Skamil	    "SIGCHLD\n", TWAIT_FNAME);
78501.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
78511.106Skamil
78521.106Skamil	validate_status_stopped(status, SIGCHLD);
78531.106Skamil
78541.106Skamil	DPRINTF("Before resuming the child process where it left off and "
78551.106Skamil	    "without signal to be sent\n");
78561.106Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
78571.106Skamil
78581.106Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
78591.106Skamil	    TWAIT_FNAME);
78601.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
78611.106Skamil
78621.106Skamil	validate_status_exited(status, exitval);
78631.103Skamil
78641.106Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
78651.106Skamil	    TWAIT_FNAME);
78661.106Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
78671.106Skamil}
78681.103Skamil
78691.106Skamil#define CLONE_TEST(name,flags,tfork,tvfork,tvforkdone)			\
78701.106SkamilATF_TC(name);								\
78711.106SkamilATF_TC_HEAD(name, tc)							\
78721.106Skamil{									\
78731.106Skamil	atf_tc_set_md_var(tc, "descr", "Verify clone(%s) "		\
78741.106Skamil	    "called with 0%s%s%s in EVENT_MASK",			\
78751.106Skamil	    #flags,							\
78761.106Skamil	    tfork ? "|PTRACE_FORK" : "",				\
78771.106Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
78781.106Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
78791.106Skamil}									\
78801.106Skamil									\
78811.106SkamilATF_TC_BODY(name, tc)							\
78821.106Skamil{									\
78831.106Skamil									\
78841.106Skamil	clone_body(flags, tfork, tvfork, tvforkdone);			\
78851.103Skamil}
78861.103Skamil
78871.106SkamilCLONE_TEST(clone1, 0, false, false, false)
78881.106Skamil#if defined(TWAIT_HAVE_PID)
78891.106SkamilCLONE_TEST(clone2, 0, true, false, false)
78901.106SkamilCLONE_TEST(clone3, 0, false, true, false)
78911.106SkamilCLONE_TEST(clone4, 0, true, true, false)
78921.106Skamil#endif
78931.106SkamilCLONE_TEST(clone5, 0, false, false, true)
78941.106Skamil#if defined(TWAIT_HAVE_PID)
78951.106SkamilCLONE_TEST(clone6, 0, true, false, true)
78961.106SkamilCLONE_TEST(clone7, 0, false, true, true)
78971.106SkamilCLONE_TEST(clone8, 0, true, true, true)
78981.106Skamil#endif
78991.106Skamil
79001.106SkamilCLONE_TEST(clone_vm1, CLONE_VM, false, false, false)
79011.106Skamil#if defined(TWAIT_HAVE_PID)
79021.106SkamilCLONE_TEST(clone_vm2, CLONE_VM, true, false, false)
79031.106SkamilCLONE_TEST(clone_vm3, CLONE_VM, false, true, false)
79041.106SkamilCLONE_TEST(clone_vm4, CLONE_VM, true, true, false)
79051.106Skamil#endif
79061.106SkamilCLONE_TEST(clone_vm5, CLONE_VM, false, false, true)
79071.106Skamil#if defined(TWAIT_HAVE_PID)
79081.106SkamilCLONE_TEST(clone_vm6, CLONE_VM, true, false, true)
79091.106SkamilCLONE_TEST(clone_vm7, CLONE_VM, false, true, true)
79101.106SkamilCLONE_TEST(clone_vm8, CLONE_VM, true, true, true)
79111.106Skamil#endif
79121.106Skamil
79131.106SkamilCLONE_TEST(clone_fs1, CLONE_FS, false, false, false)
79141.106Skamil#if defined(TWAIT_HAVE_PID)
79151.106SkamilCLONE_TEST(clone_fs2, CLONE_FS, true, false, false)
79161.106SkamilCLONE_TEST(clone_fs3, CLONE_FS, false, true, false)
79171.106SkamilCLONE_TEST(clone_fs4, CLONE_FS, true, true, false)
79181.106Skamil#endif
79191.106SkamilCLONE_TEST(clone_fs5, CLONE_FS, false, false, true)
79201.106Skamil#if defined(TWAIT_HAVE_PID)
79211.106SkamilCLONE_TEST(clone_fs6, CLONE_FS, true, false, true)
79221.106SkamilCLONE_TEST(clone_fs7, CLONE_FS, false, true, true)
79231.106SkamilCLONE_TEST(clone_fs8, CLONE_FS, true, true, true)
79241.106Skamil#endif
79251.106Skamil
79261.106SkamilCLONE_TEST(clone_files1, CLONE_FILES, false, false, false)
79271.106Skamil#if defined(TWAIT_HAVE_PID)
79281.106SkamilCLONE_TEST(clone_files2, CLONE_FILES, true, false, false)
79291.106SkamilCLONE_TEST(clone_files3, CLONE_FILES, false, true, false)
79301.106SkamilCLONE_TEST(clone_files4, CLONE_FILES, true, true, false)
79311.106Skamil#endif
79321.106SkamilCLONE_TEST(clone_files5, CLONE_FILES, false, false, true)
79331.106Skamil#if defined(TWAIT_HAVE_PID)
79341.106SkamilCLONE_TEST(clone_files6, CLONE_FILES, true, false, true)
79351.106SkamilCLONE_TEST(clone_files7, CLONE_FILES, false, true, true)
79361.106SkamilCLONE_TEST(clone_files8, CLONE_FILES, true, true, true)
79371.106Skamil#endif
79381.106Skamil
79391.106Skamil//CLONE_TEST(clone_sighand1, CLONE_SIGHAND, false, false, false)
79401.106Skamil#if defined(TWAIT_HAVE_PID)
79411.106Skamil//CLONE_TEST(clone_sighand2, CLONE_SIGHAND, true, false, false)
79421.106Skamil//CLONE_TEST(clone_sighand3, CLONE_SIGHAND, false, true, false)
79431.106Skamil//CLONE_TEST(clone_sighand4, CLONE_SIGHAND, true, true, false)
79441.106Skamil#endif
79451.106Skamil//CLONE_TEST(clone_sighand5, CLONE_SIGHAND, false, false, true)
79461.106Skamil#if defined(TWAIT_HAVE_PID)
79471.106Skamil//CLONE_TEST(clone_sighand6, CLONE_SIGHAND, true, false, true)
79481.106Skamil//CLONE_TEST(clone_sighand7, CLONE_SIGHAND, false, true, true)
79491.106Skamil//CLONE_TEST(clone_sighand8, CLONE_SIGHAND, true, true, true)
79501.106Skamil#endif
79511.106Skamil
79521.106SkamilCLONE_TEST(clone_vfork1, CLONE_VFORK, false, false, false)
79531.106Skamil#if defined(TWAIT_HAVE_PID)
79541.106SkamilCLONE_TEST(clone_vfork2, CLONE_VFORK, true, false, false)
79551.106SkamilCLONE_TEST(clone_vfork3, CLONE_VFORK, false, true, false)
79561.106SkamilCLONE_TEST(clone_vfork4, CLONE_VFORK, true, true, false)
79571.106Skamil#endif
79581.106SkamilCLONE_TEST(clone_vfork5, CLONE_VFORK, false, false, true)
79591.106Skamil#if defined(TWAIT_HAVE_PID)
79601.106SkamilCLONE_TEST(clone_vfork6, CLONE_VFORK, true, false, true)
79611.106SkamilCLONE_TEST(clone_vfork7, CLONE_VFORK, false, true, true)
79621.106SkamilCLONE_TEST(clone_vfork8, CLONE_VFORK, true, true, true)
79631.106Skamil#endif
79641.106Skamil
79651.106Skamil/// ----------------------------------------------------------------------------
79661.106Skamil
79671.106Skamil#if defined(TWAIT_HAVE_PID)
79681.103Skamilstatic void
79691.106Skamilclone_body2(int flags, bool masked, bool ignored)
79701.103Skamil{
79711.103Skamil	const int exitval = 5;
79721.103Skamil	const int exitval2 = 15;
79731.103Skamil	const int sigval = SIGSTOP;
79741.103Skamil	pid_t child, child2 = 0, wpid;
79751.103Skamil#if defined(TWAIT_HAVE_STATUS)
79761.103Skamil	int status;
79771.103Skamil#endif
79781.103Skamil	ptrace_state_t state;
79791.103Skamil	const int slen = sizeof(state);
79801.103Skamil	ptrace_event_t event;
79811.103Skamil	const int elen = sizeof(event);
79821.103Skamil	struct sigaction sa;
79831.103Skamil	struct ptrace_siginfo info;
79841.103Skamil	sigset_t intmask;
79851.103Skamil	struct kinfo_proc2 kp;
79861.103Skamil	size_t len = sizeof(kp);
79871.103Skamil
79881.103Skamil	int name[6];
79891.103Skamil	const size_t namelen = __arraycount(name);
79901.103Skamil	ki_sigset_t kp_sigmask;
79911.103Skamil	ki_sigset_t kp_sigignore;
79921.103Skamil
79931.103Skamil	const size_t stack_size = 1024 * 1024;
79941.103Skamil	void *stack, *stack_base;
79951.103Skamil
79961.103Skamil	stack = malloc(stack_size);
79971.103Skamil	ATF_REQUIRE(stack != NULL);
79981.103Skamil
79991.103Skamil#ifdef __MACHINE_STACK_GROWS_UP
80001.103Skamil	stack_base = stack;
80011.103Skamil#else
80021.103Skamil	stack_base = (char *)stack + stack_size;
80031.103Skamil#endif
80041.103Skamil
80051.103Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
80061.103Skamil	if (child == 0) {
80071.103Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
80081.103Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
80091.103Skamil
80101.103Skamil		if (masked) {
80111.103Skamil			sigemptyset(&intmask);
80121.103Skamil			sigaddset(&intmask, SIGTRAP);
80131.103Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
80141.103Skamil		}
80151.103Skamil
80161.103Skamil		if (ignored) {
80171.103Skamil			memset(&sa, 0, sizeof(sa));
80181.103Skamil			sa.sa_handler = SIG_IGN;
80191.103Skamil			sigemptyset(&sa.sa_mask);
80201.103Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
80211.103Skamil		}
80221.103Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
80231.103Skamil		FORKEE_ASSERT(raise(sigval) == 0);
80241.103Skamil
80251.103Skamil		DPRINTF("Before forking process PID=%d flags=%#x\n", getpid(),
80261.103Skamil		    flags);
80271.103Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
80281.103Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
80291.103Skamil
80301.103Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
80311.103Skamil		    child2);
80321.103Skamil
80331.103Skamil		// XXX WALLSIG?
80341.103Skamil		FORKEE_REQUIRE_SUCCESS
80351.103Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
80361.103Skamil
80371.103Skamil		forkee_status_exited(status, exitval2);
80381.103Skamil
80391.103Skamil		DPRINTF("Before exiting of the child process\n");
80401.103Skamil		_exit(exitval);
80411.103Skamil	}
80421.103Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
80431.103Skamil
80441.103Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
80451.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
80461.103Skamil
80471.103Skamil	validate_status_stopped(status, sigval);
80481.103Skamil
80491.103Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
80501.103Skamil	SYSCALL_REQUIRE(
80511.103Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
80521.103Skamil
80531.103Skamil	DPRINTF("Before checking siginfo_t\n");
80541.103Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
80551.103Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
80561.103Skamil
80571.103Skamil	name[0] = CTL_KERN,
80581.103Skamil	name[1] = KERN_PROC2,
80591.103Skamil	name[2] = KERN_PROC_PID;
80601.103Skamil	name[3] = child;
80611.103Skamil	name[4] = sizeof(kp);
80621.103Skamil	name[5] = 1;
80631.103Skamil
80641.103Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
80651.103Skamil
80661.103Skamil	if (masked)
80671.103Skamil		kp_sigmask = kp.p_sigmask;
80681.103Skamil
80691.103Skamil	if (ignored)
80701.103Skamil		kp_sigignore = kp.p_sigignore;
80711.103Skamil
80721.103Skamil	DPRINTF("Set PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE in "
80731.103Skamil	    "EVENT_MASK for the child %d\n", child);
80741.103Skamil	event.pe_set_event = PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE;
80751.103Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
80761.103Skamil
80771.103Skamil	DPRINTF("Before resuming the child process where it left off and "
80781.103Skamil	    "without signal to be sent\n");
80791.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
80801.103Skamil
80811.103Skamil	DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
80821.103Skamil	    child);
80831.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
80841.103Skamil	    child);
80851.103Skamil
80861.103Skamil	validate_status_stopped(status, SIGTRAP);
80871.103Skamil
80881.103Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
80891.103Skamil
80901.103Skamil	if (masked) {
80911.103Skamil		DPRINTF("kp_sigmask="
80921.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
80931.103Skamil		    PRIx32 "\n",
80941.103Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
80951.103Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
80961.103Skamil
80971.103Skamil		DPRINTF("kp.p_sigmask="
80981.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
80991.103Skamil		    PRIx32 "\n",
81001.103Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
81011.103Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
81021.103Skamil
81031.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
81041.103Skamil		    sizeof(kp_sigmask)));
81051.103Skamil	}
81061.103Skamil
81071.103Skamil	if (ignored) {
81081.103Skamil		DPRINTF("kp_sigignore="
81091.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
81101.103Skamil		    PRIx32 "\n",
81111.103Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
81121.103Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
81131.103Skamil
81141.103Skamil		DPRINTF("kp.p_sigignore="
81151.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
81161.103Skamil		    PRIx32 "\n",
81171.103Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
81181.103Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
81191.103Skamil
81201.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
81211.103Skamil		    sizeof(kp_sigignore)));
81221.103Skamil	}
81231.103Skamil
81241.103Skamil	SYSCALL_REQUIRE(
81251.103Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
81261.103Skamil	DPRINTF("state.pe_report_event=%#x pid=%d\n", state.pe_report_event,
81271.103Skamil	    child2);
81281.103Skamil	if (!(flags & CLONE_VFORK)) {
81291.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
81301.103Skamil		       PTRACE_FORK);
81311.103Skamil	} else {
81321.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
81331.103Skamil		       PTRACE_VFORK);
81341.103Skamil	}
81351.103Skamil
81361.103Skamil	child2 = state.pe_other_pid;
81371.103Skamil	DPRINTF("Reported ptrace event with forkee %d\n", child2);
81381.103Skamil
81391.103Skamil	DPRINTF("Before calling %s() for the forkee %d of the child "
81401.103Skamil	    "%d\n", TWAIT_FNAME, child2, child);
81411.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
81421.103Skamil	    child2);
81431.103Skamil
81441.103Skamil	validate_status_stopped(status, SIGTRAP);
81451.103Skamil
81461.103Skamil	name[3] = child2;
81471.103Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
81481.103Skamil
81491.103Skamil	if (masked) {
81501.103Skamil		DPRINTF("kp_sigmask="
81511.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
81521.103Skamil		    PRIx32 "\n",
81531.103Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
81541.103Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
81551.103Skamil
81561.103Skamil		DPRINTF("kp.p_sigmask="
81571.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
81581.103Skamil		    PRIx32 "\n",
81591.103Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
81601.103Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
81611.103Skamil
81621.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
81631.103Skamil		    sizeof(kp_sigmask)));
81641.103Skamil	}
81651.103Skamil
81661.103Skamil	if (ignored) {
81671.103Skamil		DPRINTF("kp_sigignore="
81681.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
81691.103Skamil		    PRIx32 "\n",
81701.103Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
81711.103Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
81721.103Skamil
81731.103Skamil		DPRINTF("kp.p_sigignore="
81741.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
81751.103Skamil		    PRIx32 "\n",
81761.103Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
81771.103Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
81781.103Skamil
81791.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
81801.103Skamil		    sizeof(kp_sigignore)));
81811.103Skamil	}
81821.103Skamil
81831.103Skamil	SYSCALL_REQUIRE(
81841.103Skamil	    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
81851.103Skamil	if (!(flags & CLONE_VFORK)) {
81861.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
81871.103Skamil		       PTRACE_FORK);
81881.103Skamil	} else {
81891.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
81901.103Skamil		       PTRACE_VFORK);
81911.103Skamil	}
81921.103Skamil
81931.103Skamil	ATF_REQUIRE_EQ(state.pe_other_pid, child);
81941.103Skamil
81951.103Skamil	DPRINTF("Before resuming the forkee process where it left off "
81961.103Skamil	    "and without signal to be sent\n");
81971.103Skamil	SYSCALL_REQUIRE(
81981.103Skamil	    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
81991.103Skamil
82001.103Skamil	DPRINTF("Before resuming the child process where it left off "
82011.103Skamil	    "and without signal to be sent\n");
82021.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
82031.103Skamil
82041.103Skamil	if (flags & CLONE_VFORK) {
82051.103Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
82061.103Skamil		    child);
82071.103Skamil		TWAIT_REQUIRE_SUCCESS(
82081.103Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
82091.103Skamil
82101.103Skamil		validate_status_stopped(status, SIGTRAP);
82111.103Skamil
82121.103Skamil		name[3] = child;
82131.103Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
82141.103Skamil
82151.103Skamil		/*
82161.103Skamil		 * SIGCHLD is now pending in the signal queue and
82171.103Skamil		 * the kernel presents it to userland as a masked signal.
82181.103Skamil		 */
82191.103Skamil		sigdelset((sigset_t *)&kp.p_sigmask, SIGCHLD);
82201.103Skamil
82211.103Skamil		if (masked) {
82221.103Skamil			DPRINTF("kp_sigmask="
82231.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
82241.103Skamil			    PRIx32 "\n",
82251.103Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
82261.103Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
82271.103Skamil
82281.103Skamil			DPRINTF("kp.p_sigmask="
82291.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
82301.103Skamil			    PRIx32 "\n",
82311.103Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
82321.103Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
82331.103Skamil
82341.103Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
82351.103Skamil			    sizeof(kp_sigmask)));
82361.103Skamil		}
82371.103Skamil
82381.103Skamil		if (ignored) {
82391.103Skamil			DPRINTF("kp_sigignore="
82401.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
82411.103Skamil			    PRIx32 "\n",
82421.103Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
82431.103Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
82441.103Skamil
82451.103Skamil			DPRINTF("kp.p_sigignore="
82461.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
82471.103Skamil			    PRIx32 "\n",
82481.103Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
82491.103Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
82501.103Skamil
82511.103Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
82521.103Skamil			    sizeof(kp_sigignore)));
82531.103Skamil		}
82541.103Skamil
82551.103Skamil		SYSCALL_REQUIRE(
82561.103Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
82571.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
82581.103Skamil
82591.103Skamil		child2 = state.pe_other_pid;
82601.103Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
82611.103Skamil		    child2);
82621.103Skamil
82631.103Skamil		DPRINTF("Before resuming the child process where it left off "
82641.103Skamil		    "and without signal to be sent\n");
82651.103Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
82661.103Skamil	}
82671.103Skamil
82681.103Skamil	DPRINTF("Before calling %s() for the forkee - expected exited"
82691.103Skamil	    "\n", TWAIT_FNAME);
82701.103Skamil	TWAIT_REQUIRE_SUCCESS(
82711.103Skamil	    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
82721.103Skamil
82731.103Skamil	validate_status_exited(status, exitval2);
82741.103Skamil
82751.103Skamil	DPRINTF("Before calling %s() for the forkee - expected no "
82761.103Skamil	    "process\n", TWAIT_FNAME);
82771.103Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
82781.103Skamil	    wpid = TWAIT_GENERIC(child2, &status, 0));
82791.103Skamil
82801.103Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
82811.103Skamil	    "SIGCHLD\n", TWAIT_FNAME);
82821.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
82831.103Skamil
82841.103Skamil	validate_status_stopped(status, SIGCHLD);
82851.103Skamil
82861.103Skamil	DPRINTF("Before resuming the child process where it left off and "
82871.103Skamil	    "without signal to be sent\n");
82881.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
82891.103Skamil
82901.103Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
82911.103Skamil	    TWAIT_FNAME);
82921.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
82931.103Skamil
82941.103Skamil	validate_status_exited(status, exitval);
82951.103Skamil
82961.103Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
82971.103Skamil	    TWAIT_FNAME);
82981.103Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
82991.103Skamil}
83001.103Skamil
83011.106Skamil#define CLONE_TEST2(name,flags,masked,ignored)				\
83021.103SkamilATF_TC(name);								\
83031.103SkamilATF_TC_HEAD(name, tc)							\
83041.103Skamil{									\
83051.103Skamil	atf_tc_set_md_var(tc, "descr", "Verify that clone(%s) is caught"\
83061.103Skamil	    " regardless of signal %s%s", 				\
83071.103Skamil	    #flags, masked ? "masked" : "", ignored ? "ignored" : "");	\
83081.103Skamil}									\
83091.103Skamil									\
83101.103SkamilATF_TC_BODY(name, tc)							\
83111.103Skamil{									\
83121.103Skamil									\
83131.106Skamil	clone_body2(flags, masked, ignored);				\
83141.103Skamil}
83151.103Skamil
83161.106SkamilCLONE_TEST2(clone_signalignored, 0, true, false)
83171.106SkamilCLONE_TEST2(clone_signalmasked, 0, false, true)
83181.106SkamilCLONE_TEST2(clone_vm_signalignored, CLONE_VM, true, false)
83191.106SkamilCLONE_TEST2(clone_vm_signalmasked, CLONE_VM, false, true)
83201.106SkamilCLONE_TEST2(clone_fs_signalignored, CLONE_FS, true, false)
83211.106SkamilCLONE_TEST2(clone_fs_signalmasked, CLONE_FS, false, true)
83221.106SkamilCLONE_TEST2(clone_files_signalignored, CLONE_FILES, true, false)
83231.106SkamilCLONE_TEST2(clone_files_signalmasked, CLONE_FILES, false, true)
83241.106Skamil//CLONE_TEST2(clone_sighand_signalignored, CLONE_SIGHAND, true, false) // XXX
83251.106Skamil//CLONE_TEST2(clone_sighand_signalmasked, CLONE_SIGHAND, false, true)  // XXX
83261.106SkamilCLONE_TEST2(clone_vfork_signalignored, CLONE_VFORK, true, false)
83271.106SkamilCLONE_TEST2(clone_vfork_signalmasked, CLONE_VFORK, false, true)
83281.103Skamil#endif
83291.103Skamil
83301.103Skamil/// ----------------------------------------------------------------------------
83311.103Skamil
83321.107Skamil#if defined(TWAIT_HAVE_PID)
83331.107Skamilstatic void
83341.107Skamiltraceme_vfork_clone_body(int flags)
83351.107Skamil{
83361.107Skamil	const int exitval = 5;
83371.107Skamil	const int exitval2 = 15;
83381.107Skamil	pid_t child, child2 = 0, wpid;
83391.107Skamil#if defined(TWAIT_HAVE_STATUS)
83401.107Skamil	int status;
83411.107Skamil#endif
83421.107Skamil
83431.107Skamil	const size_t stack_size = 1024 * 1024;
83441.107Skamil	void *stack, *stack_base;
83451.107Skamil
83461.107Skamil	stack = malloc(stack_size);
83471.107Skamil	ATF_REQUIRE(stack != NULL);
83481.107Skamil
83491.107Skamil#ifdef __MACHINE_STACK_GROWS_UP
83501.107Skamil	stack_base = stack;
83511.107Skamil#else
83521.107Skamil	stack_base = (char *)stack + stack_size;
83531.107Skamil#endif
83541.107Skamil
83551.107Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
83561.107Skamil	if (child == 0) {
83571.107Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
83581.107Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
83591.107Skamil
83601.107Skamil		DPRINTF("Before forking process PID=%d flags=%#x\n", getpid(),
83611.107Skamil		    flags);
83621.107Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
83631.107Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
83641.107Skamil
83651.107Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
83661.107Skamil		    child2);
83671.107Skamil
83681.107Skamil		// XXX WALLSIG?
83691.107Skamil		FORKEE_REQUIRE_SUCCESS
83701.107Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
83711.107Skamil
83721.107Skamil		forkee_status_exited(status, exitval2);
83731.107Skamil
83741.107Skamil		DPRINTF("Before exiting of the child process\n");
83751.107Skamil		_exit(exitval);
83761.107Skamil	}
83771.107Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
83781.107Skamil
83791.107Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
83801.107Skamil	    TWAIT_FNAME);
83811.107Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
83821.107Skamil
83831.107Skamil	validate_status_exited(status, exitval);
83841.107Skamil
83851.107Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
83861.107Skamil	    TWAIT_FNAME);
83871.107Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
83881.107Skamil}
83891.107Skamil
83901.107Skamil#define TRACEME_VFORK_CLONE_TEST(name,flags)				\
83911.107SkamilATF_TC(name);								\
83921.107SkamilATF_TC_HEAD(name, tc)							\
83931.107Skamil{									\
83941.107Skamil	atf_tc_set_md_var(tc, "descr", "Verify that clone(%s) is "	\
83951.107Skamil	    "handled correctly with vfork(2)ed tracer", 		\
83961.107Skamil	    #flags);							\
83971.107Skamil}									\
83981.107Skamil									\
83991.107SkamilATF_TC_BODY(name, tc)							\
84001.107Skamil{									\
84011.107Skamil									\
84021.107Skamil	traceme_vfork_clone_body(flags);				\
84031.107Skamil}
84041.107Skamil
84051.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone, 0)
84061.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_vm, CLONE_VM)
84071.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_fs, CLONE_FS)
84081.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_files, CLONE_FILES)
84091.107Skamil//TRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_sighand, CLONE_SIGHAND)  // XXX
84101.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_vfork, CLONE_VFORK)
84111.107Skamil#endif
84121.107Skamil
84131.107Skamil/// ----------------------------------------------------------------------------
84141.107Skamil
84151.122Skamilstatic void
84161.122Skamiluser_va0_disable(int operation)
84171.122Skamil{
84181.122Skamil	pid_t child, wpid;
84191.122Skamil#if defined(TWAIT_HAVE_STATUS)
84201.122Skamil	int status;
84211.122Skamil#endif
84221.122Skamil	const int sigval = SIGSTOP;
84231.122Skamil	int rv;
84241.122Skamil
84251.122Skamil	struct ptrace_siginfo info;
84261.122Skamil
84271.122Skamil	if (get_user_va0_disable() == 0)
84281.122Skamil		atf_tc_skip("vm.user_va0_disable is set to 0");
84291.122Skamil
84301.122Skamil	memset(&info, 0, sizeof(info));
84311.122Skamil
84321.122Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
84331.122Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
84341.122Skamil	if (child == 0) {
84351.122Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
84361.122Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
84371.122Skamil
84381.122Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
84391.122Skamil		FORKEE_ASSERT(raise(sigval) == 0);
84401.122Skamil
84411.122Skamil		/* NOTREACHED */
84421.122Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
84431.122Skamil		__unreachable();
84441.122Skamil	}
84451.122Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
84461.122Skamil
84471.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
84481.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
84491.122Skamil
84501.122Skamil	validate_status_stopped(status, sigval);
84511.122Skamil
84521.122Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
84531.122Skamil		"child\n");
84541.122Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
84551.122Skamil		sizeof(info)) != -1);
84561.122Skamil
84571.122Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
84581.122Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
84591.122Skamil		"si_errno=%#x\n",
84601.122Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
84611.122Skamil		info.psi_siginfo.si_errno);
84621.122Skamil
84631.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
84641.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
84651.122Skamil
84661.122Skamil	DPRINTF("Before resuming the child process in PC=0x0 "
84671.122Skamil	    "and without signal to be sent\n");
84681.122Skamil	errno = 0;
84691.122Skamil	rv = ptrace(operation, child, (void *)0, 0);
84701.122Skamil	ATF_REQUIRE_EQ(errno, EINVAL);
84711.122Skamil	ATF_REQUIRE_EQ(rv, -1);
84721.122Skamil
84731.122Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
84741.122Skamil
84751.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
84761.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
84771.122Skamil	validate_status_signaled(status, SIGKILL, 0);
84781.122Skamil
84791.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
84801.122Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
84811.122Skamil}
84821.122Skamil
84831.122Skamil#define USER_VA0_DISABLE(test, operation)				\
84841.122SkamilATF_TC(test);								\
84851.122SkamilATF_TC_HEAD(test, tc)							\
84861.122Skamil{									\
84871.122Skamil	atf_tc_set_md_var(tc, "descr",					\
84881.122Skamil	    "Verify behavior of " #operation " with PC set to 0x0");	\
84891.122Skamil}									\
84901.122Skamil									\
84911.122SkamilATF_TC_BODY(test, tc)							\
84921.122Skamil{									\
84931.122Skamil									\
84941.122Skamil	user_va0_disable(operation);					\
84951.122Skamil}
84961.122Skamil
84971.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_continue, PT_CONTINUE)
84981.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_syscall, PT_SYSCALL)
84991.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_detach, PT_DETACH)
85001.122Skamil
85011.122Skamil/// ----------------------------------------------------------------------------
85021.122Skamil
85031.130Smgorny/*
85041.130Smgorny * Parse the core file and find the requested note.  If the reading or parsing
85051.130Smgorny * fails, the test is failed.  If the note is found, it is read onto buf, up to
85061.130Smgorny * buf_len.  The actual length of the note is returned (which can be greater
85071.130Smgorny * than buf_len, indicating that it has been truncated).  If the note is not
85081.130Smgorny * found, -1 is returned.
85091.130Smgorny */
85101.130Smgornystatic ssize_t core_find_note(const char *core_path,
85111.130Smgorny    const char *note_name, uint64_t note_type, void *buf, size_t buf_len)
85121.130Smgorny{
85131.130Smgorny	int core_fd;
85141.130Smgorny	Elf *core_elf;
85151.130Smgorny	size_t core_numhdr, i;
85161.130Smgorny	ssize_t ret = -1;
85171.130Smgorny	/* note: we assume note name will be null-terminated */
85181.130Smgorny	size_t name_len = strlen(note_name) + 1;
85191.130Smgorny
85201.130Smgorny	SYSCALL_REQUIRE((core_fd = open(core_path, O_RDONLY)) != -1);
85211.130Smgorny	SYSCALL_REQUIRE(elf_version(EV_CURRENT) != EV_NONE);
85221.130Smgorny	SYSCALL_REQUIRE((core_elf = elf_begin(core_fd, ELF_C_READ, NULL)));
85231.130Smgorny
85241.130Smgorny	SYSCALL_REQUIRE(elf_getphnum(core_elf, &core_numhdr) != 0);
85251.130Smgorny	for (i = 0; i < core_numhdr && ret == -1; i++) {
85261.130Smgorny		GElf_Phdr core_hdr;
85271.130Smgorny		size_t offset;
85281.130Smgorny		SYSCALL_REQUIRE(gelf_getphdr(core_elf, i, &core_hdr));
85291.130Smgorny		if (core_hdr.p_type != PT_NOTE)
85301.130Smgorny		    continue;
85311.130Smgorny
85321.130Smgorny		for (offset = core_hdr.p_offset;
85331.130Smgorny		    offset < core_hdr.p_offset + core_hdr.p_filesz;) {
85341.130Smgorny			Elf64_Nhdr note_hdr;
85351.130Smgorny			char name_buf[64];
85361.130Smgorny
85371.130Smgorny			switch (gelf_getclass(core_elf)) {
85381.130Smgorny			case ELFCLASS64:
85391.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &note_hdr,
85401.130Smgorny				    sizeof(note_hdr), offset)
85411.130Smgorny				    == sizeof(note_hdr));
85421.130Smgorny				offset += sizeof(note_hdr);
85431.130Smgorny				break;
85441.130Smgorny			case ELFCLASS32:
85451.130Smgorny				{
85461.130Smgorny				Elf32_Nhdr tmp_hdr;
85471.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &tmp_hdr,
85481.130Smgorny				    sizeof(tmp_hdr), offset)
85491.130Smgorny				    == sizeof(tmp_hdr));
85501.130Smgorny				offset += sizeof(tmp_hdr);
85511.130Smgorny				note_hdr.n_namesz = tmp_hdr.n_namesz;
85521.130Smgorny				note_hdr.n_descsz = tmp_hdr.n_descsz;
85531.130Smgorny				note_hdr.n_type = tmp_hdr.n_type;
85541.130Smgorny				}
85551.130Smgorny				break;
85561.130Smgorny			}
85571.130Smgorny
85581.130Smgorny			/* indicates end of notes */
85591.130Smgorny			if (note_hdr.n_namesz == 0 || note_hdr.n_descsz == 0)
85601.130Smgorny				break;
85611.130Smgorny			if (note_hdr.n_namesz == name_len &&
85621.130Smgorny			    note_hdr.n_namesz <= sizeof(name_buf)) {
85631.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, name_buf,
85641.130Smgorny				    note_hdr.n_namesz, offset)
85651.131Skamil				    == (ssize_t)(size_t)note_hdr.n_namesz);
85661.130Smgorny
85671.130Smgorny				if (!strncmp(note_name, name_buf, name_len) &&
85681.130Smgorny				    note_hdr.n_type == note_type)
85691.130Smgorny					ret = note_hdr.n_descsz;
85701.130Smgorny			}
85711.130Smgorny
85721.130Smgorny			offset += note_hdr.n_namesz;
85731.130Smgorny			/* fix to alignment */
85741.146Smgorny			offset = roundup(offset, core_hdr.p_align);
85751.130Smgorny
85761.130Smgorny			/* if name & type matched above */
85771.130Smgorny			if (ret != -1) {
85781.130Smgorny				ssize_t read_len = MIN(buf_len,
85791.130Smgorny				    note_hdr.n_descsz);
85801.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, buf,
85811.130Smgorny				    read_len, offset) == read_len);
85821.130Smgorny				break;
85831.130Smgorny			}
85841.130Smgorny
85851.130Smgorny			offset += note_hdr.n_descsz;
85861.146Smgorny			/* fix to alignment */
85871.146Smgorny			offset = roundup(offset, core_hdr.p_align);
85881.130Smgorny		}
85891.130Smgorny	}
85901.130Smgorny
85911.130Smgorny	elf_end(core_elf);
85921.130Smgorny	close(core_fd);
85931.130Smgorny
85941.130Smgorny	return ret;
85951.130Smgorny}
85961.130Smgorny
85971.130SmgornyATF_TC(core_dump_procinfo);
85981.130SmgornyATF_TC_HEAD(core_dump_procinfo, tc)
85991.130Smgorny{
86001.130Smgorny	atf_tc_set_md_var(tc, "descr",
86011.130Smgorny		"Trigger a core dump and verify its contents.");
86021.130Smgorny}
86031.130Smgorny
86041.130SmgornyATF_TC_BODY(core_dump_procinfo, tc)
86051.130Smgorny{
86061.130Smgorny	const int exitval = 5;
86071.130Smgorny	pid_t child, wpid;
86081.130Smgorny#if defined(TWAIT_HAVE_STATUS)
86091.130Smgorny	const int sigval = SIGTRAP;
86101.130Smgorny	int status;
86111.130Smgorny#endif
86121.130Smgorny	char core_path[] = "/tmp/core.XXXXXX";
86131.130Smgorny	int core_fd;
86141.130Smgorny	struct netbsd_elfcore_procinfo procinfo;
86151.130Smgorny
86161.130Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
86171.130Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
86181.130Smgorny	if (child == 0) {
86191.130Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
86201.130Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
86211.130Smgorny
86221.130Smgorny		DPRINTF("Before triggering SIGTRAP\n");
86231.130Smgorny		trigger_trap();
86241.130Smgorny
86251.130Smgorny		DPRINTF("Before exiting of the child process\n");
86261.130Smgorny		_exit(exitval);
86271.130Smgorny	}
86281.130Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
86291.130Smgorny
86301.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
86311.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
86321.130Smgorny
86331.130Smgorny	validate_status_stopped(status, sigval);
86341.130Smgorny
86351.130Smgorny	SYSCALL_REQUIRE((core_fd = mkstemp(core_path)) != -1);
86361.130Smgorny	close(core_fd);
86371.130Smgorny
86381.130Smgorny	DPRINTF("Call DUMPCORE for the child process\n");
86391.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_DUMPCORE, child, core_path, strlen(core_path))
86401.130Smgorny	    != -1);
86411.130Smgorny
86421.130Smgorny	DPRINTF("Read core file\n");
86431.130Smgorny	ATF_REQUIRE_EQ(core_find_note(core_path, "NetBSD-CORE",
86441.130Smgorny	    ELF_NOTE_NETBSD_CORE_PROCINFO, &procinfo, sizeof(procinfo)),
86451.130Smgorny	    sizeof(procinfo));
86461.130Smgorny
86471.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_version, 1);
86481.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_cpisize, sizeof(procinfo));
86491.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_signo, SIGTRAP);
86501.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pid, child);
86511.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ppid, getpid());
86521.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pgrp, getpgid(child));
86531.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_sid, getsid(child));
86541.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ruid, getuid());
86551.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_euid, geteuid());
86561.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_rgid, getgid());
86571.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_egid, getegid());
86581.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_nlwps, 1);
86591.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_siglwp, 1);
86601.130Smgorny
86611.130Smgorny	unlink(core_path);
86621.130Smgorny
86631.130Smgorny	DPRINTF("Before resuming the child process where it left off and "
86641.130Smgorny	    "without signal to be sent\n");
86651.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
86661.130Smgorny
86671.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
86681.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
86691.130Smgorny
86701.130Smgorny	validate_status_exited(status, exitval);
86711.130Smgorny
86721.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
86731.130Smgorny	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
86741.130Smgorny}
86751.130Smgorny
86761.130Smgorny/// ----------------------------------------------------------------------------
86771.130Smgorny
86781.138Smgorny#if defined(TWAIT_HAVE_STATUS)
86791.138Smgorny
86801.160Smgorny#define THREAD_CONCURRENT_BREAKPOINT_NUM 50
86811.156Smgorny#define THREAD_CONCURRENT_SIGNALS_NUM 50
86821.161Smgorny#define THREAD_CONCURRENT_WATCHPOINT_NUM 50
86831.138Smgorny
86841.138Smgorny/* List of signals to use for the test */
86851.138Smgornyconst int thread_concurrent_signals_list[] = {
86861.138Smgorny	SIGIO,
86871.138Smgorny	SIGXCPU,
86881.138Smgorny	SIGXFSZ,
86891.138Smgorny	SIGVTALRM,
86901.138Smgorny	SIGPROF,
86911.138Smgorny	SIGWINCH,
86921.138Smgorny	SIGINFO,
86931.138Smgorny	SIGUSR1,
86941.138Smgorny	SIGUSR2
86951.138Smgorny};
86961.138Smgorny
86971.157Smgornyenum thread_concurrent_signal_handling {
86981.157Smgorny	/* the signal is discarded by debugger */
86991.157Smgorny	TCSH_DISCARD,
87001.157Smgorny	/* the handler is set to SIG_IGN */
87011.157Smgorny	TCSH_SIG_IGN,
87021.157Smgorny	/* an actual handler is used */
87031.157Smgorny	TCSH_HANDLER
87041.157Smgorny};
87051.157Smgorny
87061.156Smgornystatic pthread_barrier_t thread_concurrent_barrier;
87071.158Smgornystatic pthread_key_t thread_concurrent_key;
87081.161Smgornystatic uint32_t thread_concurrent_watchpoint_var = 0;
87091.138Smgorny
87101.160Smgornystatic void *
87111.160Smgornythread_concurrent_breakpoint_thread(void *arg)
87121.160Smgorny{
87131.160Smgorny	static volatile int watchme = 1;
87141.160Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
87151.160Smgorny	DPRINTF("Before entering breakpoint func from LWP %d\n", _lwp_self());
87161.160Smgorny	check_happy(watchme);
87171.160Smgorny	return NULL;
87181.160Smgorny}
87191.160Smgorny
87201.157Smgornystatic void
87211.157Smgornythread_concurrent_sig_handler(int sig)
87221.157Smgorny{
87231.158Smgorny	void *tls_val = pthread_getspecific(thread_concurrent_key);
87241.158Smgorny	DPRINTF("Before increment, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
87251.158Smgorny	FORKEE_ASSERT(pthread_setspecific(thread_concurrent_key,
87261.158Smgorny	    (void*)((uintptr_t)tls_val + 1)) == 0);
87271.157Smgorny}
87281.157Smgorny
87291.138Smgornystatic void *
87301.138Smgornythread_concurrent_signals_thread(void *arg)
87311.138Smgorny{
87321.138Smgorny	int sigval = thread_concurrent_signals_list[
87331.138Smgorny	    _lwp_self() % __arraycount(thread_concurrent_signals_list)];
87341.158Smgorny	enum thread_concurrent_signal_handling *signal_handle = arg;
87351.158Smgorny	void *tls_val;
87361.158Smgorny
87371.156Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
87381.138Smgorny	DPRINTF("Before raising %s from LWP %d\n", strsignal(sigval),
87391.138Smgorny		_lwp_self());
87401.138Smgorny	pthread_kill(pthread_self(), sigval);
87411.158Smgorny	if (*signal_handle == TCSH_HANDLER) {
87421.158Smgorny	    tls_val = pthread_getspecific(thread_concurrent_key);
87431.158Smgorny	    DPRINTF("After raising, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
87441.158Smgorny	    FORKEE_ASSERT(tls_val == (void*)1);
87451.158Smgorny	}
87461.138Smgorny	return NULL;
87471.138Smgorny}
87481.138Smgorny
87491.161Smgornystatic void *
87501.161Smgornythread_concurrent_watchpoint_thread(void *arg)
87511.161Smgorny{
87521.161Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
87531.161Smgorny	DPRINTF("Before modifying var from LWP %d\n", _lwp_self());
87541.161Smgorny	thread_concurrent_watchpoint_var = 1;
87551.161Smgorny	return NULL;
87561.161Smgorny}
87571.161Smgorny
87581.160Smgorny#if defined(__i386__) || defined(__x86_64__)
87591.160Smgornyenum thread_concurrent_sigtrap_event {
87601.160Smgorny	TCSE_UNKNOWN,
87611.161Smgorny	TCSE_BREAKPOINT,
87621.161Smgorny	TCSE_WATCHPOINT
87631.160Smgorny};
87641.160Smgorny
87651.160Smgornystatic void
87661.160Smgornythread_concurrent_lwp_setup(pid_t child, lwpid_t lwpid);
87671.160Smgornystatic enum thread_concurrent_sigtrap_event
87681.160Smgornythread_concurrent_handle_sigtrap(pid_t child, ptrace_siginfo_t *info);
87691.160Smgorny#endif
87701.160Smgorny
87711.156Smgornystatic void
87721.157Smgornythread_concurrent_test(enum thread_concurrent_signal_handling signal_handle,
87731.161Smgorny    int breakpoint_threads, int signal_threads, int watchpoint_threads)
87741.138Smgorny{
87751.138Smgorny	const int exitval = 5;
87761.138Smgorny	const int sigval = SIGSTOP;
87771.138Smgorny	pid_t child, wpid;
87781.138Smgorny	int status;
87791.141Skamil	struct lwp_event_count signal_counts[THREAD_CONCURRENT_SIGNALS_NUM]
87801.141Skamil	    = {{0, 0}};
87811.160Smgorny	struct lwp_event_count bp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
87821.160Smgorny	    = {{0, 0}};
87831.161Smgorny	struct lwp_event_count wp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
87841.161Smgorny	    = {{0, 0}};
87851.159Smgorny	ptrace_event_t event;
87861.156Smgorny	int i;
87871.156Smgorny
87881.164Skamil#if defined(HAVE_DBREGS)
87891.164Skamil	if (!can_we_set_dbregs()) {
87901.164Skamil		atf_tc_skip("Either run this test as root or set sysctl(3) "
87911.164Skamil		            "security.models.extensions.user_set_dbregs to 1");
87921.164Skamil        }
87931.164Skamil#endif
87941.164Skamil
87951.164Skamil	atf_tc_skip("PR kern/54960");
87961.157Smgorny
87971.156Smgorny	/* Protect against out-of-bounds array access. */
87981.160Smgorny	ATF_REQUIRE(breakpoint_threads <= THREAD_CONCURRENT_BREAKPOINT_NUM);
87991.156Smgorny	ATF_REQUIRE(signal_threads <= THREAD_CONCURRENT_SIGNALS_NUM);
88001.161Smgorny	ATF_REQUIRE(watchpoint_threads <= THREAD_CONCURRENT_WATCHPOINT_NUM);
88011.138Smgorny
88021.138Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
88031.138Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
88041.138Smgorny	if (child == 0) {
88051.160Smgorny		pthread_t bp_threads[THREAD_CONCURRENT_BREAKPOINT_NUM];
88061.156Smgorny		pthread_t sig_threads[THREAD_CONCURRENT_SIGNALS_NUM];
88071.161Smgorny		pthread_t wp_threads[THREAD_CONCURRENT_WATCHPOINT_NUM];
88081.138Smgorny
88091.138Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
88101.138Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
88111.138Smgorny
88121.138Smgorny		DPRINTF("Before raising %s from child\n", strsignal(sigval));
88131.138Smgorny		FORKEE_ASSERT(raise(sigval) == 0);
88141.138Smgorny
88151.157Smgorny		if (signal_handle != TCSH_DISCARD) {
88161.157Smgorny			struct sigaction sa;
88171.157Smgorny			unsigned int j;
88181.157Smgorny
88191.157Smgorny			memset(&sa, 0, sizeof(sa));
88201.157Smgorny			if (signal_handle == TCSH_SIG_IGN)
88211.157Smgorny				sa.sa_handler = SIG_IGN;
88221.157Smgorny			else
88231.157Smgorny				sa.sa_handler = thread_concurrent_sig_handler;
88241.157Smgorny			sigemptyset(&sa.sa_mask);
88251.157Smgorny
88261.157Smgorny			for (j = 0;
88271.157Smgorny			    j < __arraycount(thread_concurrent_signals_list);
88281.157Smgorny			    j++)
88291.157Smgorny				FORKEE_ASSERT(sigaction(
88301.157Smgorny				    thread_concurrent_signals_list[j], &sa, NULL)
88311.157Smgorny				    != -1);
88321.157Smgorny		}
88331.157Smgorny
88341.138Smgorny		DPRINTF("Before starting threads from the child\n");
88351.138Smgorny		FORKEE_ASSERT(pthread_barrier_init(
88361.156Smgorny		    &thread_concurrent_barrier, NULL,
88371.161Smgorny		    breakpoint_threads + signal_threads + watchpoint_threads)
88381.161Smgorny		    == 0);
88391.158Smgorny		FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL)
88401.158Smgorny		    == 0);
88411.138Smgorny
88421.156Smgorny		for (i = 0; i < signal_threads; i++) {
88431.156Smgorny			FORKEE_ASSERT(pthread_create(&sig_threads[i], NULL,
88441.158Smgorny			    thread_concurrent_signals_thread,
88451.158Smgorny			    &signal_handle) == 0);
88461.138Smgorny		}
88471.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
88481.160Smgorny			FORKEE_ASSERT(pthread_create(&bp_threads[i], NULL,
88491.160Smgorny			    thread_concurrent_breakpoint_thread, NULL) == 0);
88501.160Smgorny		}
88511.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
88521.161Smgorny			FORKEE_ASSERT(pthread_create(&wp_threads[i], NULL,
88531.161Smgorny			    thread_concurrent_watchpoint_thread, NULL) == 0);
88541.161Smgorny		}
88551.138Smgorny
88561.138Smgorny		DPRINTF("Before joining threads from the child\n");
88571.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
88581.161Smgorny			FORKEE_ASSERT(pthread_join(wp_threads[i], NULL) == 0);
88591.161Smgorny		}
88601.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
88611.160Smgorny			FORKEE_ASSERT(pthread_join(bp_threads[i], NULL) == 0);
88621.160Smgorny		}
88631.156Smgorny		for (i = 0; i < signal_threads; i++) {
88641.156Smgorny			FORKEE_ASSERT(pthread_join(sig_threads[i], NULL) == 0);
88651.138Smgorny		}
88661.138Smgorny
88671.158Smgorny		FORKEE_ASSERT(pthread_key_delete(thread_concurrent_key) == 0);
88681.138Smgorny		FORKEE_ASSERT(pthread_barrier_destroy(
88691.156Smgorny		    &thread_concurrent_barrier) == 0);
88701.138Smgorny
88711.138Smgorny		DPRINTF("Before exiting of the child process\n");
88721.138Smgorny		_exit(exitval);
88731.138Smgorny	}
88741.138Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
88751.138Smgorny
88761.138Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
88771.138Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
88781.138Smgorny
88791.138Smgorny	validate_status_stopped(status, sigval);
88801.138Smgorny
88811.159Smgorny	DPRINTF("Set LWP event mask for the child process\n");
88821.159Smgorny	memset(&event, 0, sizeof(event));
88831.159Smgorny	event.pe_set_event |= PTRACE_LWP_CREATE;
88841.159Smgorny	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, sizeof(event))
88851.159Smgorny	    != -1);
88861.159Smgorny
88871.138Smgorny	DPRINTF("Before resuming the child process where it left off\n");
88881.138Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
88891.138Smgorny
88901.138Smgorny	DPRINTF("Before entering signal collection loop\n");
88911.138Smgorny	while (1) {
88921.138Smgorny		ptrace_siginfo_t info;
88931.138Smgorny
88941.138Smgorny		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
88951.138Smgorny		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
88961.138Smgorny		    child);
88971.138Smgorny		if (WIFEXITED(status))
88981.138Smgorny			break;
88991.138Smgorny		/* Note: we use validate_status_stopped() to get nice error
89001.138Smgorny		 * message.  Signal is irrelevant since it won't be reached.
89011.138Smgorny		 */
89021.138Smgorny		else if (!WIFSTOPPED(status))
89031.138Smgorny			validate_status_stopped(status, 0);
89041.138Smgorny
89051.138Smgorny		DPRINTF("Before calling PT_GET_SIGINFO\n");
89061.138Smgorny		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
89071.138Smgorny		    sizeof(info)) != -1);
89081.138Smgorny
89091.138Smgorny		DPRINTF("Received signal %d from LWP %d (wait: %d)\n",
89101.138Smgorny		    info.psi_siginfo.si_signo, info.psi_lwpid,
89111.138Smgorny		    WSTOPSIG(status));
89121.138Smgorny
89131.159Smgorny		ATF_CHECK_EQ_MSG(info.psi_siginfo.si_signo, WSTOPSIG(status),
89141.159Smgorny		    "lwp=%d, WSTOPSIG=%d, psi_siginfo=%d", info.psi_lwpid,
89151.159Smgorny		    WSTOPSIG(status), info.psi_siginfo.si_signo);
89161.159Smgorny
89171.159Smgorny		if (WSTOPSIG(status) != SIGTRAP) {
89181.159Smgorny			int expected_sig =
89191.159Smgorny			    thread_concurrent_signals_list[info.psi_lwpid %
89201.159Smgorny			    __arraycount(thread_concurrent_signals_list)];
89211.159Smgorny			ATF_CHECK_EQ_MSG(WSTOPSIG(status), expected_sig,
89221.159Smgorny				"lwp=%d, expected %d, got %d", info.psi_lwpid,
89231.159Smgorny				expected_sig, WSTOPSIG(status));
89241.138Smgorny
89251.159Smgorny			*FIND_EVENT_COUNT(signal_counts, info.psi_lwpid) += 1;
89261.160Smgorny		} else if (info.psi_siginfo.si_code == TRAP_LWP) {
89271.160Smgorny#if defined(__i386__) || defined(__x86_64__)
89281.160Smgorny			thread_concurrent_lwp_setup(child, info.psi_lwpid);
89291.160Smgorny#endif
89301.159Smgorny		} else {
89311.160Smgorny#if defined(__i386__) || defined(__x86_64__)
89321.160Smgorny			switch (thread_concurrent_handle_sigtrap(child, &info)) {
89331.160Smgorny				case TCSE_UNKNOWN:
89341.160Smgorny					/* already reported inside the function */
89351.160Smgorny					break;
89361.160Smgorny				case TCSE_BREAKPOINT:
89371.160Smgorny					*FIND_EVENT_COUNT(bp_counts,
89381.160Smgorny					    info.psi_lwpid) += 1;
89391.160Smgorny					break;
89401.161Smgorny				case TCSE_WATCHPOINT:
89411.161Smgorny					*FIND_EVENT_COUNT(wp_counts,
89421.161Smgorny					    info.psi_lwpid) += 1;
89431.161Smgorny					break;
89441.160Smgorny			}
89451.160Smgorny#else
89461.160Smgorny			ATF_CHECK_MSG(0, "Unexpected SIGTRAP, si_code=%d\n",
89471.160Smgorny			    info.psi_siginfo.si_code);
89481.160Smgorny#endif
89491.159Smgorny		}
89501.138Smgorny
89511.138Smgorny		DPRINTF("Before resuming the child process\n");
89521.157Smgorny		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
89531.159Smgorny		     signal_handle != TCSH_DISCARD && WSTOPSIG(status) != SIGTRAP
89541.159Smgorny		     ? WSTOPSIG(status) : 0) != -1);
89551.138Smgorny	}
89561.138Smgorny
89571.156Smgorny	for (i = 0; i < signal_threads; i++)
89581.141Skamil		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 1,
89591.141Skamil		    "signal_counts[%d].lec_count=%d; lec_lwp=%d",
89601.141Skamil		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
89611.156Smgorny	for (i = signal_threads; i < THREAD_CONCURRENT_SIGNALS_NUM; i++)
89621.156Smgorny		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 0,
89631.156Smgorny		    "extraneous signal_counts[%d].lec_count=%d; lec_lwp=%d",
89641.156Smgorny		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
89651.138Smgorny
89661.160Smgorny	for (i = 0; i < breakpoint_threads; i++)
89671.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 1,
89681.160Smgorny		    "bp_counts[%d].lec_count=%d; lec_lwp=%d",
89691.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
89701.160Smgorny	for (i = breakpoint_threads; i < THREAD_CONCURRENT_BREAKPOINT_NUM; i++)
89711.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 0,
89721.160Smgorny		    "extraneous bp_counts[%d].lec_count=%d; lec_lwp=%d",
89731.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
89741.160Smgorny
89751.161Smgorny	for (i = 0; i < watchpoint_threads; i++)
89761.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 1,
89771.161Smgorny		    "wp_counts[%d].lec_count=%d; lec_lwp=%d",
89781.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
89791.161Smgorny	for (i = watchpoint_threads; i < THREAD_CONCURRENT_WATCHPOINT_NUM; i++)
89801.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 0,
89811.161Smgorny		    "extraneous wp_counts[%d].lec_count=%d; lec_lwp=%d",
89821.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
89831.161Smgorny
89841.138Smgorny	validate_status_exited(status, exitval);
89851.138Smgorny}
89861.138Smgorny
89871.161Smgorny#define THREAD_CONCURRENT_TEST(test, sig_hdl, bps, sigs, wps, descr)	\
89881.156SmgornyATF_TC(test);								\
89891.156SmgornyATF_TC_HEAD(test, tc)							\
89901.156Smgorny{									\
89911.156Smgorny	atf_tc_set_md_var(tc, "descr", descr);				\
89921.156Smgorny}									\
89931.156Smgorny									\
89941.156SmgornyATF_TC_BODY(test, tc)							\
89951.156Smgorny{									\
89961.161Smgorny	thread_concurrent_test(sig_hdl, bps, sigs, wps);		\
89971.156Smgorny}
89981.156Smgorny
89991.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals, TCSH_DISCARD,
90001.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
90011.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
90021.157Smgorny    "correctly");
90031.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_sig_ign, TCSH_SIG_IGN,
90041.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
90051.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
90061.157Smgorny    "correctly and passed back to SIG_IGN handler");
90071.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_handler, TCSH_HANDLER,
90081.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
90091.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
90101.157Smgorny    "correctly and passed back to a handler function");
90111.156Smgorny
90121.163Skamil#if defined(__i386__) || defined(__x86_64__)
90131.160SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_breakpoints, TCSH_DISCARD,
90141.161Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, 0,
90151.161Smgorny    "Verify that concurrent breakpoints are reported correctly");
90161.161SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_watchpoints, TCSH_DISCARD,
90171.161Smgorny    0, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
90181.160Smgorny    "Verify that concurrent breakpoints are reported correctly");
90191.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp, TCSH_DISCARD,
90201.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
90211.162Smgorny    "Verify that concurrent breakpoints and watchpoints are reported "
90221.162Smgorny    "correctly");
90231.162Smgorny
90241.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig, TCSH_DISCARD,
90251.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
90261.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly");
90271.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_sig_ign, TCSH_SIG_IGN,
90281.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
90291.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
90301.162Smgorny    "and passed back to SIG_IGN handler");
90311.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_handler, TCSH_HANDLER,
90321.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
90331.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
90341.162Smgorny    "and passed back to a handler function");
90351.162Smgorny
90361.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig, TCSH_DISCARD,
90371.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
90381.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly");
90391.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_sig_ign, TCSH_SIG_IGN,
90401.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
90411.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
90421.162Smgorny    "and passed back to SIG_IGN handler");
90431.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_handler, TCSH_HANDLER,
90441.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
90451.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
90461.162Smgorny    "and passed back to a handler function");
90471.162Smgorny
90481.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig, TCSH_DISCARD,
90491.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
90501.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
90511.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
90521.162Smgorny    "correctly");
90531.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_sig_ign, TCSH_SIG_IGN,
90541.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
90551.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
90561.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
90571.162Smgorny    "correctly and passed back to SIG_IGN handler");
90581.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_handler, TCSH_HANDLER,
90591.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
90601.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
90611.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
90621.162Smgorny    "correctly and passed back to a handler function");
90631.163Skamil#endif
90641.160Smgorny
90651.138Smgorny#endif /*defined(TWAIT_HAVE_STATUS)*/
90661.138Smgorny
90671.138Smgorny/// ----------------------------------------------------------------------------
90681.138Smgorny
90691.1Skamil#include "t_ptrace_amd64_wait.h"
90701.1Skamil#include "t_ptrace_i386_wait.h"
90711.1Skamil#include "t_ptrace_x86_wait.h"
90721.1Skamil
90731.165Skamil/// ----------------------------------------------------------------------------
90741.165Skamil
90751.165Skamil#else
90761.165SkamilATF_TC(dummy);
90771.165SkamilATF_TC_HEAD(dummy, tc)
90781.165Skamil{
90791.165Skamil	atf_tc_set_md_var(tc, "descr", "A dummy test");
90801.165Skamil}
90811.165Skamil
90821.165SkamilATF_TC_BODY(dummy, tc)
90831.165Skamil{
90841.165Skamil
90851.165Skamil	// Dummy, skipped
90861.165Skamil	// The ATF framework requires at least a single defined test.
90871.165Skamil}
90881.165Skamil#endif
90891.165Skamil
90901.1SkamilATF_TP_ADD_TCS(tp)
90911.1Skamil{
90921.1Skamil	setvbuf(stdout, NULL, _IONBF, 0);
90931.1Skamil	setvbuf(stderr, NULL, _IONBF, 0);
90941.33Skamil
90951.165Skamil#ifdef ENABLE_TESTS
90961.36Skamil	ATF_TP_ADD_TC(tp, traceme_raise1);
90971.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise2);
90981.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise3);
90991.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise4);
91001.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise5);
91011.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise6);
91021.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise7);
91031.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise8);
91041.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise9);
91051.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise10);
91061.33Skamil
91071.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored1);
91081.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored2);
91091.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored3);
91101.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored4);
91111.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored5);
91121.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored6);
91131.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored7);
91141.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored8);
91151.87Skamil
91161.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked1);
91171.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked2);
91181.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked3);
91191.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked4);
91201.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked5);
91211.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked6);
91221.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked7);
91231.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked8);
91241.86Skamil
91251.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_trap);
91261.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_segv);
91271.71Skamil	ATF_TP_ADD_TC(tp, traceme_crash_ill);
91281.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_fpe);
91291.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_bus);
91301.59Skamil
91311.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_trap);
91321.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_segv);
91331.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_ill);
91341.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_fpe);
91351.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_bus);
91361.88Skamil
91371.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_trap);
91381.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_segv);
91391.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_ill);
91401.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_fpe);
91411.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_bus);
91421.88Skamil
91431.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle1);
91441.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle2);
91451.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle3);
91461.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle4);
91471.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle5);
91481.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle6);
91491.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle7);
91501.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle8);
91511.50Skamil
91521.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked1);
91531.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked2);
91541.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked3);
91551.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked4);
91561.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked5);
91571.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked6);
91581.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked7);
91591.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked8);
91601.50Skamil
91611.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored1);
91621.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored2);
91631.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored3);
91641.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored4);
91651.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored5);
91661.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored6);
91671.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored7);
91681.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored8);
91691.50Skamil
91701.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple1);
91711.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple2);
91721.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple3);
91731.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple4);
91741.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple5);
91751.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple6);
91761.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple7);
91771.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple8);
91781.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple9);
91791.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple10);
91801.1Skamil
91811.37Skamil	ATF_TP_ADD_TC(tp, traceme_pid1_parent);
91821.37Skamil
91831.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise1);
91841.46Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise2);
91851.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise3);
91861.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise4);
91871.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise5);
91881.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise6);
91891.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise7);
91901.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise8);
91911.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise9);
91921.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise10);
91931.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise11);
91941.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise12);
91951.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise13);
91961.40Skamil
91971.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_trap);
91981.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_segv);
91991.71Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_ill);
92001.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_fpe);
92011.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_bus);
92021.41Skamil
92031.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_trap);
92041.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_segv);
92051.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_ill);
92061.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_fpe);
92071.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_bus);
92081.92Skamil
92091.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_trap);
92101.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_segv);
92111.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_ill);
92121.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_fpe);
92131.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_bus);
92141.92Skamil
92151.43Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_exec);
92161.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_exec);
92171.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_exec);
92181.43Skamil
92191.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_trap);
92201.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_segv);
92211.71Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_ill);
92221.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_fpe);
92231.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_bus);
92241.59Skamil
92251.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92261.94Skamil	    unrelated_tracer_sees_signalmasked_crash_trap);
92271.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92281.94Skamil	    unrelated_tracer_sees_signalmasked_crash_segv);
92291.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92301.94Skamil	    unrelated_tracer_sees_signalmasked_crash_ill);
92311.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92321.94Skamil	    unrelated_tracer_sees_signalmasked_crash_fpe);
92331.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92341.94Skamil	    unrelated_tracer_sees_signalmasked_crash_bus);
92351.94Skamil
92361.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92371.94Skamil	    unrelated_tracer_sees_signalignored_crash_trap);
92381.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92391.94Skamil	    unrelated_tracer_sees_signalignored_crash_segv);
92401.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92411.94Skamil	    unrelated_tracer_sees_signalignored_crash_ill);
92421.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92431.94Skamil	    unrelated_tracer_sees_signalignored_crash_fpe);
92441.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92451.94Skamil	    unrelated_tracer_sees_signalignored_crash_bus);
92461.94Skamil
92471.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sees_terminaton_before_the_parent);
92481.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sysctl_lookup_without_duplicates);
92491.61Skre	ATF_TP_ADD_TC_HAVE_PID(tp,
92501.61Skre		unrelated_tracer_sees_terminaton_before_the_parent);
92511.67Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_attach_to_unrelated_stopped_process);
92521.51Skamil
92531.51Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_child);
92541.66Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_stopped_child);
92551.51Skamil
92561.51Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_parent);
92571.65Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_stopped_parent);
92581.51Skamil
92591.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92601.51Skamil		tracee_sees_its_original_parent_getppid);
92611.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92621.51Skamil		tracee_sees_its_original_parent_sysctl_kinfo_proc2);
92631.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
92641.51Skamil		tracee_sees_its_original_parent_procfs_status);
92651.1Skamil
92661.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_empty);
92671.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_fork);
92681.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork);
92691.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork_done);
92701.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_create);
92711.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_exit);
92721.125Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_posix_spawn);
92731.1Skamil
92741.31Skamil	ATF_TP_ADD_TC(tp, fork1);
92751.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork2);
92761.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork3);
92771.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork4);
92781.31Skamil	ATF_TP_ADD_TC(tp, fork5);
92791.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork6);
92801.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork7);
92811.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork8);
92821.125Skamil	ATF_TP_ADD_TC(tp, fork9);
92831.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork10);
92841.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork11);
92851.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork12);
92861.125Skamil	ATF_TP_ADD_TC(tp, fork13);
92871.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork14);
92881.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork15);
92891.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork16);
92901.31Skamil
92911.31Skamil	ATF_TP_ADD_TC(tp, vfork1);
92921.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork2);
92931.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork3);
92941.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork4);
92951.31Skamil	ATF_TP_ADD_TC(tp, vfork5);
92961.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork6);
92971.104Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork7);
92981.104Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork8);
92991.125Skamil	ATF_TP_ADD_TC(tp, vfork9);
93001.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork10);
93011.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork11);
93021.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork12);
93031.125Skamil	ATF_TP_ADD_TC(tp, vfork13);
93041.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork14);
93051.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork15);
93061.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork16);
93071.1Skamil
93081.124Skamil	ATF_TP_ADD_TC(tp, posix_spawn1);
93091.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn2);
93101.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn3);
93111.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn4);
93121.124Skamil	ATF_TP_ADD_TC(tp, posix_spawn5);
93131.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn6);
93141.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn7);
93151.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn8);
93161.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn9);
93171.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn10);
93181.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn11);
93191.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn12);
93201.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn13);
93211.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn14);
93221.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn15);
93231.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn16);
93241.124Skamil
93251.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork1);
93261.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork2);
93271.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork3);
93281.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork4);
93291.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork5);
93301.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork6);
93311.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork7);
93321.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork8);
93331.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork9);
93341.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork10);
93351.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork11);
93361.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork12);
93371.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork13);
93381.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork14);
93391.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork15);
93401.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork16);
93411.149Skamil
93421.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork1);
93431.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork2);
93441.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork3);
93451.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork4);
93461.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork5);
93471.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork6);
93481.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork7);
93491.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork8);
93501.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork9);
93511.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork10);
93521.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork11);
93531.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork12);
93541.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork13);
93551.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork14);
93561.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork15);
93571.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork16);
93581.149Skamil
93591.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn1);
93601.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn2);
93611.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn3);
93621.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn4);
93631.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn5);
93641.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn6);
93651.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn7);
93661.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn8);
93671.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn9);
93681.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn10);
93691.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn11);
93701.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn12);
93711.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn13);
93721.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn14);
93731.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn15);
93741.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn16);
93751.149Skamil
93761.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_detach_spawner);
93771.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_detach_forker);
93781.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_detach_vforker);
93791.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_detach_vforkerdone);
93801.126Skamil
93811.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_kill_spawner);
93821.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_kill_forker);
93831.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_kill_vforker);
93841.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_kill_vforkerdone);
93851.116Skamil
93861.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn_detach_spawner);
93871.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork_detach_forker);
93881.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork_detach_vforker);
93891.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork_detach_vforkerdone);
93901.150Skamil
93911.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn_kill_spawner);
93921.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork_kill_forker);
93931.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork_kill_vforker);
93941.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork_kill_vforkerdone);
93951.150Skamil
93961.108Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_fork);
93971.108Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_vfork);
93981.108Skamil
93991.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8);
94001.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16);
94011.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32);
94021.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64);
94031.54Skamil
94041.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8);
94051.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16);
94061.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32);
94071.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64);
94081.54Skamil
94091.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8);
94101.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16);
94111.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32);
94121.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64);
94131.54Skamil
94141.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8);
94151.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16);
94161.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32);
94171.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64);
94181.54Skamil
94191.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d);
94201.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i);
94211.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d);
94221.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i);
94231.54Skamil
94241.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8_text);
94251.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16_text);
94261.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32_text);
94271.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64_text);
94281.54Skamil
94291.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8_text);
94301.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16_text);
94311.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32_text);
94321.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64_text);
94331.54Skamil
94341.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8_text);
94351.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16_text);
94361.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32_text);
94371.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64_text);
94381.54Skamil
94391.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8_text);
94401.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16_text);
94411.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32_text);
94421.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64_text);
94431.54Skamil
94441.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d_text);
94451.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i_text);
94461.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d_text);
94471.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i_text);
94481.1Skamil
94491.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_auxv);
94501.1Skamil
94511.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_i);
94521.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_d);
94531.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_i);
94541.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_d);
94551.101Skamil
94561.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_i);
94571.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_d);
94581.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_i);
94591.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_d);
94601.101Skamil
94611.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_auxv);
94621.101Skamil
94631.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_i);
94641.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_d);
94651.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_i);
94661.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_d);
94671.115Skamil
94681.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_i);
94691.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_d);
94701.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_i);
94711.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_d);
94721.115Skamil
94731.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs1);
94741.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs2);
94751.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs3);
94761.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs4);
94771.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs5);
94781.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs6);
94791.1Skamil
94801.148Smartin	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs_set_unaligned_pc_0x1);
94811.148Smartin	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs_set_unaligned_pc_0x3);
94821.148Smartin	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs_set_unaligned_pc_0x7);
94831.147Skamil
94841.72Skamil	ATF_TP_ADD_TC_HAVE_FPREGS(tp, access_fpregs1);
94851.72Skamil	ATF_TP_ADD_TC_HAVE_FPREGS(tp, access_fpregs2);
94861.1Skamil
94871.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step1);
94881.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step2);
94891.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step3);
94901.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step4);
94911.1Skamil
94921.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep1);
94931.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep2);
94941.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep3);
94951.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep4);
94961.2Skamil
94971.95Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step_signalmasked);
94981.95Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step_signalignored);
94991.95Skamil
95001.1Skamil	ATF_TP_ADD_TC(tp, kill1);
95011.1Skamil	ATF_TP_ADD_TC(tp, kill2);
95021.75Skamil	ATF_TP_ADD_TC(tp, kill3);
95031.1Skamil
95041.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0);
95051.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1);
95061.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2);
95071.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3);
95081.77Skamil
95091.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus);
95101.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus);
95111.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus);
95121.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus);
95131.143Skamil
95141.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_sigmask);
95151.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_sigmask);
95161.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_sigmask);
95171.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_sigmask);
95181.143Skamil
95191.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_name);
95201.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_name);
95211.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_name);
95221.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_name);
95231.143Skamil
95241.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_private);
95251.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_private);
95261.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_private);
95271.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_private);
95281.143Skamil
95291.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0);
95301.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1);
95311.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2);
95321.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3);
95331.143Skamil
95341.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_sigmask);
95351.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_sigmask);
95361.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_sigmask);
95371.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_sigmask);
95381.143Skamil
95391.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_name);
95401.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_name);
95411.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_name);
95421.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_name);
95431.143Skamil
95441.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_private);
95451.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_private);
95461.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_private);
95471.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_private);
95481.143Skamil
95491.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo0);
95501.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo1);
95511.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo2);
95521.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo3);
95531.1Skamil
95541.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_unmodified);
95551.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_faked);
95561.79Skamil
95571.82Skamil	ATF_TP_ADD_TC(tp, traceme_exec);
95581.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_exec);
95591.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_exec);
95601.1Skamil
95611.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_nolwpevents);
95621.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit);
95631.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate);
95641.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit);
95651.1Skamil
95661.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit_masked_sigtrap);
95671.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_masked_sigtrap);
95681.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit_masked_sigtrap);
95691.153Skamil
95701.84Skamil	ATF_TP_ADD_TC(tp, signal_mask_unrelated);
95711.84Skamil
95721.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_singalmasked);
95731.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_singalignored);
95741.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_singalmasked);
95751.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_singalignored);
95761.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_singalmasked);
95771.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_singalignored);
95781.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vforkdone_singalmasked);
95791.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vforkdone_singalignored);
95801.99Skamil
95811.151Skamil	ATF_TP_ADD_TC(tp, threads_and_exec);
95821.151Skamil
95831.154Skamil	ATF_TP_ADD_TC(tp, suspend_no_deadlock);
95841.1Skamil
95851.155Skamil	ATF_TP_ADD_TC(tp, resume);
95861.1Skamil
95871.166Skamil	ATF_TP_ADD_TC(tp, syscall);
95881.166Skamil	ATF_TP_ADD_TC(tp, syscall_killed_on_sce);
95891.167Skamil	ATF_TP_ADD_TC(tp, syscall_signal_on_sce);
95901.167Skamil	ATF_TP_ADD_TC(tp, syscall_detach_on_sce);
95911.1Skamil
95921.1Skamil	ATF_TP_ADD_TC(tp, syscallemu1);
95931.1Skamil
95941.106Skamil	ATF_TP_ADD_TC(tp, clone1);
95951.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone2);
95961.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone3);
95971.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone4);
95981.106Skamil	ATF_TP_ADD_TC(tp, clone5);
95991.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone6);
96001.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone7);
96011.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone8);
96021.106Skamil
96031.106Skamil	ATF_TP_ADD_TC(tp, clone_vm1);
96041.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm2);
96051.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm3);
96061.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm4);
96071.106Skamil	ATF_TP_ADD_TC(tp, clone_vm5);
96081.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm6);
96091.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm7);
96101.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm8);
96111.106Skamil
96121.106Skamil	ATF_TP_ADD_TC(tp, clone_fs1);
96131.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs2);
96141.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs3);
96151.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs4);
96161.106Skamil	ATF_TP_ADD_TC(tp, clone_fs5);
96171.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs6);
96181.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs7);
96191.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs8);
96201.106Skamil
96211.106Skamil	ATF_TP_ADD_TC(tp, clone_files1);
96221.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files2);
96231.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files3);
96241.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files4);
96251.106Skamil	ATF_TP_ADD_TC(tp, clone_files5);
96261.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files6);
96271.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files7);
96281.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files8);
96291.106Skamil
96301.106Skamil//	ATF_TP_ADD_TC(tp, clone_sighand1); // XXX
96311.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand2); // XXX
96321.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand3); // XXX
96331.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand4); // XXX
96341.106Skamil//	ATF_TP_ADD_TC(tp, clone_sighand5); // XXX
96351.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand6); // XXX
96361.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand7); // XXX
96371.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand8); // XXX
96381.106Skamil
96391.106Skamil	ATF_TP_ADD_TC(tp, clone_vfork1);
96401.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork2);
96411.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork3);
96421.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork4);
96431.106Skamil	ATF_TP_ADD_TC(tp, clone_vfork5);
96441.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork6);
96451.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork7);
96461.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork8);
96471.106Skamil
96481.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_signalignored);
96491.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_signalmasked);
96501.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm_signalignored);
96511.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm_signalmasked);
96521.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs_signalignored);
96531.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs_signalmasked);
96541.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files_signalignored);
96551.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files_signalmasked);
96561.103Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand_signalignored); // XXX
96571.103Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand_signalmasked); // XXX
96581.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork_signalignored);
96591.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork_signalmasked);
96601.103Skamil
96611.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone);
96621.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_vm);
96631.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_fs);
96641.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_files);
96651.107Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_sighand); // XXX
96661.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_vfork);
96671.107Skamil
96681.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_continue);
96691.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall);
96701.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach);
96711.122Skamil
96721.130Smgorny	ATF_TP_ADD_TC(tp, core_dump_procinfo);
96731.130Smgorny
96741.138Smgorny#if defined(TWAIT_HAVE_STATUS)
96751.138Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals);
96761.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_sig_ign);
96771.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_handler);
96781.160Smgorny#if defined(__i386__) || defined(__x86_64__)
96791.160Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_breakpoints);
96801.161Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_watchpoints);
96811.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp);
96821.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig);
96831.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_sig_ign);
96841.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_handler);
96851.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig);
96861.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_sig_ign);
96871.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_handler);
96881.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig);
96891.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_sig_ign);
96901.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_handler);
96911.160Smgorny#endif
96921.138Smgorny#endif
96931.138Smgorny
96941.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
96951.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_I386();
96961.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_X86();
96971.1Skamil
96981.165Skamil#else
96991.165Skamil	ATF_TP_ADD_TC(tp, dummy);
97001.165Skamil#endif
97011.165Skamil
97021.1Skamil	return atf_no_error();
97031.1Skamil}
9704