t_ptrace_wait.c revision 1.147
11.147Skamil/*	$NetBSD: t_ptrace_wait.c,v 1.147 2020/01/21 16:46:07 kamil Exp $	*/
21.1Skamil
31.1Skamil/*-
41.78Skamil * Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc.
51.1Skamil * All rights reserved.
61.1Skamil *
71.1Skamil * Redistribution and use in source and binary forms, with or without
81.1Skamil * modification, are permitted provided that the following conditions
91.1Skamil * are met:
101.1Skamil * 1. Redistributions of source code must retain the above copyright
111.1Skamil *    notice, this list of conditions and the following disclaimer.
121.1Skamil * 2. Redistributions in binary form must reproduce the above copyright
131.1Skamil *    notice, this list of conditions and the following disclaimer in the
141.1Skamil *    documentation and/or other materials provided with the distribution.
151.1Skamil *
161.1Skamil * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
171.1Skamil * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
181.1Skamil * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
191.1Skamil * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
201.1Skamil * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
211.1Skamil * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
221.1Skamil * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
231.1Skamil * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
241.1Skamil * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
251.1Skamil * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
261.1Skamil * POSSIBILITY OF SUCH DAMAGE.
271.1Skamil */
281.1Skamil
291.1Skamil#include <sys/cdefs.h>
301.147Skamil__RCSID("$NetBSD: t_ptrace_wait.c,v 1.147 2020/01/21 16:46:07 kamil Exp $");
311.143Skamil
321.143Skamil#define __LEGACY_PT_LWPINFO
331.1Skamil
341.1Skamil#include <sys/param.h>
351.1Skamil#include <sys/types.h>
361.130Smgorny#include <sys/exec_elf.h>
371.39Skamil#include <sys/mman.h>
381.1Skamil#include <sys/ptrace.h>
391.1Skamil#include <sys/resource.h>
401.1Skamil#include <sys/stat.h>
411.1Skamil#include <sys/syscall.h>
421.1Skamil#include <sys/sysctl.h>
431.129Smgorny#include <sys/uio.h>
441.1Skamil#include <sys/wait.h>
451.1Skamil#include <machine/reg.h>
461.132Skamil#include <assert.h>
471.1Skamil#include <elf.h>
481.1Skamil#include <err.h>
491.1Skamil#include <errno.h>
501.130Smgorny#include <fcntl.h>
511.1Skamil#include <lwp.h>
521.77Skamil#include <pthread.h>
531.1Skamil#include <sched.h>
541.1Skamil#include <signal.h>
551.124Skamil#include <spawn.h>
561.1Skamil#include <stdint.h>
571.1Skamil#include <stdio.h>
581.1Skamil#include <stdlib.h>
591.1Skamil#include <strings.h>
601.26Skamil#include <time.h>
611.1Skamil#include <unistd.h>
621.1Skamil
631.114Skamil#include <fenv.h>
641.114Skamil#if (__arm__ && !__SOFTFP__) || __aarch64__
651.114Skamil#include <ieeefp.h> /* only need for ARM Cortex/Neon hack */
661.114Skamil#endif
671.114Skamil
681.121Smgorny#if defined(__i386__) || defined(__x86_64__)
691.121Smgorny#include <cpuid.h>
701.121Smgorny#include <x86/cpu_extended_state.h>
711.129Smgorny#include <x86/specialreg.h>
721.121Smgorny#endif
731.121Smgorny
741.130Smgorny#include <libelf.h>
751.130Smgorny#include <gelf.h>
761.130Smgorny
771.1Skamil#include <atf-c.h>
781.1Skamil
791.132Skamil/* Assumptions in the kernel code that must be kept. */
801.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_report_event) ==
811.132Skamil    sizeof(((siginfo_t *)0)->si_pe_report_event),
821.132Skamil    "pe_report_event and si_pe_report_event must be of the same size");
831.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_other_pid) ==
841.132Skamil    sizeof(((siginfo_t *)0)->si_pe_other_pid),
851.132Skamil    "pe_other_pid and si_pe_other_pid must be of the same size");
861.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_lwp) ==
871.132Skamil    sizeof(((siginfo_t *)0)->si_pe_lwp),
881.132Skamil    "pe_lwp and si_pe_lwp must be of the same size");
891.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_other_pid) ==
901.132Skamil    sizeof(((struct ptrace_state *)0)->pe_lwp),
911.132Skamil    "pe_other_pid and pe_lwp must be of the same size");
921.132Skamil
931.1Skamil#include "h_macros.h"
941.1Skamil
951.1Skamil#include "t_ptrace_wait.h"
961.1Skamil#include "msg.h"
971.1Skamil
981.1Skamil#define PARENT_TO_CHILD(info, fds, msg) \
991.61Skre    SYSCALL_REQUIRE(msg_write_child(info " to child " # fds, &fds, &msg, \
1001.61Skre	sizeof(msg)) == 0)
1011.1Skamil
1021.1Skamil#define CHILD_FROM_PARENT(info, fds, msg) \
1031.61Skre    FORKEE_ASSERT(msg_read_parent(info " from parent " # fds, &fds, &msg, \
1041.61Skre	sizeof(msg)) == 0)
1051.1Skamil
1061.1Skamil#define CHILD_TO_PARENT(info, fds, msg) \
1071.61Skre    FORKEE_ASSERT(msg_write_parent(info " to parent " # fds, &fds, &msg, \
1081.61Skre	sizeof(msg)) == 0)
1091.1Skamil
1101.1Skamil#define PARENT_FROM_CHILD(info, fds, msg) \
1111.61Skre    SYSCALL_REQUIRE(msg_read_child(info " from parent " # fds, &fds, &msg, \
1121.61Skre	sizeof(msg)) == 0)
1131.13Schristos
1141.13Schristos#define SYSCALL_REQUIRE(expr) ATF_REQUIRE_MSG(expr, "%s: %s", # expr, \
1151.13Schristos    strerror(errno))
1161.18Schristos#define SYSCALL_REQUIRE_ERRNO(res, exp) ATF_REQUIRE_MSG(res == exp, \
1171.18Schristos    "%d(%s) != %d", res, strerror(res), exp)
1181.13Schristos
1191.13Schristosstatic int debug = 0;
1201.13Schristos
1211.13Schristos#define DPRINTF(a, ...)	do  \
1221.123Skamil	if (debug) \
1231.142Skamil	printf("%s() %d.%d %s:%d " a, \
1241.142Skamil	__func__, getpid(), _lwp_self(), __FILE__, __LINE__,  ##__VA_ARGS__); \
1251.13Schristos    while (/*CONSTCOND*/0)
1261.1Skamil
1271.34Skamil/// ----------------------------------------------------------------------------
1281.34Skamil
1291.33Skamilstatic void
1301.33Skamiltraceme_raise(int sigval)
1311.1Skamil{
1321.1Skamil	const int exitval = 5;
1331.1Skamil	pid_t child, wpid;
1341.1Skamil#if defined(TWAIT_HAVE_STATUS)
1351.1Skamil	int status;
1361.1Skamil#endif
1371.1Skamil
1381.133Skamil	ptrace_state_t state, zero_state;
1391.133Skamil	const int slen = sizeof(state);
1401.45Skamil	struct ptrace_siginfo info;
1411.133Skamil	memset(&zero_state, 0, sizeof(zero_state));
1421.45Skamil	memset(&info, 0, sizeof(info));
1431.45Skamil
1441.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
1451.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
1461.1Skamil	if (child == 0) {
1471.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1481.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
1491.1Skamil
1501.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
1511.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
1521.1Skamil
1531.36Skamil		switch (sigval) {
1541.36Skamil		case SIGKILL:
1551.36Skamil			/* NOTREACHED */
1561.36Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
1571.70Smrg			__unreachable();
1581.36Skamil		default:
1591.36Skamil			DPRINTF("Before exiting of the child process\n");
1601.36Skamil			_exit(exitval);
1611.36Skamil		}
1621.1Skamil	}
1631.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
1641.1Skamil
1651.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1661.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
1671.1Skamil
1681.36Skamil	switch (sigval) {
1691.36Skamil	case SIGKILL:
1701.36Skamil		validate_status_signaled(status, sigval, 0);
1711.133Skamil		SYSCALL_REQUIRE(
1721.133Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) == -1);
1731.133Skamil
1741.36Skamil		break;
1751.36Skamil	default:
1761.36Skamil		validate_status_stopped(status, sigval);
1771.1Skamil
1781.45Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
1791.61Skre			"child\n");
1801.45Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
1811.61Skre			sizeof(info)) != -1);
1821.45Skamil
1831.45Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
1841.45Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
1851.61Skre			"si_errno=%#x\n",
1861.61Skre			info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
1871.61Skre			info.psi_siginfo.si_errno);
1881.45Skamil
1891.45Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
1901.45Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
1911.45Skamil
1921.133Skamil		DPRINTF("Assert that PT_GET_PROCESS_STATE returns non-error");
1931.133Skamil		SYSCALL_REQUIRE(
1941.133Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
1951.133Skamil		ATF_REQUIRE(memcmp(&state, &zero_state, slen) == 0);
1961.133Skamil
1971.36Skamil		DPRINTF("Before resuming the child process where it left off "
1981.36Skamil		    "and without signal to be sent\n");
1991.36Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
2001.1Skamil
2011.36Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2021.36Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
2031.61Skre		    child);
2041.36Skamil		break;
2051.36Skamil	}
2061.1Skamil
2071.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2081.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
2091.1Skamil}
2101.1Skamil
2111.61Skre#define TRACEME_RAISE(test, sig)					\
2121.61SkreATF_TC(test);								\
2131.61SkreATF_TC_HEAD(test, tc)							\
2141.61Skre{									\
2151.61Skre	atf_tc_set_md_var(tc, "descr",					\
2161.61Skre	    "Verify " #sig " followed by _exit(2) in a child");		\
2171.61Skre}									\
2181.61Skre									\
2191.61SkreATF_TC_BODY(test, tc)							\
2201.61Skre{									\
2211.61Skre									\
2221.61Skre	traceme_raise(sig);						\
2231.33Skamil}
2241.33Skamil
2251.36SkamilTRACEME_RAISE(traceme_raise1, SIGKILL) /* non-maskable */
2261.33SkamilTRACEME_RAISE(traceme_raise2, SIGSTOP) /* non-maskable */
2271.33SkamilTRACEME_RAISE(traceme_raise3, SIGABRT) /* regular abort trap */
2281.33SkamilTRACEME_RAISE(traceme_raise4, SIGHUP)  /* hangup */
2291.33SkamilTRACEME_RAISE(traceme_raise5, SIGCONT) /* continued? */
2301.85SkamilTRACEME_RAISE(traceme_raise6, SIGTRAP) /* crash signal */
2311.85SkamilTRACEME_RAISE(traceme_raise7, SIGBUS) /* crash signal */
2321.85SkamilTRACEME_RAISE(traceme_raise8, SIGILL) /* crash signal */
2331.85SkamilTRACEME_RAISE(traceme_raise9, SIGFPE) /* crash signal */
2341.85SkamilTRACEME_RAISE(traceme_raise10, SIGSEGV) /* crash signal */
2351.33Skamil
2361.34Skamil/// ----------------------------------------------------------------------------
2371.1Skamil
2381.1Skamilstatic void
2391.87Skamiltraceme_raisesignal_ignored(int sigignored)
2401.87Skamil{
2411.87Skamil	const int exitval = 5;
2421.87Skamil	const int sigval = SIGSTOP;
2431.87Skamil	pid_t child, wpid;
2441.87Skamil	struct sigaction sa;
2451.87Skamil#if defined(TWAIT_HAVE_STATUS)
2461.87Skamil	int status;
2471.87Skamil#endif
2481.87Skamil	struct ptrace_siginfo info;
2491.87Skamil
2501.87Skamil	memset(&info, 0, sizeof(info));
2511.87Skamil
2521.87Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
2531.87Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
2541.87Skamil	if (child == 0) {
2551.87Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
2561.87Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
2571.87Skamil
2581.87Skamil		memset(&sa, 0, sizeof(sa));
2591.87Skamil		sa.sa_handler = SIG_IGN;
2601.87Skamil		sigemptyset(&sa.sa_mask);
2611.87Skamil		FORKEE_ASSERT(sigaction(sigignored, &sa, NULL) != -1);
2621.87Skamil
2631.87Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
2641.87Skamil		FORKEE_ASSERT(raise(sigval) == 0);
2651.87Skamil
2661.87Skamil		DPRINTF("Before raising %s from child\n",
2671.87Skamil		    strsignal(sigignored));
2681.87Skamil		FORKEE_ASSERT(raise(sigignored) == 0);
2691.87Skamil
2701.87Skamil		DPRINTF("Before exiting of the child process\n");
2711.87Skamil		_exit(exitval);
2721.87Skamil	}
2731.87Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
2741.87Skamil
2751.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2761.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2771.87Skamil
2781.87Skamil	validate_status_stopped(status, sigval);
2791.87Skamil
2801.87Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
2811.87Skamil	SYSCALL_REQUIRE(
2821.87Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
2831.87Skamil
2841.87Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
2851.87Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
2861.87Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
2871.87Skamil	    info.psi_siginfo.si_errno);
2881.87Skamil
2891.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
2901.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
2911.87Skamil
2921.87Skamil	DPRINTF("Before resuming the child process where it left off and "
2931.87Skamil	    "without signal to be sent\n");
2941.87Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
2951.87Skamil
2961.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2971.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2981.87Skamil
2991.87Skamil	validate_status_stopped(status, sigignored);
3001.87Skamil
3011.87Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
3021.87Skamil	SYSCALL_REQUIRE(
3031.87Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
3041.87Skamil
3051.87Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
3061.87Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
3071.87Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
3081.87Skamil	    info.psi_siginfo.si_errno);
3091.87Skamil
3101.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigignored);
3111.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
3121.87Skamil
3131.87Skamil	DPRINTF("Before resuming the child process where it left off and "
3141.87Skamil	    "without signal to be sent\n");
3151.87Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
3161.87Skamil
3171.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3181.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
3191.87Skamil
3201.87Skamil	validate_status_exited(status, exitval);
3211.87Skamil
3221.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3231.87Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
3241.87Skamil}
3251.87Skamil
3261.87Skamil#define TRACEME_RAISESIGNAL_IGNORED(test, sig)				\
3271.87SkamilATF_TC(test);								\
3281.87SkamilATF_TC_HEAD(test, tc)							\
3291.87Skamil{									\
3301.87Skamil	atf_tc_set_md_var(tc, "descr",					\
3311.87Skamil	    "Verify that ignoring (with SIG_IGN) " #sig " in tracee "	\
3321.87Skamil	    "does not stop tracer from catching this raised signal");	\
3331.87Skamil}									\
3341.87Skamil									\
3351.87SkamilATF_TC_BODY(test, tc)							\
3361.87Skamil{									\
3371.87Skamil									\
3381.87Skamil	traceme_raisesignal_ignored(sig);				\
3391.87Skamil}
3401.87Skamil
3411.87Skamil// A signal handler for SIGKILL and SIGSTOP cannot be ignored.
3421.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored1, SIGABRT) /* abort */
3431.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored2, SIGHUP)  /* hangup */
3441.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored3, SIGCONT) /* cont. */
3451.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored4, SIGTRAP) /* crash */
3461.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored5, SIGBUS) /* crash */
3471.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored6, SIGILL) /* crash */
3481.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored7, SIGFPE) /* crash */
3491.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored8, SIGSEGV) /* crash */
3501.87Skamil
3511.87Skamil/// ----------------------------------------------------------------------------
3521.87Skamil
3531.87Skamilstatic void
3541.86Skamiltraceme_raisesignal_masked(int sigmasked)
3551.86Skamil{
3561.86Skamil	const int exitval = 5;
3571.86Skamil	const int sigval = SIGSTOP;
3581.86Skamil	pid_t child, wpid;
3591.86Skamil#if defined(TWAIT_HAVE_STATUS)
3601.86Skamil	int status;
3611.86Skamil#endif
3621.86Skamil	sigset_t intmask;
3631.86Skamil	struct ptrace_siginfo info;
3641.86Skamil
3651.86Skamil	memset(&info, 0, sizeof(info));
3661.86Skamil
3671.86Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
3681.86Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
3691.86Skamil	if (child == 0) {
3701.86Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
3711.86Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
3721.86Skamil
3731.86Skamil		sigemptyset(&intmask);
3741.86Skamil		sigaddset(&intmask, sigmasked);
3751.86Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
3761.86Skamil
3771.86Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
3781.86Skamil		FORKEE_ASSERT(raise(sigval) == 0);
3791.86Skamil
3801.86Skamil		DPRINTF("Before raising %s breakpoint from child\n",
3811.86Skamil		    strsignal(sigmasked));
3821.86Skamil		FORKEE_ASSERT(raise(sigmasked) == 0);
3831.86Skamil
3841.86Skamil		DPRINTF("Before exiting of the child process\n");
3851.86Skamil		_exit(exitval);
3861.86Skamil	}
3871.86Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
3881.86Skamil
3891.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3901.86Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
3911.86Skamil
3921.86Skamil	validate_status_stopped(status, sigval);
3931.86Skamil
3941.86Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
3951.86Skamil	SYSCALL_REQUIRE(
3961.86Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
3971.86Skamil
3981.86Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
3991.86Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
4001.86Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
4011.86Skamil	    info.psi_siginfo.si_errno);
4021.86Skamil
4031.86Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
4041.86Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
4051.86Skamil
4061.86Skamil	DPRINTF("Before resuming the child process where it left off and "
4071.86Skamil	    "without signal to be sent\n");
4081.86Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
4091.86Skamil
4101.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
4111.86Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
4121.86Skamil
4131.86Skamil	validate_status_exited(status, exitval);
4141.86Skamil
4151.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
4161.86Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
4171.86Skamil}
4181.86Skamil
4191.86Skamil#define TRACEME_RAISESIGNAL_MASKED(test, sig)				\
4201.86SkamilATF_TC(test);								\
4211.86SkamilATF_TC_HEAD(test, tc)							\
4221.86Skamil{									\
4231.86Skamil	atf_tc_set_md_var(tc, "descr",					\
4241.86Skamil	    "Verify that masking (with SIG_BLOCK) " #sig " in tracee "	\
4251.86Skamil	    "stops tracer from catching this raised signal");		\
4261.86Skamil}									\
4271.86Skamil									\
4281.86SkamilATF_TC_BODY(test, tc)							\
4291.86Skamil{									\
4301.86Skamil									\
4311.86Skamil	traceme_raisesignal_masked(sig);				\
4321.86Skamil}
4331.86Skamil
4341.86Skamil// A signal handler for SIGKILL and SIGSTOP cannot be masked.
4351.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked1, SIGABRT) /* abort trap */
4361.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked2, SIGHUP)  /* hangup */
4371.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked3, SIGCONT) /* continued? */
4381.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked4, SIGTRAP) /* crash sig. */
4391.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked5, SIGBUS) /* crash sig. */
4401.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked6, SIGILL) /* crash sig. */
4411.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked7, SIGFPE) /* crash sig. */
4421.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked8, SIGSEGV) /* crash sig. */
4431.86Skamil
4441.86Skamil/// ----------------------------------------------------------------------------
4451.86Skamil
4461.86Skamilstatic void
4471.59Skamiltraceme_crash(int sig)
4481.59Skamil{
4491.59Skamil	pid_t child, wpid;
4501.59Skamil#if defined(TWAIT_HAVE_STATUS)
4511.59Skamil	int status;
4521.59Skamil#endif
4531.59Skamil	struct ptrace_siginfo info;
4541.61Skre
4551.71Skamil#ifndef PTRACE_ILLEGAL_ASM
4561.71Skamil	if (sig == SIGILL)
4571.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
4581.71Skamil#endif
4591.71Skamil
4601.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
4611.114Skamil		atf_tc_skip("FP exceptions are not supported");
4621.114Skamil
4631.59Skamil	memset(&info, 0, sizeof(info));
4641.59Skamil
4651.59Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
4661.59Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
4671.59Skamil	if (child == 0) {
4681.59Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
4691.59Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
4701.59Skamil
4711.59Skamil		DPRINTF("Before executing a trap\n");
4721.59Skamil		switch (sig) {
4731.59Skamil		case SIGTRAP:
4741.59Skamil			trigger_trap();
4751.59Skamil			break;
4761.59Skamil		case SIGSEGV:
4771.59Skamil			trigger_segv();
4781.59Skamil			break;
4791.59Skamil		case SIGILL:
4801.59Skamil			trigger_ill();
4811.59Skamil			break;
4821.59Skamil		case SIGFPE:
4831.59Skamil			trigger_fpe();
4841.59Skamil			break;
4851.59Skamil		case SIGBUS:
4861.59Skamil			trigger_bus();
4871.59Skamil			break;
4881.59Skamil		default:
4891.59Skamil			/* NOTREACHED */
4901.59Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
4911.59Skamil		}
4921.59Skamil
4931.59Skamil		/* NOTREACHED */
4941.59Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
4951.59Skamil	}
4961.59Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
4971.59Skamil
4981.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
4991.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
5001.59Skamil
5011.59Skamil	validate_status_stopped(status, sig);
5021.59Skamil
5031.59Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
5041.61Skre	SYSCALL_REQUIRE(
5051.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
5061.59Skamil
5071.59Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
5081.59Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
5091.61Skre	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
5101.61Skre	    info.psi_siginfo.si_errno);
5111.59Skamil
5121.59Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
5131.59Skamil	switch (sig) {
5141.59Skamil	case SIGTRAP:
5151.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
5161.59Skamil		break;
5171.59Skamil	case SIGSEGV:
5181.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
5191.59Skamil		break;
5201.71Skamil	case SIGILL:
5211.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
5221.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
5231.71Skamil		break;
5241.59Skamil	case SIGFPE:
5251.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
5261.59Skamil		break;
5271.59Skamil	case SIGBUS:
5281.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
5291.59Skamil		break;
5301.59Skamil	}
5311.59Skamil
5321.59Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
5331.59Skamil
5341.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5351.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
5361.59Skamil
5371.59Skamil	validate_status_signaled(status, SIGKILL, 0);
5381.59Skamil
5391.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5401.59Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
5411.59Skamil}
5421.59Skamil
5431.61Skre#define TRACEME_CRASH(test, sig)					\
5441.61SkreATF_TC(test);								\
5451.61SkreATF_TC_HEAD(test, tc)							\
5461.61Skre{									\
5471.61Skre	atf_tc_set_md_var(tc, "descr",					\
5481.61Skre	    "Verify crash signal " #sig " in a child after PT_TRACE_ME"); \
5491.61Skre}									\
5501.61Skre									\
5511.61SkreATF_TC_BODY(test, tc)							\
5521.61Skre{									\
5531.61Skre									\
5541.61Skre	traceme_crash(sig);						\
5551.59Skamil}
5561.59Skamil
5571.59SkamilTRACEME_CRASH(traceme_crash_trap, SIGTRAP)
5581.59SkamilTRACEME_CRASH(traceme_crash_segv, SIGSEGV)
5591.71SkamilTRACEME_CRASH(traceme_crash_ill, SIGILL)
5601.59SkamilTRACEME_CRASH(traceme_crash_fpe, SIGFPE)
5611.59SkamilTRACEME_CRASH(traceme_crash_bus, SIGBUS)
5621.59Skamil
5631.59Skamil/// ----------------------------------------------------------------------------
5641.59Skamil
5651.59Skamilstatic void
5661.88Skamiltraceme_signalmasked_crash(int sig)
5671.88Skamil{
5681.89Skamil	const int sigval = SIGSTOP;
5691.88Skamil	pid_t child, wpid;
5701.88Skamil#if defined(TWAIT_HAVE_STATUS)
5711.88Skamil	int status;
5721.88Skamil#endif
5731.88Skamil	struct ptrace_siginfo info;
5741.88Skamil	sigset_t intmask;
5751.89Skamil	struct kinfo_proc2 kp;
5761.89Skamil	size_t len = sizeof(kp);
5771.89Skamil
5781.89Skamil	int name[6];
5791.89Skamil	const size_t namelen = __arraycount(name);
5801.89Skamil	ki_sigset_t kp_sigmask;
5811.88Skamil
5821.88Skamil#ifndef PTRACE_ILLEGAL_ASM
5831.88Skamil	if (sig == SIGILL)
5841.88Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
5851.88Skamil#endif
5861.88Skamil
5871.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
5881.114Skamil		atf_tc_skip("FP exceptions are not supported");
5891.114Skamil
5901.88Skamil	memset(&info, 0, sizeof(info));
5911.88Skamil
5921.88Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
5931.88Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
5941.88Skamil	if (child == 0) {
5951.88Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
5961.88Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
5971.88Skamil
5981.88Skamil		sigemptyset(&intmask);
5991.88Skamil		sigaddset(&intmask, sig);
6001.88Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
6011.88Skamil
6021.89Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
6031.89Skamil		FORKEE_ASSERT(raise(sigval) == 0);
6041.89Skamil
6051.88Skamil		DPRINTF("Before executing a trap\n");
6061.88Skamil		switch (sig) {
6071.88Skamil		case SIGTRAP:
6081.88Skamil			trigger_trap();
6091.88Skamil			break;
6101.88Skamil		case SIGSEGV:
6111.88Skamil			trigger_segv();
6121.88Skamil			break;
6131.88Skamil		case SIGILL:
6141.88Skamil			trigger_ill();
6151.88Skamil			break;
6161.88Skamil		case SIGFPE:
6171.88Skamil			trigger_fpe();
6181.88Skamil			break;
6191.88Skamil		case SIGBUS:
6201.88Skamil			trigger_bus();
6211.88Skamil			break;
6221.88Skamil		default:
6231.88Skamil			/* NOTREACHED */
6241.88Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
6251.88Skamil		}
6261.88Skamil
6271.88Skamil		/* NOTREACHED */
6281.88Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
6291.88Skamil	}
6301.88Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
6311.88Skamil
6321.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6331.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
6341.88Skamil
6351.89Skamil	validate_status_stopped(status, sigval);
6361.89Skamil
6371.89Skamil	name[0] = CTL_KERN,
6381.89Skamil	name[1] = KERN_PROC2,
6391.89Skamil	name[2] = KERN_PROC_PID;
6401.89Skamil	name[3] = child;
6411.89Skamil	name[4] = sizeof(kp);
6421.89Skamil	name[5] = 1;
6431.89Skamil
6441.89Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
6451.89Skamil
6461.89Skamil	kp_sigmask = kp.p_sigmask;
6471.89Skamil
6481.89Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
6491.89Skamil	SYSCALL_REQUIRE(
6501.89Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
6511.89Skamil
6521.89Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
6531.89Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
6541.89Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
6551.89Skamil	    info.psi_siginfo.si_errno);
6561.89Skamil
6571.89Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
6581.89Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
6591.89Skamil
6601.89Skamil	DPRINTF("Before resuming the child process where it left off and "
6611.89Skamil	    "without signal to be sent\n");
6621.89Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
6631.89Skamil
6641.89Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6651.89Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
6661.89Skamil
6671.88Skamil	validate_status_stopped(status, sig);
6681.88Skamil
6691.88Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
6701.88Skamil	SYSCALL_REQUIRE(
6711.88Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
6721.88Skamil
6731.88Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
6741.88Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
6751.88Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
6761.88Skamil	    info.psi_siginfo.si_errno);
6771.88Skamil
6781.89Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
6791.89Skamil
6801.89Skamil	DPRINTF("kp_sigmask="
6811.89Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
6821.89Skamil	    kp_sigmask.__bits[0], kp_sigmask.__bits[1], kp_sigmask.__bits[2],
6831.89Skamil	    kp_sigmask.__bits[3]);
6841.89Skamil
6851.89Skamil	DPRINTF("kp.p_sigmask="
6861.89Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
6871.89Skamil	    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
6881.89Skamil	    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
6891.89Skamil
6901.89Skamil	ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask, sizeof(kp_sigmask)));
6911.89Skamil
6921.88Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
6931.88Skamil	switch (sig) {
6941.88Skamil	case SIGTRAP:
6951.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
6961.88Skamil		break;
6971.88Skamil	case SIGSEGV:
6981.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
6991.88Skamil		break;
7001.88Skamil	case SIGILL:
7011.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
7021.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
7031.88Skamil		break;
7041.88Skamil	case SIGFPE:
7051.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
7061.88Skamil		break;
7071.88Skamil	case SIGBUS:
7081.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
7091.88Skamil		break;
7101.88Skamil	}
7111.88Skamil
7121.88Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
7131.88Skamil
7141.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
7151.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
7161.88Skamil
7171.88Skamil	validate_status_signaled(status, SIGKILL, 0);
7181.88Skamil
7191.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
7201.88Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
7211.88Skamil}
7221.88Skamil
7231.88Skamil#define TRACEME_SIGNALMASKED_CRASH(test, sig)				\
7241.88SkamilATF_TC(test);								\
7251.88SkamilATF_TC_HEAD(test, tc)							\
7261.88Skamil{									\
7271.88Skamil	atf_tc_set_md_var(tc, "descr",					\
7281.88Skamil	    "Verify masked crash signal " #sig " in a child after "	\
7291.88Skamil	    "PT_TRACE_ME is delivered to its tracer");			\
7301.88Skamil}									\
7311.88Skamil									\
7321.88SkamilATF_TC_BODY(test, tc)							\
7331.88Skamil{									\
7341.88Skamil									\
7351.88Skamil	traceme_signalmasked_crash(sig);				\
7361.88Skamil}
7371.88Skamil
7381.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_trap, SIGTRAP)
7391.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_segv, SIGSEGV)
7401.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_ill, SIGILL)
7411.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_fpe, SIGFPE)
7421.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_bus, SIGBUS)
7431.88Skamil
7441.88Skamil/// ----------------------------------------------------------------------------
7451.88Skamil
7461.88Skamilstatic void
7471.88Skamiltraceme_signalignored_crash(int sig)
7481.88Skamil{
7491.90Skamil	const int sigval = SIGSTOP;
7501.88Skamil	pid_t child, wpid;
7511.88Skamil#if defined(TWAIT_HAVE_STATUS)
7521.88Skamil	int status;
7531.88Skamil#endif
7541.88Skamil	struct sigaction sa;
7551.88Skamil	struct ptrace_siginfo info;
7561.90Skamil	struct kinfo_proc2 kp;
7571.90Skamil	size_t len = sizeof(kp);
7581.90Skamil
7591.90Skamil	int name[6];
7601.90Skamil	const size_t namelen = __arraycount(name);
7611.90Skamil	ki_sigset_t kp_sigignore;
7621.88Skamil
7631.88Skamil#ifndef PTRACE_ILLEGAL_ASM
7641.88Skamil	if (sig == SIGILL)
7651.88Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
7661.88Skamil#endif
7671.88Skamil
7681.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
7691.114Skamil		atf_tc_skip("FP exceptions are not supported");
7701.114Skamil
7711.88Skamil	memset(&info, 0, sizeof(info));
7721.88Skamil
7731.88Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
7741.88Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
7751.88Skamil	if (child == 0) {
7761.88Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
7771.88Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
7781.88Skamil
7791.88Skamil		memset(&sa, 0, sizeof(sa));
7801.88Skamil		sa.sa_handler = SIG_IGN;
7811.88Skamil		sigemptyset(&sa.sa_mask);
7821.88Skamil
7831.88Skamil		FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
7841.88Skamil
7851.90Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
7861.90Skamil		FORKEE_ASSERT(raise(sigval) == 0);
7871.90Skamil
7881.88Skamil		DPRINTF("Before executing a trap\n");
7891.88Skamil		switch (sig) {
7901.88Skamil		case SIGTRAP:
7911.88Skamil			trigger_trap();
7921.88Skamil			break;
7931.88Skamil		case SIGSEGV:
7941.88Skamil			trigger_segv();
7951.88Skamil			break;
7961.88Skamil		case SIGILL:
7971.88Skamil			trigger_ill();
7981.88Skamil			break;
7991.88Skamil		case SIGFPE:
8001.88Skamil			trigger_fpe();
8011.88Skamil			break;
8021.88Skamil		case SIGBUS:
8031.88Skamil			trigger_bus();
8041.88Skamil			break;
8051.88Skamil		default:
8061.88Skamil			/* NOTREACHED */
8071.88Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
8081.88Skamil		}
8091.88Skamil
8101.88Skamil		/* NOTREACHED */
8111.88Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
8121.88Skamil	}
8131.88Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
8141.88Skamil
8151.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8161.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8171.88Skamil
8181.90Skamil	validate_status_stopped(status, sigval);
8191.90Skamil
8201.90Skamil	name[0] = CTL_KERN,
8211.90Skamil	name[1] = KERN_PROC2,
8221.90Skamil	name[2] = KERN_PROC_PID;
8231.90Skamil	name[3] = child;
8241.90Skamil	name[4] = sizeof(kp);
8251.90Skamil	name[5] = 1;
8261.90Skamil
8271.90Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
8281.90Skamil
8291.90Skamil	kp_sigignore = kp.p_sigignore;
8301.90Skamil
8311.90Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
8321.90Skamil	SYSCALL_REQUIRE(
8331.90Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
8341.90Skamil
8351.90Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
8361.90Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
8371.90Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
8381.90Skamil	    info.psi_siginfo.si_errno);
8391.90Skamil
8401.90Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
8411.90Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
8421.90Skamil
8431.90Skamil	DPRINTF("Before resuming the child process where it left off and "
8441.90Skamil	    "without signal to be sent\n");
8451.90Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
8461.90Skamil
8471.90Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8481.90Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8491.90Skamil
8501.88Skamil	validate_status_stopped(status, sig);
8511.88Skamil
8521.88Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
8531.88Skamil	SYSCALL_REQUIRE(
8541.88Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
8551.88Skamil
8561.88Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
8571.88Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
8581.88Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
8591.88Skamil	    info.psi_siginfo.si_errno);
8601.88Skamil
8611.90Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
8621.90Skamil
8631.90Skamil	DPRINTF("kp_sigignore="
8641.90Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
8651.90Skamil	    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
8661.90Skamil	    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
8671.90Skamil
8681.90Skamil	DPRINTF("kp.p_sigignore="
8691.90Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
8701.90Skamil	    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
8711.90Skamil	    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
8721.90Skamil
8731.90Skamil	ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore, sizeof(kp_sigignore)));
8741.90Skamil
8751.88Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
8761.88Skamil	switch (sig) {
8771.88Skamil	case SIGTRAP:
8781.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
8791.88Skamil		break;
8801.88Skamil	case SIGSEGV:
8811.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
8821.88Skamil		break;
8831.88Skamil	case SIGILL:
8841.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
8851.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
8861.88Skamil		break;
8871.88Skamil	case SIGFPE:
8881.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
8891.88Skamil		break;
8901.88Skamil	case SIGBUS:
8911.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
8921.88Skamil		break;
8931.88Skamil	}
8941.88Skamil
8951.88Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
8961.88Skamil
8971.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8981.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8991.88Skamil
9001.88Skamil	validate_status_signaled(status, SIGKILL, 0);
9011.88Skamil
9021.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9031.88Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
9041.88Skamil}
9051.88Skamil
9061.88Skamil#define TRACEME_SIGNALIGNORED_CRASH(test, sig)				\
9071.88SkamilATF_TC(test);								\
9081.88SkamilATF_TC_HEAD(test, tc)							\
9091.88Skamil{									\
9101.88Skamil	atf_tc_set_md_var(tc, "descr",					\
9111.88Skamil	    "Verify ignored crash signal " #sig " in a child after "	\
9121.88Skamil	    "PT_TRACE_ME is delivered to its tracer"); 			\
9131.88Skamil}									\
9141.88Skamil									\
9151.88SkamilATF_TC_BODY(test, tc)							\
9161.88Skamil{									\
9171.88Skamil									\
9181.88Skamil	traceme_signalignored_crash(sig);				\
9191.88Skamil}
9201.88Skamil
9211.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_trap, SIGTRAP)
9221.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_segv, SIGSEGV)
9231.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_ill, SIGILL)
9241.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_fpe, SIGFPE)
9251.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_bus, SIGBUS)
9261.88Skamil
9271.88Skamil/// ----------------------------------------------------------------------------
9281.88Skamil
9291.88Skamilstatic void
9301.50Skamiltraceme_sendsignal_handle(int sigsent, void (*sah)(int a), int *traceme_caught)
9311.1Skamil{
9321.1Skamil	const int exitval = 5;
9331.34Skamil	const int sigval = SIGSTOP;
9341.1Skamil	pid_t child, wpid;
9351.1Skamil	struct sigaction sa;
9361.1Skamil#if defined(TWAIT_HAVE_STATUS)
9371.1Skamil	int status;
9381.1Skamil#endif
9391.61Skre	struct ptrace_siginfo info;
9401.1Skamil
9411.45Skamil	memset(&info, 0, sizeof(info));
9421.45Skamil
9431.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
9441.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
9451.1Skamil	if (child == 0) {
9461.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
9471.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
9481.1Skamil
9491.34Skamil		sa.sa_handler = sah;
9501.1Skamil		sa.sa_flags = SA_SIGINFO;
9511.1Skamil		sigemptyset(&sa.sa_mask);
9521.1Skamil
9531.1Skamil		FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
9541.1Skamil
9551.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
9561.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
9571.1Skamil
9581.34Skamil		FORKEE_ASSERT_EQ(*traceme_caught, 1);
9591.1Skamil
9601.13Schristos		DPRINTF("Before exiting of the child process\n");
9611.1Skamil		_exit(exitval);
9621.1Skamil	}
9631.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
9641.1Skamil
9651.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9661.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9671.1Skamil
9681.1Skamil	validate_status_stopped(status, sigval);
9691.1Skamil
9701.45Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
9711.61Skre	SYSCALL_REQUIRE(
9721.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
9731.45Skamil
9741.45Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
9751.45Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
9761.45Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
9771.45Skamil	    info.psi_siginfo.si_errno);
9781.45Skamil
9791.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
9801.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
9811.45Skamil
9821.13Schristos	DPRINTF("Before resuming the child process where it left off and with "
9831.1Skamil	    "signal %s to be sent\n", strsignal(sigsent));
9841.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
9851.1Skamil
9861.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9871.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9881.1Skamil
9891.1Skamil	validate_status_exited(status, exitval);
9901.1Skamil
9911.13Schristos	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
9921.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
9931.1Skamil}
9941.1Skamil
9951.61Skre#define TRACEME_SENDSIGNAL_HANDLE(test, sig)				\
9961.61SkreATF_TC(test);								\
9971.61SkreATF_TC_HEAD(test, tc)							\
9981.61Skre{									\
9991.61Skre	atf_tc_set_md_var(tc, "descr",					\
10001.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
10011.61Skre	    "handled correctly and caught by a signal handler");	\
10021.61Skre}									\
10031.61Skre									\
10041.61Skrestatic int test##_caught = 0;						\
10051.61Skre									\
10061.61Skrestatic void								\
10071.61Skretest##_sighandler(int arg)						\
10081.61Skre{									\
10091.61Skre	FORKEE_ASSERT_EQ(arg, sig);					\
10101.61Skre									\
10111.61Skre	++ test##_caught;						\
10121.61Skre}									\
10131.61Skre									\
10141.61SkreATF_TC_BODY(test, tc)							\
10151.61Skre{									\
10161.61Skre									\
10171.61Skre	traceme_sendsignal_handle(sig, test##_sighandler, & test##_caught); \
10181.34Skamil}
10191.34Skamil
10201.34Skamil// A signal handler for SIGKILL and SIGSTOP cannot be registered.
10211.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle1, SIGABRT) /* abort trap */
10221.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle2, SIGHUP)  /* hangup */
10231.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle3, SIGCONT) /* continued? */
10241.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle4, SIGTRAP) /* crash sig. */
10251.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle5, SIGBUS) /* crash sig. */
10261.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle6, SIGILL) /* crash sig. */
10271.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle7, SIGFPE) /* crash sig. */
10281.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle8, SIGSEGV) /* crash sig. */
10291.34Skamil
10301.34Skamil/// ----------------------------------------------------------------------------
10311.34Skamil
10321.35Skamilstatic void
10331.50Skamiltraceme_sendsignal_masked(int sigsent)
10341.50Skamil{
10351.50Skamil	const int exitval = 5;
10361.50Skamil	const int sigval = SIGSTOP;
10371.50Skamil	pid_t child, wpid;
10381.50Skamil	sigset_t set;
10391.50Skamil#if defined(TWAIT_HAVE_STATUS)
10401.50Skamil	int status;
10411.50Skamil#endif
10421.61Skre	struct ptrace_siginfo info;
10431.50Skamil
10441.50Skamil	memset(&info, 0, sizeof(info));
10451.50Skamil
10461.50Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
10471.50Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
10481.50Skamil	if (child == 0) {
10491.50Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
10501.50Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
10511.50Skamil
10521.50Skamil		sigemptyset(&set);
10531.50Skamil		sigaddset(&set, sigsent);
10541.50Skamil		FORKEE_ASSERT(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
10551.50Skamil
10561.50Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
10571.50Skamil		FORKEE_ASSERT(raise(sigval) == 0);
10581.50Skamil
10591.50Skamil		_exit(exitval);
10601.50Skamil	}
10611.50Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
10621.50Skamil
10631.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10641.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
10651.50Skamil
10661.50Skamil	validate_status_stopped(status, sigval);
10671.50Skamil
10681.50Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
10691.61Skre	SYSCALL_REQUIRE(
10701.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
10711.50Skamil
10721.50Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
10731.50Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
10741.50Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
10751.50Skamil	    info.psi_siginfo.si_errno);
10761.50Skamil
10771.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
10781.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
10791.50Skamil
10801.50Skamil	DPRINTF("Before resuming the child process where it left off and with "
10811.50Skamil	    "signal %s to be sent\n", strsignal(sigsent));
10821.50Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
10831.50Skamil
10841.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10851.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
10861.50Skamil
10871.50Skamil	validate_status_exited(status, exitval);
10881.50Skamil
10891.50Skamil	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
10901.50Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
10911.50Skamil}
10921.50Skamil
10931.61Skre#define TRACEME_SENDSIGNAL_MASKED(test, sig)				\
10941.61SkreATF_TC(test);								\
10951.61SkreATF_TC_HEAD(test, tc)							\
10961.61Skre{									\
10971.61Skre	atf_tc_set_md_var(tc, "descr",					\
10981.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
10991.61Skre	    "handled correctly and the signal is masked by SIG_BLOCK");	\
11001.61Skre}									\
11011.61Skre									\
11021.61SkreATF_TC_BODY(test, tc)							\
11031.61Skre{									\
11041.61Skre									\
11051.61Skre	traceme_sendsignal_masked(sig);					\
11061.50Skamil}
11071.50Skamil
11081.50Skamil// A signal handler for SIGKILL and SIGSTOP cannot be masked.
11091.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked1, SIGABRT) /* abort trap */
11101.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked2, SIGHUP)  /* hangup */
11111.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked3, SIGCONT) /* continued? */
11121.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked4, SIGTRAP) /* crash sig. */
11131.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked5, SIGBUS) /* crash sig. */
11141.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked6, SIGILL) /* crash sig. */
11151.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked7, SIGFPE) /* crash sig. */
11161.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked8, SIGSEGV) /* crash sig. */
11171.50Skamil
11181.50Skamil/// ----------------------------------------------------------------------------
11191.50Skamil
11201.50Skamilstatic void
11211.50Skamiltraceme_sendsignal_ignored(int sigsent)
11221.50Skamil{
11231.50Skamil	const int exitval = 5;
11241.50Skamil	const int sigval = SIGSTOP;
11251.50Skamil	pid_t child, wpid;
11261.50Skamil	struct sigaction sa;
11271.50Skamil#if defined(TWAIT_HAVE_STATUS)
11281.50Skamil	int status;
11291.50Skamil#endif
11301.61Skre	struct ptrace_siginfo info;
11311.50Skamil
11321.50Skamil	memset(&info, 0, sizeof(info));
11331.50Skamil
11341.50Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
11351.50Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
11361.50Skamil	if (child == 0) {
11371.50Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
11381.61Skre
11391.50Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
11401.50Skamil
11411.50Skamil		memset(&sa, 0, sizeof(sa));
11421.50Skamil		sa.sa_handler = SIG_IGN;
11431.50Skamil		sigemptyset(&sa.sa_mask);
11441.50Skamil		FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
11451.50Skamil
11461.50Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
11471.50Skamil		FORKEE_ASSERT(raise(sigval) == 0);
11481.50Skamil
11491.50Skamil		_exit(exitval);
11501.50Skamil	}
11511.50Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
11521.50Skamil
11531.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11541.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11551.50Skamil
11561.50Skamil	validate_status_stopped(status, sigval);
11571.50Skamil
11581.50Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
11591.61Skre	SYSCALL_REQUIRE(
11601.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
11611.50Skamil
11621.50Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
11631.50Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
11641.50Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
11651.50Skamil	    info.psi_siginfo.si_errno);
11661.50Skamil
11671.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
11681.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
11691.50Skamil
11701.50Skamil	DPRINTF("Before resuming the child process where it left off and with "
11711.50Skamil	    "signal %s to be sent\n", strsignal(sigsent));
11721.50Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
11731.50Skamil
11741.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11751.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11761.50Skamil
11771.50Skamil	validate_status_exited(status, exitval);
11781.50Skamil
11791.50Skamil	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
11801.50Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
11811.50Skamil}
11821.50Skamil
11831.61Skre#define TRACEME_SENDSIGNAL_IGNORED(test, sig)				\
11841.61SkreATF_TC(test);								\
11851.61SkreATF_TC_HEAD(test, tc)							\
11861.61Skre{									\
11871.61Skre	atf_tc_set_md_var(tc, "descr",					\
11881.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
11891.61Skre	    "handled correctly and the signal is masked by SIG_IGN");	\
11901.61Skre}									\
11911.61Skre									\
11921.61SkreATF_TC_BODY(test, tc)							\
11931.61Skre{									\
11941.61Skre									\
11951.61Skre	traceme_sendsignal_ignored(sig);				\
11961.50Skamil}
11971.50Skamil
11981.50Skamil// A signal handler for SIGKILL and SIGSTOP cannot be ignored.
11991.61SkreTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored1, SIGABRT) /* abort */
12001.50SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored2, SIGHUP)  /* hangup */
12011.61SkreTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored3, SIGCONT) /* continued */
12021.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored4, SIGTRAP) /* crash s. */
12031.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored5, SIGBUS) /* crash s. */
12041.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored6, SIGILL) /* crash s. */
12051.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored7, SIGFPE) /* crash s. */
12061.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored8, SIGSEGV) /* crash s. */
12071.50Skamil
12081.50Skamil/// ----------------------------------------------------------------------------
12091.50Skamil
12101.50Skamilstatic void
12111.50Skamiltraceme_sendsignal_simple(int sigsent)
12121.1Skamil{
12131.35Skamil	const int sigval = SIGSTOP;
12141.35Skamil	int exitval = 0;
12151.1Skamil	pid_t child, wpid;
12161.1Skamil#if defined(TWAIT_HAVE_STATUS)
12171.1Skamil	int status;
12181.85Skamil	int expect_core;
12191.85Skamil
12201.85Skamil	switch (sigsent) {
12211.85Skamil	case SIGABRT:
12221.85Skamil	case SIGTRAP:
12231.85Skamil	case SIGBUS:
12241.85Skamil	case SIGILL:
12251.85Skamil	case SIGFPE:
12261.85Skamil	case SIGSEGV:
12271.85Skamil		expect_core = 1;
12281.85Skamil		break;
12291.85Skamil	default:
12301.85Skamil		expect_core = 0;
12311.85Skamil		break;
12321.85Skamil	}
12331.1Skamil#endif
12341.61Skre	struct ptrace_siginfo info;
12351.1Skamil
12361.45Skamil	memset(&info, 0, sizeof(info));
12371.45Skamil
12381.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
12391.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
12401.1Skamil	if (child == 0) {
12411.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
12421.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
12431.1Skamil
12441.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
12451.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
12461.1Skamil
12471.35Skamil		switch (sigsent) {
12481.35Skamil		case SIGCONT:
12491.48Skamil		case SIGSTOP:
12501.35Skamil			_exit(exitval);
12511.35Skamil		default:
12521.35Skamil			/* NOTREACHED */
12531.35Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
12541.35Skamil		}
12551.1Skamil	}
12561.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
12571.1Skamil
12581.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12591.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
12601.1Skamil
12611.1Skamil	validate_status_stopped(status, sigval);
12621.1Skamil
12631.45Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
12641.61Skre	SYSCALL_REQUIRE(
12651.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
12661.45Skamil
12671.45Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12681.45Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
12691.45Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12701.45Skamil	    info.psi_siginfo.si_errno);
12711.45Skamil
12721.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
12731.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
12741.45Skamil
12751.13Schristos	DPRINTF("Before resuming the child process where it left off and with "
12761.1Skamil	    "signal %s to be sent\n", strsignal(sigsent));
12771.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
12781.1Skamil
12791.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12801.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
12811.1Skamil
12821.35Skamil	switch (sigsent) {
12831.48Skamil	case SIGSTOP:
12841.48Skamil		validate_status_stopped(status, sigsent);
12851.48Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
12861.61Skre		    "child\n");
12871.48Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
12881.61Skre		    sizeof(info)) != -1);
12891.48Skamil
12901.48Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12911.48Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
12921.61Skre		    "si_errno=%#x\n",
12931.61Skre		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12941.61Skre		    info.psi_siginfo.si_errno);
12951.48Skamil
12961.48Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
12971.48Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
12981.48Skamil
12991.48Skamil		DPRINTF("Before resuming the child process where it left off "
13001.61Skre		    "and with signal %s to be sent\n", strsignal(sigsent));
13011.48Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
13021.48Skamil
13031.48Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
13041.48Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
13051.61Skre		    child);
13061.48Skamil		/* FALLTHROUGH */
13071.35Skamil	case SIGCONT:
13081.35Skamil		validate_status_exited(status, exitval);
13091.35Skamil		break;
13101.35Skamil	default:
13111.35Skamil		validate_status_signaled(status, sigsent, expect_core);
13121.35Skamil		break;
13131.35Skamil	}
13141.1Skamil
13151.13Schristos	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
13161.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
13171.1Skamil}
13181.1Skamil
13191.61Skre#define TRACEME_SENDSIGNAL_SIMPLE(test, sig)				\
13201.61SkreATF_TC(test);								\
13211.61SkreATF_TC_HEAD(test, tc)							\
13221.61Skre{									\
13231.61Skre	atf_tc_set_md_var(tc, "descr",					\
13241.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
13251.61Skre	    "handled correctly in a child without a signal handler");	\
13261.61Skre}									\
13271.61Skre									\
13281.61SkreATF_TC_BODY(test, tc)							\
13291.61Skre{									\
13301.61Skre									\
13311.61Skre	traceme_sendsignal_simple(sig);					\
13321.35Skamil}
13331.35Skamil
13341.61SkreTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple1, SIGKILL) /* non-maskable*/
13351.61SkreTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple2, SIGSTOP) /* non-maskable*/
13361.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple3, SIGABRT) /* abort trap */
13371.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple4, SIGHUP)  /* hangup */
13381.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple5, SIGCONT) /* continued? */
13391.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple6, SIGTRAP) /* crash sig. */
13401.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple7, SIGBUS) /* crash sig. */
13411.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple8, SIGILL) /* crash sig. */
13421.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple9, SIGFPE) /* crash sig. */
13431.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple10, SIGSEGV) /* crash sig. */
13441.35Skamil
13451.35Skamil/// ----------------------------------------------------------------------------
13461.35Skamil
13471.37SkamilATF_TC(traceme_pid1_parent);
13481.37SkamilATF_TC_HEAD(traceme_pid1_parent, tc)
13491.37Skamil{
13501.37Skamil	atf_tc_set_md_var(tc, "descr",
13511.37Skamil	    "Verify that PT_TRACE_ME is not allowed when our parent is PID1");
13521.37Skamil}
13531.37Skamil
13541.37SkamilATF_TC_BODY(traceme_pid1_parent, tc)
13551.37Skamil{
13561.37Skamil	struct msg_fds parent_child;
13571.37Skamil	int exitval_child1 = 1, exitval_child2 = 2;
13581.37Skamil	pid_t child1, child2, wpid;
13591.37Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
13601.37Skamil#if defined(TWAIT_HAVE_STATUS)
13611.37Skamil	int status;
13621.37Skamil#endif
13631.37Skamil
13641.37Skamil	SYSCALL_REQUIRE(msg_open(&parent_child) == 0);
13651.37Skamil
13661.37Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
13671.37Skamil	SYSCALL_REQUIRE((child1 = fork()) != -1);
13681.37Skamil	if (child1 == 0) {
13691.37Skamil		DPRINTF("Before forking process PID=%d\n", getpid());
13701.37Skamil		SYSCALL_REQUIRE((child2 = fork()) != -1);
13711.37Skamil		if (child2 != 0) {
13721.37Skamil			DPRINTF("Parent process PID=%d, child2's PID=%d\n",
13731.61Skre			    getpid(), child2);
13741.37Skamil			_exit(exitval_child1);
13751.37Skamil		}
13761.37Skamil		CHILD_FROM_PARENT("exit child1", parent_child, msg);
13771.37Skamil
13781.37Skamil		DPRINTF("Assert that our parent is PID1 (initproc)\n");
13791.37Skamil		FORKEE_ASSERT_EQ(getppid(), 1);
13801.37Skamil
13811.37Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
13821.37Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) == -1);
13831.37Skamil		SYSCALL_REQUIRE_ERRNO(errno, EPERM);
13841.37Skamil
13851.37Skamil		CHILD_TO_PARENT("child2 exiting", parent_child, msg);
13861.37Skamil
13871.37Skamil		_exit(exitval_child2);
13881.37Skamil	}
13891.37Skamil	DPRINTF("Parent process PID=%d, child1's PID=%d\n", getpid(), child1);
13901.37Skamil
13911.37Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
13921.61Skre	TWAIT_REQUIRE_SUCCESS(
13931.61Skre	    wpid = TWAIT_GENERIC(child1, &status, WEXITED), child1);
13941.37Skamil
13951.37Skamil	validate_status_exited(status, exitval_child1);
13961.37Skamil
13971.37Skamil	DPRINTF("Notify that child1 is dead\n");
13981.37Skamil	PARENT_TO_CHILD("exit child1", parent_child, msg);
13991.37Skamil
14001.37Skamil	DPRINTF("Wait for exiting of child2\n");
14011.37Skamil	PARENT_FROM_CHILD("child2 exiting", parent_child, msg);
14021.37Skamil}
14031.37Skamil
14041.37Skamil/// ----------------------------------------------------------------------------
14051.37Skamil
14061.40Skamilstatic void
14071.40Skamiltraceme_vfork_raise(int sigval)
14081.40Skamil{
14091.46Skamil	const int exitval = 5, exitval_watcher = 10;
14101.46Skamil	pid_t child, parent, watcher, wpid;
14111.46Skamil	int rv;
14121.40Skamil#if defined(TWAIT_HAVE_STATUS)
14131.40Skamil	int status;
14141.85Skamil
14151.85Skamil	/* volatile workarounds GCC -Werror=clobbered */
14161.85Skamil	volatile int expect_core;
14171.85Skamil
14181.85Skamil	switch (sigval) {
14191.85Skamil	case SIGABRT:
14201.85Skamil	case SIGTRAP:
14211.85Skamil	case SIGBUS:
14221.85Skamil	case SIGILL:
14231.85Skamil	case SIGFPE:
14241.85Skamil	case SIGSEGV:
14251.85Skamil		expect_core = 1;
14261.85Skamil		break;
14271.85Skamil	default:
14281.85Skamil		expect_core = 0;
14291.85Skamil		break;
14301.85Skamil	}
14311.40Skamil#endif
14321.40Skamil
14331.46Skamil	/*
14341.46Skamil	 * Spawn a dedicated thread to watch for a stopped child and emit
14351.46Skamil	 * the SIGKILL signal to it.
14361.46Skamil	 *
14371.46Skamil	 * vfork(2) might clobber watcher, this means that it's safer and
14381.46Skamil	 * simpler to reparent this process to initproc and forget about it.
14391.46Skamil	 */
14401.46Skamil	if (sigval == SIGSTOP) {
14411.46Skamil		parent = getpid();
14421.46Skamil
14431.46Skamil		watcher = fork();
14441.46Skamil		ATF_REQUIRE(watcher != 1);
14451.46Skamil		if (watcher == 0) {
14461.46Skamil			/* Double fork(2) trick to reparent to initproc */
14471.46Skamil			watcher = fork();
14481.46Skamil			FORKEE_ASSERT_NEQ(watcher, -1);
14491.46Skamil			if (watcher != 0)
14501.46Skamil				_exit(exitval_watcher);
14511.46Skamil
14521.46Skamil			child = await_stopped_child(parent);
14531.46Skamil
14541.46Skamil			errno = 0;
14551.46Skamil			rv = kill(child, SIGKILL);
14561.46Skamil			FORKEE_ASSERT_EQ(rv, 0);
14571.46Skamil			FORKEE_ASSERT_EQ(errno, 0);
14581.46Skamil
14591.46Skamil			/* This exit value will be collected by initproc */
14601.46Skamil			_exit(0);
14611.46Skamil		}
14621.46Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14631.46Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(watcher, &status, 0),
14641.61Skre		    watcher);
14651.46Skamil
14661.46Skamil		validate_status_exited(status, exitval_watcher);
14671.46Skamil
14681.46Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14691.61Skre		TWAIT_REQUIRE_FAILURE(ECHILD,
14701.61Skre		    wpid = TWAIT_GENERIC(watcher, &status, 0));
14711.46Skamil	}
14721.46Skamil
14731.40Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
14741.40Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
14751.40Skamil	if (child == 0) {
14761.40Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
14771.40Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
14781.40Skamil
14791.40Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
14801.40Skamil		FORKEE_ASSERT(raise(sigval) == 0);
14811.40Skamil
14821.40Skamil		switch (sigval) {
14831.46Skamil		case SIGSTOP:
14841.40Skamil		case SIGKILL:
14851.40Skamil		case SIGABRT:
14861.40Skamil		case SIGHUP:
14871.85Skamil		case SIGTRAP:
14881.85Skamil		case SIGBUS:
14891.85Skamil		case SIGILL:
14901.85Skamil		case SIGFPE:
14911.85Skamil		case SIGSEGV:
14921.40Skamil			/* NOTREACHED */
14931.40Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
14941.70Smrg			__unreachable();
14951.40Skamil		default:
14961.40Skamil			DPRINTF("Before exiting of the child process\n");
14971.40Skamil			_exit(exitval);
14981.40Skamil		}
14991.40Skamil	}
15001.40Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
15011.40Skamil
15021.40Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15031.40Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
15041.40Skamil
15051.40Skamil	switch (sigval) {
15061.40Skamil	case SIGKILL:
15071.40Skamil	case SIGABRT:
15081.40Skamil	case SIGHUP:
15091.85Skamil	case SIGTRAP:
15101.85Skamil	case SIGBUS:
15111.85Skamil	case SIGILL:
15121.85Skamil	case SIGFPE:
15131.85Skamil	case SIGSEGV:
15141.40Skamil		validate_status_signaled(status, sigval, expect_core);
15151.40Skamil		break;
15161.40Skamil	case SIGSTOP:
15171.46Skamil		validate_status_signaled(status, SIGKILL, 0);
15181.46Skamil		break;
15191.40Skamil	case SIGCONT:
15201.47Skamil	case SIGTSTP:
15211.47Skamil	case SIGTTIN:
15221.47Skamil	case SIGTTOU:
15231.40Skamil		validate_status_exited(status, exitval);
15241.40Skamil		break;
15251.40Skamil	default:
15261.40Skamil		/* NOTREACHED */
15271.40Skamil		ATF_REQUIRE(0 && "NOT IMPLEMENTED");
15281.40Skamil		break;
15291.40Skamil	}
15301.40Skamil
15311.40Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15321.40Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
15331.40Skamil}
15341.40Skamil
15351.61Skre#define TRACEME_VFORK_RAISE(test, sig)					\
15361.61SkreATF_TC(test);								\
15371.61SkreATF_TC_HEAD(test, tc)							\
15381.61Skre{									\
15391.61Skre	atf_tc_set_md_var(tc, "descr",					\
15401.61Skre	    "Verify PT_TRACE_ME followed by raise of " #sig " in a "	\
15411.61Skre	    "vfork(2)ed child");					\
15421.61Skre}									\
15431.61Skre									\
15441.61SkreATF_TC_BODY(test, tc)							\
15451.61Skre{									\
15461.61Skre									\
15471.61Skre	traceme_vfork_raise(sig);					\
15481.40Skamil}
15491.40Skamil
15501.40SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise1, SIGKILL) /* non-maskable */
15511.46SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise2, SIGSTOP) /* non-maskable */
15521.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise3, SIGTSTP) /* ignored in vfork(2) */
15531.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise4, SIGTTIN) /* ignored in vfork(2) */
15541.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise5, SIGTTOU) /* ignored in vfork(2) */
15551.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise6, SIGABRT) /* regular abort trap */
15561.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise7, SIGHUP)  /* hangup */
15571.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise8, SIGCONT) /* continued? */
15581.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise9, SIGTRAP) /* crash signal */
15591.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise10, SIGBUS) /* crash signal */
15601.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise11, SIGILL) /* crash signal */
15611.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise12, SIGFPE) /* crash signal */
15621.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise13, SIGSEGV) /* crash signal */
15631.40Skamil
15641.40Skamil/// ----------------------------------------------------------------------------
15651.40Skamil
15661.52Skamilstatic void
15671.52Skamiltraceme_vfork_crash(int sig)
15681.41Skamil{
15691.41Skamil	pid_t child, wpid;
15701.41Skamil#if defined(TWAIT_HAVE_STATUS)
15711.41Skamil	int status;
15721.41Skamil#endif
15731.41Skamil
15741.71Skamil#ifndef PTRACE_ILLEGAL_ASM
15751.71Skamil	if (sig == SIGILL)
15761.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
15771.71Skamil#endif
15781.71Skamil
15791.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
15801.114Skamil		atf_tc_skip("FP exceptions are not supported");
15811.114Skamil
15821.41Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
15831.41Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
15841.41Skamil	if (child == 0) {
15851.41Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
15861.41Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
15871.41Skamil
15881.52Skamil		DPRINTF("Before executing a trap\n");
15891.52Skamil		switch (sig) {
15901.52Skamil		case SIGTRAP:
15911.52Skamil			trigger_trap();
15921.52Skamil			break;
15931.52Skamil		case SIGSEGV:
15941.52Skamil			trigger_segv();
15951.52Skamil			break;
15961.52Skamil		case SIGILL:
15971.52Skamil			trigger_ill();
15981.52Skamil			break;
15991.52Skamil		case SIGFPE:
16001.52Skamil			trigger_fpe();
16011.52Skamil			break;
16021.52Skamil		case SIGBUS:
16031.52Skamil			trigger_bus();
16041.52Skamil			break;
16051.52Skamil		default:
16061.52Skamil			/* NOTREACHED */
16071.52Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
16081.52Skamil		}
16091.41Skamil
16101.41Skamil		/* NOTREACHED */
16111.41Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
16121.41Skamil	}
16131.41Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
16141.41Skamil
16151.41Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16161.41Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
16171.41Skamil
16181.52Skamil	validate_status_signaled(status, sig, 1);
16191.41Skamil
16201.41Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16211.41Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
16221.41Skamil}
16231.41Skamil
16241.61Skre#define TRACEME_VFORK_CRASH(test, sig)					\
16251.61SkreATF_TC(test);								\
16261.61SkreATF_TC_HEAD(test, tc)							\
16271.61Skre{									\
16281.61Skre	atf_tc_set_md_var(tc, "descr",					\
16291.61Skre	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
16301.61Skre	    "vfork(2)ed child");					\
16311.61Skre}									\
16321.61Skre									\
16331.61SkreATF_TC_BODY(test, tc)							\
16341.61Skre{									\
16351.61Skre									\
16361.61Skre	traceme_vfork_crash(sig);					\
16371.52Skamil}
16381.52Skamil
16391.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_trap, SIGTRAP)
16401.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_segv, SIGSEGV)
16411.71SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_ill, SIGILL)
16421.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_fpe, SIGFPE)
16431.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_bus, SIGBUS)
16441.52Skamil
16451.41Skamil/// ----------------------------------------------------------------------------
16461.41Skamil
16471.92Skamilstatic void
16481.92Skamiltraceme_vfork_signalmasked_crash(int sig)
16491.92Skamil{
16501.92Skamil	pid_t child, wpid;
16511.92Skamil#if defined(TWAIT_HAVE_STATUS)
16521.92Skamil	int status;
16531.92Skamil#endif
16541.92Skamil	sigset_t intmask;
16551.92Skamil
16561.92Skamil#ifndef PTRACE_ILLEGAL_ASM
16571.92Skamil	if (sig == SIGILL)
16581.92Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
16591.92Skamil#endif
16601.92Skamil
16611.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
16621.114Skamil		atf_tc_skip("FP exceptions are not supported");
16631.114Skamil
16641.92Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
16651.92Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
16661.92Skamil	if (child == 0) {
16671.92Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
16681.92Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
16691.92Skamil
16701.92Skamil		sigemptyset(&intmask);
16711.92Skamil		sigaddset(&intmask, sig);
16721.92Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
16731.92Skamil
16741.92Skamil		DPRINTF("Before executing a trap\n");
16751.92Skamil		switch (sig) {
16761.92Skamil		case SIGTRAP:
16771.92Skamil			trigger_trap();
16781.92Skamil			break;
16791.92Skamil		case SIGSEGV:
16801.92Skamil			trigger_segv();
16811.92Skamil			break;
16821.92Skamil		case SIGILL:
16831.92Skamil			trigger_ill();
16841.92Skamil			break;
16851.92Skamil		case SIGFPE:
16861.92Skamil			trigger_fpe();
16871.92Skamil			break;
16881.92Skamil		case SIGBUS:
16891.92Skamil			trigger_bus();
16901.92Skamil			break;
16911.92Skamil		default:
16921.92Skamil			/* NOTREACHED */
16931.92Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
16941.92Skamil		}
16951.92Skamil
16961.92Skamil		/* NOTREACHED */
16971.92Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
16981.92Skamil	}
16991.92Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
17001.92Skamil
17011.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17021.92Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17031.92Skamil
17041.92Skamil	validate_status_signaled(status, sig, 1);
17051.92Skamil
17061.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17071.92Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
17081.92Skamil}
17091.92Skamil
17101.92Skamil#define TRACEME_VFORK_SIGNALMASKED_CRASH(test, sig)			\
17111.92SkamilATF_TC(test);								\
17121.92SkamilATF_TC_HEAD(test, tc)							\
17131.92Skamil{									\
17141.92Skamil	atf_tc_set_md_var(tc, "descr",					\
17151.92Skamil	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
17161.92Skamil	    "vfork(2)ed child with a masked signal");			\
17171.92Skamil}									\
17181.92Skamil									\
17191.92SkamilATF_TC_BODY(test, tc)							\
17201.92Skamil{									\
17211.92Skamil									\
17221.92Skamil	traceme_vfork_signalmasked_crash(sig);				\
17231.92Skamil}
17241.92Skamil
17251.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_trap, SIGTRAP)
17261.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_segv, SIGSEGV)
17271.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_ill, SIGILL)
17281.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_fpe, SIGFPE)
17291.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_bus, SIGBUS)
17301.92Skamil
17311.92Skamil/// ----------------------------------------------------------------------------
17321.92Skamil
17331.92Skamilstatic void
17341.92Skamiltraceme_vfork_signalignored_crash(int sig)
17351.92Skamil{
17361.92Skamil	pid_t child, wpid;
17371.92Skamil#if defined(TWAIT_HAVE_STATUS)
17381.92Skamil	int status;
17391.92Skamil#endif
17401.92Skamil	struct sigaction sa;
17411.92Skamil
17421.92Skamil#ifndef PTRACE_ILLEGAL_ASM
17431.92Skamil	if (sig == SIGILL)
17441.92Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
17451.92Skamil#endif
17461.92Skamil
17471.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
17481.114Skamil		atf_tc_skip("FP exceptions are not supported");
17491.114Skamil
17501.92Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
17511.92Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
17521.92Skamil	if (child == 0) {
17531.92Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
17541.92Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
17551.92Skamil
17561.92Skamil		memset(&sa, 0, sizeof(sa));
17571.92Skamil		sa.sa_handler = SIG_IGN;
17581.92Skamil		sigemptyset(&sa.sa_mask);
17591.92Skamil
17601.92Skamil		FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
17611.92Skamil
17621.92Skamil		DPRINTF("Before executing a trap\n");
17631.92Skamil		switch (sig) {
17641.92Skamil		case SIGTRAP:
17651.92Skamil			trigger_trap();
17661.92Skamil			break;
17671.92Skamil		case SIGSEGV:
17681.92Skamil			trigger_segv();
17691.92Skamil			break;
17701.92Skamil		case SIGILL:
17711.92Skamil			trigger_ill();
17721.92Skamil			break;
17731.92Skamil		case SIGFPE:
17741.92Skamil			trigger_fpe();
17751.92Skamil			break;
17761.92Skamil		case SIGBUS:
17771.92Skamil			trigger_bus();
17781.92Skamil			break;
17791.92Skamil		default:
17801.92Skamil			/* NOTREACHED */
17811.92Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
17821.92Skamil		}
17831.92Skamil
17841.92Skamil		/* NOTREACHED */
17851.92Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
17861.92Skamil	}
17871.92Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
17881.92Skamil
17891.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17901.92Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17911.92Skamil
17921.92Skamil	validate_status_signaled(status, sig, 1);
17931.92Skamil
17941.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17951.92Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
17961.92Skamil}
17971.92Skamil
17981.92Skamil#define TRACEME_VFORK_SIGNALIGNORED_CRASH(test, sig)			\
17991.92SkamilATF_TC(test);								\
18001.92SkamilATF_TC_HEAD(test, tc)							\
18011.92Skamil{									\
18021.92Skamil	atf_tc_set_md_var(tc, "descr",					\
18031.92Skamil	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
18041.92Skamil	    "vfork(2)ed child with ignored signal");			\
18051.92Skamil}									\
18061.92Skamil									\
18071.92SkamilATF_TC_BODY(test, tc)							\
18081.92Skamil{									\
18091.92Skamil									\
18101.92Skamil	traceme_vfork_signalignored_crash(sig);				\
18111.92Skamil}
18121.92Skamil
18131.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_trap,
18141.92Skamil    SIGTRAP)
18151.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_segv,
18161.92Skamil    SIGSEGV)
18171.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_ill,
18181.92Skamil    SIGILL)
18191.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_fpe,
18201.92Skamil    SIGFPE)
18211.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_bus,
18221.92Skamil    SIGBUS)
18231.92Skamil
18241.92Skamil/// ----------------------------------------------------------------------------
18251.92Skamil
18261.96Skamilstatic void
18271.96Skamiltraceme_vfork_exec(bool masked, bool ignored)
18281.43Skamil{
18291.43Skamil	const int sigval = SIGTRAP;
18301.43Skamil	pid_t child, wpid;
18311.43Skamil#if defined(TWAIT_HAVE_STATUS)
18321.43Skamil	int status;
18331.43Skamil#endif
18341.96Skamil	struct sigaction sa;
18351.61Skre	struct ptrace_siginfo info;
18361.96Skamil	sigset_t intmask;
18371.96Skamil	struct kinfo_proc2 kp;
18381.96Skamil	size_t len = sizeof(kp);
18391.96Skamil
18401.96Skamil	int name[6];
18411.96Skamil	const size_t namelen = __arraycount(name);
18421.96Skamil	ki_sigset_t kp_sigmask;
18431.96Skamil	ki_sigset_t kp_sigignore;
18441.43Skamil
18451.43Skamil	memset(&info, 0, sizeof(info));
18461.43Skamil
18471.43Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
18481.43Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
18491.43Skamil	if (child == 0) {
18501.43Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
18511.43Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
18521.43Skamil
18531.96Skamil		if (masked) {
18541.96Skamil			sigemptyset(&intmask);
18551.96Skamil			sigaddset(&intmask, sigval);
18561.96Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
18571.96Skamil		}
18581.96Skamil
18591.96Skamil		if (ignored) {
18601.96Skamil			memset(&sa, 0, sizeof(sa));
18611.96Skamil			sa.sa_handler = SIG_IGN;
18621.96Skamil			sigemptyset(&sa.sa_mask);
18631.96Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
18641.96Skamil		}
18651.96Skamil
18661.43Skamil		DPRINTF("Before calling execve(2) from child\n");
18671.43Skamil		execlp("/bin/echo", "/bin/echo", NULL);
18681.43Skamil
18691.43Skamil		/* NOTREACHED */
18701.43Skamil		FORKEE_ASSERTX(0 && "Not reached");
18711.43Skamil	}
18721.43Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
18731.43Skamil
18741.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18751.43Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
18761.43Skamil
18771.43Skamil	validate_status_stopped(status, sigval);
18781.43Skamil
18791.96Skamil	name[0] = CTL_KERN,
18801.96Skamil	name[1] = KERN_PROC2,
18811.96Skamil	name[2] = KERN_PROC_PID;
18821.96Skamil	name[3] = getpid();
18831.96Skamil	name[4] = sizeof(kp);
18841.96Skamil	name[5] = 1;
18851.96Skamil
18861.96Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
18871.96Skamil
18881.96Skamil	if (masked)
18891.96Skamil		kp_sigmask = kp.p_sigmask;
18901.96Skamil
18911.96Skamil	if (ignored)
18921.96Skamil		kp_sigignore = kp.p_sigignore;
18931.96Skamil
18941.96Skamil	name[3] = getpid();
18951.96Skamil
18961.96Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
18971.96Skamil
18981.96Skamil	if (masked) {
18991.96Skamil		DPRINTF("kp_sigmask="
19001.96Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19011.96Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
19021.96Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
19031.96Skamil
19041.96Skamil	        DPRINTF("kp.p_sigmask="
19051.96Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19061.96Skamil	            kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
19071.96Skamil	            kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
19081.96Skamil
19091.96Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
19101.96Skamil		    sizeof(kp_sigmask)));
19111.96Skamil	}
19121.96Skamil
19131.96Skamil	if (ignored) {
19141.96Skamil		DPRINTF("kp_sigignore="
19151.96Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19161.96Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
19171.96Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
19181.96Skamil
19191.96Skamil	        DPRINTF("kp.p_sigignore="
19201.96Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19211.96Skamil	            kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
19221.96Skamil	            kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
19231.96Skamil
19241.96Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
19251.96Skamil		    sizeof(kp_sigignore)));
19261.96Skamil	}
19271.96Skamil
19281.43Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
19291.61Skre	SYSCALL_REQUIRE(
19301.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
19311.43Skamil
19321.43Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
19331.43Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
19341.43Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
19351.43Skamil	    info.psi_siginfo.si_errno);
19361.43Skamil
19371.43Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
19381.43Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
19391.43Skamil
19401.43Skamil	DPRINTF("Before resuming the child process where it left off and "
19411.43Skamil	    "without signal to be sent\n");
19421.43Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
19431.43Skamil
19441.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
19451.43Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
19461.43Skamil
19471.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
19481.43Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
19491.43Skamil}
19501.43Skamil
19511.96Skamil#define TRACEME_VFORK_EXEC(test, masked, ignored)			\
19521.96SkamilATF_TC(test);								\
19531.96SkamilATF_TC_HEAD(test, tc)							\
19541.96Skamil{									\
19551.96Skamil	atf_tc_set_md_var(tc, "descr",					\
19561.96Skamil	    "Verify PT_TRACE_ME followed by exec(3) in a vfork(2)ed "	\
19571.96Skamil	    "child%s%s", masked ? " with masked signal" : "",		\
19581.96Skamil	    masked ? " with ignored signal" : "");			\
19591.96Skamil}									\
19601.96Skamil									\
19611.96SkamilATF_TC_BODY(test, tc)							\
19621.96Skamil{									\
19631.96Skamil									\
19641.96Skamil	traceme_vfork_exec(masked, ignored);				\
19651.96Skamil}
19661.96Skamil
19671.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_exec, false, false)
19681.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalmasked_exec, true, false)
19691.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalignored_exec, false, true)
19701.96Skamil
19711.43Skamil/// ----------------------------------------------------------------------------
19721.43Skamil
19731.1Skamil#if defined(TWAIT_HAVE_PID)
19741.51Skamilstatic void
19751.94Skamilunrelated_tracer_sees_crash(int sig, bool masked, bool ignored)
19761.59Skamil{
19771.94Skamil	const int sigval = SIGSTOP;
19781.59Skamil	struct msg_fds parent_tracee, parent_tracer;
19791.59Skamil	const int exitval = 10;
19801.59Skamil	pid_t tracee, tracer, wpid;
19811.59Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
19821.59Skamil#if defined(TWAIT_HAVE_STATUS)
19831.59Skamil	int status;
19841.59Skamil#endif
19851.94Skamil	struct sigaction sa;
19861.59Skamil	struct ptrace_siginfo info;
19871.94Skamil	sigset_t intmask;
19881.94Skamil	struct kinfo_proc2 kp;
19891.94Skamil	size_t len = sizeof(kp);
19901.94Skamil
19911.94Skamil	int name[6];
19921.94Skamil	const size_t namelen = __arraycount(name);
19931.94Skamil	ki_sigset_t kp_sigmask;
19941.94Skamil	ki_sigset_t kp_sigignore;
19951.61Skre
19961.71Skamil#ifndef PTRACE_ILLEGAL_ASM
19971.71Skamil	if (sig == SIGILL)
19981.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
19991.71Skamil#endif
20001.71Skamil
20011.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
20021.114Skamil		atf_tc_skip("FP exceptions are not supported");
20031.114Skamil
20041.59Skamil	memset(&info, 0, sizeof(info));
20051.59Skamil
20061.59Skamil	DPRINTF("Spawn tracee\n");
20071.59Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
20081.59Skamil	tracee = atf_utils_fork();
20091.59Skamil	if (tracee == 0) {
20101.59Skamil		// Wait for parent to let us crash
20111.59Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
20121.61Skre
20131.94Skamil		if (masked) {
20141.94Skamil			sigemptyset(&intmask);
20151.94Skamil			sigaddset(&intmask, sig);
20161.94Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
20171.94Skamil		}
20181.94Skamil
20191.94Skamil		if (ignored) {
20201.94Skamil			memset(&sa, 0, sizeof(sa));
20211.94Skamil			sa.sa_handler = SIG_IGN;
20221.94Skamil			sigemptyset(&sa.sa_mask);
20231.94Skamil			FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
20241.94Skamil		}
20251.94Skamil
20261.94Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
20271.94Skamil		FORKEE_ASSERT(raise(sigval) == 0);
20281.94Skamil
20291.59Skamil		DPRINTF("Before executing a trap\n");
20301.59Skamil		switch (sig) {
20311.59Skamil		case SIGTRAP:
20321.59Skamil			trigger_trap();
20331.59Skamil			break;
20341.59Skamil		case SIGSEGV:
20351.59Skamil			trigger_segv();
20361.59Skamil			break;
20371.59Skamil		case SIGILL:
20381.59Skamil			trigger_ill();
20391.59Skamil			break;
20401.59Skamil		case SIGFPE:
20411.59Skamil			trigger_fpe();
20421.59Skamil			break;
20431.59Skamil		case SIGBUS:
20441.59Skamil			trigger_bus();
20451.59Skamil			break;
20461.59Skamil		default:
20471.59Skamil			/* NOTREACHED */
20481.59Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
20491.59Skamil		}
20501.59Skamil
20511.59Skamil		/* NOTREACHED */
20521.59Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
20531.59Skamil	}
20541.59Skamil
20551.59Skamil	DPRINTF("Spawn debugger\n");
20561.59Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
20571.59Skamil	tracer = atf_utils_fork();
20581.59Skamil	if (tracer == 0) {
20591.59Skamil		/* Fork again and drop parent to reattach to PID 1 */
20601.59Skamil		tracer = atf_utils_fork();
20611.59Skamil		if (tracer != 0)
20621.61Skre			_exit(exitval);
20631.59Skamil
20641.59Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
20651.59Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
20661.59Skamil
20671.59Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
20681.59Skamil		FORKEE_REQUIRE_SUCCESS(
20691.59Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
20701.59Skamil
20711.59Skamil		forkee_status_stopped(status, SIGSTOP);
20721.59Skamil
20731.94Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
20741.94Skamil		    "traced process\n");
20751.94Skamil		SYSCALL_REQUIRE(
20761.94Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
20771.94Skamil
20781.94Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
20791.94Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
20801.94Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
20811.94Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
20821.94Skamil
20831.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
20841.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
20851.94Skamil
20861.59Skamil		/* Resume tracee with PT_CONTINUE */
20871.59Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
20881.59Skamil
20891.59Skamil		/* Inform parent that tracer has attached to tracee */
20901.59Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
20911.59Skamil
20921.59Skamil		/* Wait for parent to tell use that tracee should have exited */
20931.59Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
20941.59Skamil
20951.59Skamil		/* Wait for tracee and assert that it exited */
20961.59Skamil		FORKEE_REQUIRE_SUCCESS(
20971.59Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
20981.59Skamil
20991.94Skamil		forkee_status_stopped(status, sigval);
21001.94Skamil
21011.94Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
21021.94Skamil		    "traced process\n");
21031.94Skamil		SYSCALL_REQUIRE(
21041.94Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
21051.94Skamil
21061.94Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
21071.94Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
21081.94Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
21091.94Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
21101.94Skamil
21111.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
21121.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
21131.94Skamil
21141.94Skamil		name[0] = CTL_KERN,
21151.94Skamil		name[1] = KERN_PROC2,
21161.94Skamil		name[2] = KERN_PROC_PID;
21171.94Skamil		name[3] = tracee;
21181.94Skamil		name[4] = sizeof(kp);
21191.94Skamil		name[5] = 1;
21201.94Skamil
21211.94Skamil		FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
21221.94Skamil
21231.94Skamil		if (masked)
21241.94Skamil			kp_sigmask = kp.p_sigmask;
21251.94Skamil
21261.94Skamil		if (ignored)
21271.94Skamil			kp_sigignore = kp.p_sigignore;
21281.94Skamil
21291.94Skamil		/* Resume tracee with PT_CONTINUE */
21301.94Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
21311.94Skamil
21321.94Skamil		/* Wait for tracee and assert that it exited */
21331.94Skamil		FORKEE_REQUIRE_SUCCESS(
21341.94Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
21351.94Skamil
21361.93Skamil		forkee_status_stopped(status, sig);
21371.59Skamil
21381.59Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
21391.61Skre		    "traced process\n");
21401.61Skre		SYSCALL_REQUIRE(
21411.61Skre		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
21421.59Skamil
21431.59Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
21441.59Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
21451.61Skre		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
21461.61Skre		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
21471.59Skamil
21481.93Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sig);
21491.94Skamil
21501.94Skamil		FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
21511.94Skamil
21521.94Skamil		if (masked) {
21531.94Skamil			DPRINTF("kp_sigmask="
21541.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21551.94Skamil			    PRIx32 "\n",
21561.94Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
21571.94Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
21581.94Skamil
21591.94Skamil			DPRINTF("kp.p_sigmask="
21601.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21611.94Skamil			    PRIx32 "\n",
21621.94Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
21631.94Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
21641.94Skamil
21651.94Skamil			FORKEE_ASSERTX(!memcmp(&kp_sigmask, &kp.p_sigmask,
21661.94Skamil			    sizeof(kp_sigmask)));
21671.94Skamil		}
21681.94Skamil
21691.94Skamil		if (ignored) {
21701.94Skamil			DPRINTF("kp_sigignore="
21711.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21721.94Skamil			    PRIx32 "\n",
21731.94Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
21741.94Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
21751.94Skamil
21761.94Skamil			DPRINTF("kp.p_sigignore="
21771.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21781.94Skamil			    PRIx32 "\n",
21791.94Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
21801.94Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
21811.94Skamil
21821.94Skamil			FORKEE_ASSERTX(!memcmp(&kp_sigignore, &kp.p_sigignore,
21831.94Skamil			    sizeof(kp_sigignore)));
21841.94Skamil		}
21851.94Skamil
21861.59Skamil		switch (sig) {
21871.59Skamil		case SIGTRAP:
21881.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
21891.59Skamil			break;
21901.59Skamil		case SIGSEGV:
21911.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
21921.59Skamil			break;
21931.71Skamil		case SIGILL:
21941.113Skamil			FORKEE_ASSERT(info.psi_siginfo.si_code >= ILL_ILLOPC &&
21951.112Skamil			            info.psi_siginfo.si_code <= ILL_BADSTK);
21961.71Skamil			break;
21971.59Skamil		case SIGFPE:
21981.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
21991.59Skamil			break;
22001.59Skamil		case SIGBUS:
22011.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
22021.59Skamil			break;
22031.59Skamil		}
22041.59Skamil
22051.59Skamil		FORKEE_ASSERT(ptrace(PT_KILL, tracee, NULL, 0) != -1);
22061.59Skamil		DPRINTF("Before calling %s() for the tracee\n", TWAIT_FNAME);
22071.93Skamil		FORKEE_REQUIRE_SUCCESS(
22081.61Skre		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
22091.59Skamil
22101.93Skamil		forkee_status_signaled(status, SIGKILL, 0);
22111.59Skamil
22121.71Skamil		/* Inform parent that tracer is exiting normally */
22131.71Skamil		CHILD_TO_PARENT("tracer done", parent_tracer, msg);
22141.71Skamil
22151.59Skamil		DPRINTF("Before exiting of the tracer process\n");
22161.59Skamil		_exit(0 /* collect by initproc */);
22171.59Skamil	}
22181.59Skamil
22191.59Skamil	DPRINTF("Wait for the tracer process (direct child) to exit "
22201.59Skamil	    "calling %s()\n", TWAIT_FNAME);
22211.59Skamil	TWAIT_REQUIRE_SUCCESS(
22221.59Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
22231.59Skamil
22241.59Skamil	validate_status_exited(status, exitval);
22251.59Skamil
22261.59Skamil	DPRINTF("Wait for the non-exited tracee process with %s()\n",
22271.59Skamil	    TWAIT_FNAME);
22281.59Skamil	TWAIT_REQUIRE_SUCCESS(
22291.59Skamil	    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
22301.59Skamil
22311.59Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
22321.59Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
22331.59Skamil
22341.59Skamil	DPRINTF("Resume the tracee and let it crash\n");
22351.59Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
22361.59Skamil
22371.59Skamil	DPRINTF("Resume the tracer and let it detect crashed tracee\n");
22381.59Skamil	PARENT_TO_CHILD("Message 2", parent_tracer, msg);
22391.59Skamil
22401.59Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
22411.59Skamil	    TWAIT_FNAME);
22421.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
22431.59Skamil
22441.59Skamil	validate_status_signaled(status, SIGKILL, 0);
22451.59Skamil
22461.71Skamil	DPRINTF("Await normal exit of tracer\n");
22471.71Skamil	PARENT_FROM_CHILD("tracer done", parent_tracer, msg);
22481.71Skamil
22491.59Skamil	msg_close(&parent_tracer);
22501.59Skamil	msg_close(&parent_tracee);
22511.59Skamil}
22521.59Skamil
22531.61Skre#define UNRELATED_TRACER_SEES_CRASH(test, sig)				\
22541.61SkreATF_TC(test);								\
22551.61SkreATF_TC_HEAD(test, tc)							\
22561.61Skre{									\
22571.61Skre	atf_tc_set_md_var(tc, "descr",					\
22581.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
22591.94Skamil	    "the debuggee");						\
22601.61Skre}									\
22611.61Skre									\
22621.61SkreATF_TC_BODY(test, tc)							\
22631.61Skre{									\
22641.61Skre									\
22651.94Skamil	unrelated_tracer_sees_crash(sig, false, false);			\
22661.59Skamil}
22671.59Skamil
22681.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_trap, SIGTRAP)
22691.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_segv, SIGSEGV)
22701.71SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_ill, SIGILL)
22711.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_fpe, SIGFPE)
22721.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_bus, SIGBUS)
22731.94Skamil
22741.94Skamil#define UNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(test, sig)		\
22751.94SkamilATF_TC(test);								\
22761.94SkamilATF_TC_HEAD(test, tc)							\
22771.94Skamil{									\
22781.94Skamil	atf_tc_set_md_var(tc, "descr",					\
22791.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
22801.94Skamil	    "the debuggee with masked signal");				\
22811.94Skamil}									\
22821.94Skamil									\
22831.94SkamilATF_TC_BODY(test, tc)							\
22841.94Skamil{									\
22851.94Skamil									\
22861.94Skamil	unrelated_tracer_sees_crash(sig, true, false);			\
22871.94Skamil}
22881.94Skamil
22891.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22901.94Skamil    unrelated_tracer_sees_signalmasked_crash_trap, SIGTRAP)
22911.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22921.94Skamil    unrelated_tracer_sees_signalmasked_crash_segv, SIGSEGV)
22931.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22941.94Skamil    unrelated_tracer_sees_signalmasked_crash_ill, SIGILL)
22951.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22961.94Skamil    unrelated_tracer_sees_signalmasked_crash_fpe, SIGFPE)
22971.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22981.94Skamil    unrelated_tracer_sees_signalmasked_crash_bus, SIGBUS)
22991.94Skamil
23001.94Skamil#define UNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(test, sig)		\
23011.94SkamilATF_TC(test);								\
23021.94SkamilATF_TC_HEAD(test, tc)							\
23031.94Skamil{									\
23041.94Skamil	atf_tc_set_md_var(tc, "descr",					\
23051.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
23061.94Skamil	    "the debuggee with signal ignored");			\
23071.94Skamil}									\
23081.94Skamil									\
23091.94SkamilATF_TC_BODY(test, tc)							\
23101.94Skamil{									\
23111.94Skamil									\
23121.94Skamil	unrelated_tracer_sees_crash(sig, false, true);			\
23131.94Skamil}
23141.94Skamil
23151.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23161.94Skamil    unrelated_tracer_sees_signalignored_crash_trap, SIGTRAP)
23171.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23181.94Skamil    unrelated_tracer_sees_signalignored_crash_segv, SIGSEGV)
23191.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23201.94Skamil    unrelated_tracer_sees_signalignored_crash_ill, SIGILL)
23211.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23221.94Skamil    unrelated_tracer_sees_signalignored_crash_fpe, SIGFPE)
23231.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23241.94Skamil    unrelated_tracer_sees_signalignored_crash_bus, SIGBUS)
23251.59Skamil#endif
23261.59Skamil
23271.59Skamil/// ----------------------------------------------------------------------------
23281.59Skamil
23291.59Skamil#if defined(TWAIT_HAVE_PID)
23301.59Skamilstatic void
23311.67Skamiltracer_sees_terminaton_before_the_parent_raw(bool notimeout, bool unrelated,
23321.67Skamil                                             bool stopped)
23331.1Skamil{
23341.51Skamil	/*
23351.51Skamil	 * notimeout - disable timeout in await zombie function
23361.51Skamil	 * unrelated - attach from unrelated tracer reparented to initproc
23371.67Skamil	 * stopped - attach to a stopped process
23381.51Skamil	 */
23391.1Skamil
23401.1Skamil	struct msg_fds parent_tracee, parent_tracer;
23411.1Skamil	const int exitval_tracee = 5;
23421.1Skamil	const int exitval_tracer = 10;
23431.1Skamil	pid_t tracee, tracer, wpid;
23441.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
23451.1Skamil#if defined(TWAIT_HAVE_STATUS)
23461.1Skamil	int status;
23471.1Skamil#endif
23481.1Skamil
23491.67Skamil	/*
23501.67Skamil	 * Only a subset of options are supported.
23511.67Skamil	 */
23521.67Skamil	ATF_REQUIRE((!notimeout && !unrelated && !stopped) ||
23531.67Skamil	            (!notimeout && unrelated && !stopped) ||
23541.67Skamil	            (notimeout && !unrelated && !stopped) ||
23551.67Skamil	            (!notimeout && unrelated && stopped));
23561.67Skamil
23571.13Schristos	DPRINTF("Spawn tracee\n");
23581.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
23591.1Skamil	tracee = atf_utils_fork();
23601.1Skamil	if (tracee == 0) {
23611.67Skamil		if (stopped) {
23621.67Skamil			DPRINTF("Stop self PID %d\n", getpid());
23631.67Skamil			raise(SIGSTOP);
23641.67Skamil		}
23651.67Skamil
23661.1Skamil		// Wait for parent to let us exit
23671.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
23681.1Skamil		_exit(exitval_tracee);
23691.1Skamil	}
23701.1Skamil
23711.13Schristos	DPRINTF("Spawn debugger\n");
23721.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
23731.1Skamil	tracer = atf_utils_fork();
23741.1Skamil	if (tracer == 0) {
23751.51Skamil		if(unrelated) {
23761.51Skamil			/* Fork again and drop parent to reattach to PID 1 */
23771.51Skamil			tracer = atf_utils_fork();
23781.51Skamil			if (tracer != 0)
23791.51Skamil				_exit(exitval_tracer);
23801.51Skamil		}
23811.51Skamil
23821.67Skamil		if (stopped) {
23831.67Skamil			DPRINTF("Await for a stopped parent PID %d\n", tracee);
23841.67Skamil			await_stopped(tracee);
23851.67Skamil		}
23861.67Skamil
23871.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
23881.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
23891.1Skamil
23901.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
23911.1Skamil		FORKEE_REQUIRE_SUCCESS(
23921.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
23931.1Skamil
23941.1Skamil		forkee_status_stopped(status, SIGSTOP);
23951.1Skamil
23961.1Skamil		/* Resume tracee with PT_CONTINUE */
23971.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
23981.1Skamil
23991.1Skamil		/* Inform parent that tracer has attached to tracee */
24001.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
24011.1Skamil
24021.1Skamil		/* Wait for parent to tell use that tracee should have exited */
24031.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
24041.1Skamil
24051.1Skamil		/* Wait for tracee and assert that it exited */
24061.1Skamil		FORKEE_REQUIRE_SUCCESS(
24071.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
24081.1Skamil
24091.1Skamil		forkee_status_exited(status, exitval_tracee);
24101.13Schristos		DPRINTF("Tracee %d exited with %d\n", tracee, exitval_tracee);
24111.1Skamil
24121.13Schristos		DPRINTF("Before exiting of the tracer process\n");
24131.51Skamil		_exit(unrelated ? 0 /* collect by initproc */ : exitval_tracer);
24141.51Skamil	}
24151.51Skamil
24161.51Skamil	if (unrelated) {
24171.51Skamil		DPRINTF("Wait for the tracer process (direct child) to exit "
24181.51Skamil		    "calling %s()\n", TWAIT_FNAME);
24191.51Skamil		TWAIT_REQUIRE_SUCCESS(
24201.51Skamil		    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
24211.51Skamil
24221.51Skamil		validate_status_exited(status, exitval_tracer);
24231.51Skamil
24241.51Skamil		DPRINTF("Wait for the non-exited tracee process with %s()\n",
24251.51Skamil		    TWAIT_FNAME);
24261.51Skamil		TWAIT_REQUIRE_SUCCESS(
24271.51Skamil		    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
24281.1Skamil	}
24291.1Skamil
24301.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
24311.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
24321.1Skamil
24331.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
24341.1Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
24351.1Skamil
24361.13Schristos	DPRINTF("Detect that tracee is zombie\n");
24371.51Skamil	if (notimeout)
24381.26Skamil		await_zombie_raw(tracee, 0);
24391.26Skamil	else
24401.26Skamil		await_zombie(tracee);
24411.1Skamil
24421.13Schristos	DPRINTF("Assert that there is no status about tracee %d - "
24431.1Skamil	    "Tracer must detect zombie first - calling %s()\n", tracee,
24441.1Skamil	    TWAIT_FNAME);
24451.1Skamil	TWAIT_REQUIRE_SUCCESS(
24461.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
24471.1Skamil
24481.51Skamil	if (unrelated) {
24491.51Skamil		DPRINTF("Resume the tracer and let it detect exited tracee\n");
24501.51Skamil		PARENT_TO_CHILD("Message 2", parent_tracer, msg);
24511.51Skamil	} else {
24521.51Skamil		DPRINTF("Tell the tracer child should have exited\n");
24531.51Skamil		PARENT_TO_CHILD("wait for tracee exit", parent_tracer,  msg);
24541.51Skamil		DPRINTF("Wait for tracer to finish its job and exit - calling "
24551.59Skamil			"%s()\n", TWAIT_FNAME);
24561.51Skamil
24571.51Skamil		DPRINTF("Wait from tracer child to complete waiting for "
24581.59Skamil			"tracee\n");
24591.51Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
24601.51Skamil		    tracer);
24611.1Skamil
24621.51Skamil		validate_status_exited(status, exitval_tracer);
24631.51Skamil	}
24641.1Skamil
24651.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
24661.1Skamil	    TWAIT_FNAME);
24671.51Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
24681.1Skamil
24691.1Skamil	validate_status_exited(status, exitval_tracee);
24701.1Skamil
24711.1Skamil	msg_close(&parent_tracer);
24721.1Skamil	msg_close(&parent_tracee);
24731.1Skamil}
24741.26Skamil
24751.51SkamilATF_TC(tracer_sees_terminaton_before_the_parent);
24761.51SkamilATF_TC_HEAD(tracer_sees_terminaton_before_the_parent, tc)
24771.51Skamil{
24781.51Skamil	atf_tc_set_md_var(tc, "descr",
24791.51Skamil	    "Assert that tracer sees process termination before the parent");
24801.51Skamil}
24811.51Skamil
24821.51SkamilATF_TC_BODY(tracer_sees_terminaton_before_the_parent, tc)
24831.26Skamil{
24841.26Skamil
24851.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, false, false);
24861.26Skamil}
24871.26Skamil
24881.51SkamilATF_TC(tracer_sysctl_lookup_without_duplicates);
24891.51SkamilATF_TC_HEAD(tracer_sysctl_lookup_without_duplicates, tc)
24901.1Skamil{
24911.1Skamil	atf_tc_set_md_var(tc, "descr",
24921.51Skamil	    "Assert that await_zombie() in attach1 always finds a single "
24931.51Skamil	    "process and no other error is reported");
24941.1Skamil}
24951.1Skamil
24961.51SkamilATF_TC_BODY(tracer_sysctl_lookup_without_duplicates, tc)
24971.1Skamil{
24981.51Skamil	time_t start, end;
24991.51Skamil	double diff;
25001.51Skamil	unsigned long N = 0;
25011.1Skamil
25021.51Skamil	/*
25031.51Skamil	 * Reuse this test with tracer_sees_terminaton_before_the_parent_raw().
25041.51Skamil	 * This test body isn't specific to this race, however it's just good
25051.51Skamil	 * enough for this purposes, no need to invent a dedicated code flow.
25061.51Skamil	 */
25071.1Skamil
25081.51Skamil	start = time(NULL);
25091.51Skamil	while (true) {
25101.51Skamil		DPRINTF("Step: %lu\n", N);
25111.67Skamil		tracer_sees_terminaton_before_the_parent_raw(true, false,
25121.67Skamil		                                             false);
25131.51Skamil		end = time(NULL);
25141.51Skamil		diff = difftime(end, start);
25151.51Skamil		if (diff >= 5.0)
25161.51Skamil			break;
25171.51Skamil		++N;
25181.1Skamil	}
25191.51Skamil	DPRINTF("Iterations: %lu\n", N);
25201.51Skamil}
25211.1Skamil
25221.51SkamilATF_TC(unrelated_tracer_sees_terminaton_before_the_parent);
25231.51SkamilATF_TC_HEAD(unrelated_tracer_sees_terminaton_before_the_parent, tc)
25241.51Skamil{
25251.51Skamil	atf_tc_set_md_var(tc, "descr",
25261.51Skamil	    "Assert that tracer sees process termination before the parent");
25271.51Skamil}
25281.1Skamil
25291.51SkamilATF_TC_BODY(unrelated_tracer_sees_terminaton_before_the_parent, tc)
25301.51Skamil{
25311.1Skamil
25321.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, false);
25331.67Skamil}
25341.67Skamil
25351.67SkamilATF_TC(tracer_attach_to_unrelated_stopped_process);
25361.67SkamilATF_TC_HEAD(tracer_attach_to_unrelated_stopped_process, tc)
25371.67Skamil{
25381.67Skamil	atf_tc_set_md_var(tc, "descr",
25391.67Skamil	    "Assert that tracer can attach to an unrelated stopped process");
25401.67Skamil}
25411.67Skamil
25421.67SkamilATF_TC_BODY(tracer_attach_to_unrelated_stopped_process, tc)
25431.67Skamil{
25441.67Skamil
25451.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, true);
25461.1Skamil}
25471.1Skamil#endif
25481.1Skamil
25491.51Skamil/// ----------------------------------------------------------------------------
25501.51Skamil
25511.66Skamilstatic void
25521.66Skamilparent_attach_to_its_child(bool stopped)
25531.1Skamil{
25541.1Skamil	struct msg_fds parent_tracee;
25551.1Skamil	const int exitval_tracee = 5;
25561.1Skamil	pid_t tracee, wpid;
25571.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
25581.1Skamil#if defined(TWAIT_HAVE_STATUS)
25591.1Skamil	int status;
25601.1Skamil#endif
25611.1Skamil
25621.13Schristos	DPRINTF("Spawn tracee\n");
25631.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
25641.1Skamil	tracee = atf_utils_fork();
25651.1Skamil	if (tracee == 0) {
25661.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
25671.13Schristos		DPRINTF("Parent should now attach to tracee\n");
25681.1Skamil
25691.66Skamil		if (stopped) {
25701.66Skamil			DPRINTF("Stop self PID %d\n", getpid());
25711.66Skamil			SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
25721.66Skamil		}
25731.66Skamil
25741.1Skamil		CHILD_FROM_PARENT("Message 2", parent_tracee, msg);
25751.1Skamil		/* Wait for message from the parent */
25761.1Skamil		_exit(exitval_tracee);
25771.1Skamil	}
25781.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
25791.57Skamil
25801.66Skamil	if (stopped) {
25811.66Skamil		DPRINTF("Await for a stopped tracee PID %d\n", tracee);
25821.66Skamil		await_stopped(tracee);
25831.66Skamil	}
25841.66Skamil
25851.13Schristos	DPRINTF("Before calling PT_ATTACH for tracee %d\n", tracee);
25861.13Schristos	SYSCALL_REQUIRE(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
25871.1Skamil
25881.13Schristos	DPRINTF("Wait for the stopped tracee process with %s()\n",
25891.1Skamil	    TWAIT_FNAME);
25901.1Skamil	TWAIT_REQUIRE_SUCCESS(
25911.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
25921.1Skamil
25931.1Skamil	validate_status_stopped(status, SIGSTOP);
25941.1Skamil
25951.13Schristos	DPRINTF("Resume tracee with PT_CONTINUE\n");
25961.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
25971.1Skamil
25981.13Schristos	DPRINTF("Let the tracee exit now\n");
25991.1Skamil	PARENT_TO_CHILD("Message 2", parent_tracee, msg);
26001.1Skamil
26011.13Schristos	DPRINTF("Wait for tracee to exit with %s()\n", TWAIT_FNAME);
26021.1Skamil	TWAIT_REQUIRE_SUCCESS(
26031.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
26041.1Skamil
26051.1Skamil	validate_status_exited(status, exitval_tracee);
26061.1Skamil
26071.13Schristos	DPRINTF("Before calling %s() for tracee\n", TWAIT_FNAME);
26081.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
26091.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0));
26101.1Skamil
26111.1Skamil	msg_close(&parent_tracee);
26121.1Skamil}
26131.1Skamil
26141.66SkamilATF_TC(parent_attach_to_its_child);
26151.66SkamilATF_TC_HEAD(parent_attach_to_its_child, tc)
26161.66Skamil{
26171.66Skamil	atf_tc_set_md_var(tc, "descr",
26181.66Skamil	    "Assert that tracer parent can PT_ATTACH to its child");
26191.66Skamil}
26201.66Skamil
26211.66SkamilATF_TC_BODY(parent_attach_to_its_child, tc)
26221.66Skamil{
26231.66Skamil
26241.66Skamil	parent_attach_to_its_child(false);
26251.66Skamil}
26261.66Skamil
26271.66SkamilATF_TC(parent_attach_to_its_stopped_child);
26281.66SkamilATF_TC_HEAD(parent_attach_to_its_stopped_child, tc)
26291.66Skamil{
26301.66Skamil	atf_tc_set_md_var(tc, "descr",
26311.66Skamil	    "Assert that tracer parent can PT_ATTACH to its stopped child");
26321.66Skamil}
26331.66Skamil
26341.66SkamilATF_TC_BODY(parent_attach_to_its_stopped_child, tc)
26351.66Skamil{
26361.66Skamil
26371.66Skamil	parent_attach_to_its_child(true);
26381.66Skamil}
26391.66Skamil
26401.51Skamil/// ----------------------------------------------------------------------------
26411.51Skamil
26421.65Skamilstatic void
26431.65Skamilchild_attach_to_its_parent(bool stopped)
26441.1Skamil{
26451.1Skamil	struct msg_fds parent_tracee;
26461.1Skamil	const int exitval_tracer = 5;
26471.1Skamil	pid_t tracer, wpid;
26481.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
26491.1Skamil#if defined(TWAIT_HAVE_STATUS)
26501.1Skamil	int status;
26511.1Skamil#endif
26521.1Skamil
26531.13Schristos	DPRINTF("Spawn tracer\n");
26541.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
26551.1Skamil	tracer = atf_utils_fork();
26561.1Skamil	if (tracer == 0) {
26571.1Skamil		/* Wait for message from the parent */
26581.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
26591.1Skamil
26601.65Skamil		if (stopped) {
26611.65Skamil			DPRINTF("Await for a stopped parent PID %d\n",
26621.65Skamil			        getppid());
26631.65Skamil			await_stopped(getppid());
26641.65Skamil		}
26651.65Skamil
26661.13Schristos		DPRINTF("Attach to parent PID %d with PT_ATTACH from child\n",
26671.1Skamil		    getppid());
26681.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, getppid(), NULL, 0) != -1);
26691.1Skamil
26701.13Schristos		DPRINTF("Wait for the stopped parent process with %s()\n",
26711.1Skamil		    TWAIT_FNAME);
26721.1Skamil		FORKEE_REQUIRE_SUCCESS(
26731.1Skamil		    wpid = TWAIT_GENERIC(getppid(), &status, 0), getppid());
26741.1Skamil
26751.1Skamil		forkee_status_stopped(status, SIGSTOP);
26761.1Skamil
26771.13Schristos		DPRINTF("Resume parent with PT_DETACH\n");
26781.1Skamil		FORKEE_ASSERT(ptrace(PT_DETACH, getppid(), (void *)1, 0)
26791.1Skamil		    != -1);
26801.1Skamil
26811.1Skamil		/* Tell parent we are ready */
26821.1Skamil		CHILD_TO_PARENT("Message 1", parent_tracee, msg);
26831.1Skamil
26841.1Skamil		_exit(exitval_tracer);
26851.1Skamil	}
26861.1Skamil
26871.13Schristos	DPRINTF("Wait for the tracer to become ready\n");
26881.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
26891.65Skamil
26901.65Skamil	if (stopped) {
26911.65Skamil		DPRINTF("Stop self PID %d\n", getpid());
26921.65Skamil		SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
26931.65Skamil	}
26941.65Skamil
26951.13Schristos	DPRINTF("Allow the tracer to exit now\n");
26961.1Skamil	PARENT_FROM_CHILD("Message 1", parent_tracee, msg);
26971.1Skamil
26981.13Schristos	DPRINTF("Wait for tracer to exit with %s()\n", TWAIT_FNAME);
26991.1Skamil	TWAIT_REQUIRE_SUCCESS(
27001.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
27011.1Skamil
27021.1Skamil	validate_status_exited(status, exitval_tracer);
27031.1Skamil
27041.13Schristos	DPRINTF("Before calling %s() for tracer\n", TWAIT_FNAME);
27051.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
27061.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0));
27071.1Skamil
27081.1Skamil	msg_close(&parent_tracee);
27091.1Skamil}
27101.1Skamil
27111.65SkamilATF_TC(child_attach_to_its_parent);
27121.65SkamilATF_TC_HEAD(child_attach_to_its_parent, tc)
27131.65Skamil{
27141.65Skamil	atf_tc_set_md_var(tc, "descr",
27151.65Skamil	    "Assert that tracer child can PT_ATTACH to its parent");
27161.65Skamil}
27171.65Skamil
27181.65SkamilATF_TC_BODY(child_attach_to_its_parent, tc)
27191.65Skamil{
27201.65Skamil
27211.65Skamil	child_attach_to_its_parent(false);
27221.65Skamil}
27231.65Skamil
27241.65SkamilATF_TC(child_attach_to_its_stopped_parent);
27251.65SkamilATF_TC_HEAD(child_attach_to_its_stopped_parent, tc)
27261.65Skamil{
27271.65Skamil	atf_tc_set_md_var(tc, "descr",
27281.65Skamil	    "Assert that tracer child can PT_ATTACH to its stopped parent");
27291.65Skamil}
27301.65Skamil
27311.65SkamilATF_TC_BODY(child_attach_to_its_stopped_parent, tc)
27321.65Skamil{
27331.65Skamil	/*
27341.65Skamil	 * The ATF framework (atf-run) does not tolerate raise(SIGSTOP), as
27351.65Skamil	 * this causes a pipe (established from atf-run) to be broken.
27361.65Skamil	 * atf-run uses this mechanism to monitor whether a test is alive.
27371.65Skamil	 *
27381.65Skamil	 * As a workaround spawn this test as a subprocess.
27391.65Skamil	 */
27401.65Skamil
27411.65Skamil	const int exitval = 15;
27421.65Skamil	pid_t child, wpid;
27431.65Skamil#if defined(TWAIT_HAVE_STATUS)
27441.65Skamil	int status;
27451.65Skamil#endif
27461.65Skamil
27471.65Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
27481.65Skamil	if (child == 0) {
27491.65Skamil		child_attach_to_its_parent(true);
27501.65Skamil		_exit(exitval);
27511.65Skamil	} else {
27521.65Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
27531.65Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
27541.65Skamil
27551.65Skamil		validate_status_exited(status, exitval);
27561.65Skamil
27571.65Skamil		DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
27581.65Skamil		TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
27591.65Skamil	}
27601.65Skamil}
27611.65Skamil
27621.51Skamil/// ----------------------------------------------------------------------------
27631.51Skamil
27641.1Skamil#if defined(TWAIT_HAVE_PID)
27651.1Skamil
27661.51Skamilenum tracee_sees_its_original_parent_type {
27671.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
27681.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
27691.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS
27701.51Skamil};
27711.51Skamil
27721.51Skamilstatic void
27731.51Skamiltracee_sees_its_original_parent(enum tracee_sees_its_original_parent_type type)
27741.1Skamil{
27751.1Skamil	struct msg_fds parent_tracer, parent_tracee;
27761.1Skamil	const int exitval_tracee = 5;
27771.1Skamil	const int exitval_tracer = 10;
27781.1Skamil	pid_t parent, tracee, tracer, wpid;
27791.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
27801.1Skamil#if defined(TWAIT_HAVE_STATUS)
27811.1Skamil	int status;
27821.1Skamil#endif
27831.51Skamil	/* sysctl(3) - kinfo_proc2 */
27841.51Skamil	int name[CTL_MAXNAME];
27851.51Skamil	struct kinfo_proc2 kp;
27861.51Skamil	size_t len = sizeof(kp);
27871.51Skamil	unsigned int namelen;
27881.51Skamil
27891.51Skamil	/* procfs - status  */
27901.51Skamil	FILE *fp;
27911.51Skamil	struct stat st;
27921.51Skamil	const char *fname = "/proc/curproc/status";
27931.51Skamil	char s_executable[MAXPATHLEN];
27941.51Skamil	int s_pid, s_ppid;
27951.51Skamil	int rv;
27961.51Skamil
27971.51Skamil	if (type == TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS) {
27981.61Skre		SYSCALL_REQUIRE(
27991.61Skre		    (rv = stat(fname, &st)) == 0 || (errno == ENOENT));
28001.61Skre		if (rv != 0)
28011.51Skamil			atf_tc_skip("/proc/curproc/status not found");
28021.51Skamil	}
28031.1Skamil
28041.13Schristos	DPRINTF("Spawn tracee\n");
28051.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
28061.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
28071.1Skamil	tracee = atf_utils_fork();
28081.1Skamil	if (tracee == 0) {
28091.1Skamil		parent = getppid();
28101.1Skamil
28111.1Skamil		/* Emit message to the parent */
28121.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
28131.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
28141.1Skamil
28151.51Skamil		switch (type) {
28161.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID:
28171.51Skamil			FORKEE_ASSERT_EQ(parent, getppid());
28181.51Skamil			break;
28191.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2:
28201.51Skamil			namelen = 0;
28211.51Skamil			name[namelen++] = CTL_KERN;
28221.51Skamil			name[namelen++] = KERN_PROC2;
28231.51Skamil			name[namelen++] = KERN_PROC_PID;
28241.51Skamil			name[namelen++] = getpid();
28251.51Skamil			name[namelen++] = len;
28261.51Skamil			name[namelen++] = 1;
28271.51Skamil
28281.61Skre			FORKEE_ASSERT_EQ(
28291.61Skre			    sysctl(name, namelen, &kp, &len, NULL, 0), 0);
28301.51Skamil			FORKEE_ASSERT_EQ(parent, kp.p_ppid);
28311.51Skamil			break;
28321.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS:
28331.51Skamil			/*
28341.51Skamil			 * Format:
28351.51Skamil			 *  EXECUTABLE PID PPID ...
28361.51Skamil			 */
28371.51Skamil			FORKEE_ASSERT((fp = fopen(fname, "r")) != NULL);
28381.51Skamil			fscanf(fp, "%s %d %d", s_executable, &s_pid, &s_ppid);
28391.51Skamil			FORKEE_ASSERT_EQ(fclose(fp), 0);
28401.51Skamil			FORKEE_ASSERT_EQ(parent, s_ppid);
28411.51Skamil			break;
28421.51Skamil		}
28431.1Skamil
28441.1Skamil		_exit(exitval_tracee);
28451.1Skamil	}
28461.13Schristos	DPRINTF("Wait for child to record its parent identifier (pid)\n");
28471.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
28481.1Skamil
28491.13Schristos	DPRINTF("Spawn debugger\n");
28501.1Skamil	tracer = atf_utils_fork();
28511.1Skamil	if (tracer == 0) {
28521.1Skamil		/* No IPC to communicate with the child */
28531.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
28541.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
28551.1Skamil
28561.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
28571.1Skamil		FORKEE_REQUIRE_SUCCESS(
28581.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
28591.1Skamil
28601.1Skamil		forkee_status_stopped(status, SIGSTOP);
28611.1Skamil
28621.1Skamil		/* Resume tracee with PT_CONTINUE */
28631.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
28641.1Skamil
28651.1Skamil		/* Inform parent that tracer has attached to tracee */
28661.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
28671.1Skamil
28681.1Skamil		/* Wait for parent to tell use that tracee should have exited */
28691.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
28701.1Skamil
28711.1Skamil		/* Wait for tracee and assert that it exited */
28721.1Skamil		FORKEE_REQUIRE_SUCCESS(
28731.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
28741.1Skamil
28751.1Skamil		forkee_status_exited(status, exitval_tracee);
28761.1Skamil
28771.13Schristos		DPRINTF("Before exiting of the tracer process\n");
28781.1Skamil		_exit(exitval_tracer);
28791.1Skamil	}
28801.1Skamil
28811.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
28821.1Skamil	PARENT_FROM_CHILD("tracer ready",  parent_tracer, msg);
28831.1Skamil
28841.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
28851.1Skamil	PARENT_TO_CHILD("exit tracee",  parent_tracee, msg);
28861.1Skamil
28871.13Schristos	DPRINTF("Detect that tracee is zombie\n");
28881.1Skamil	await_zombie(tracee);
28891.1Skamil
28901.13Schristos	DPRINTF("Assert that there is no status about tracee - "
28911.1Skamil	    "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
28921.1Skamil	TWAIT_REQUIRE_SUCCESS(
28931.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
28941.1Skamil
28951.13Schristos	DPRINTF("Tell the tracer child should have exited\n");
28961.1Skamil	PARENT_TO_CHILD("wait for tracee exit",  parent_tracer, msg);
28971.1Skamil
28981.13Schristos	DPRINTF("Wait from tracer child to complete waiting for tracee\n");
28991.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
29001.1Skamil	    tracer);
29011.1Skamil
29021.1Skamil	validate_status_exited(status, exitval_tracer);
29031.1Skamil
29041.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
29051.1Skamil	    TWAIT_FNAME);
29061.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
29071.1Skamil	    tracee);
29081.1Skamil
29091.1Skamil	validate_status_exited(status, exitval_tracee);
29101.1Skamil
29111.1Skamil	msg_close(&parent_tracer);
29121.1Skamil	msg_close(&parent_tracee);
29131.1Skamil}
29141.1Skamil
29151.61Skre#define TRACEE_SEES_ITS_ORIGINAL_PARENT(test, type, descr)		\
29161.61SkreATF_TC(test);								\
29171.61SkreATF_TC_HEAD(test, tc)							\
29181.61Skre{									\
29191.61Skre	atf_tc_set_md_var(tc, "descr",					\
29201.61Skre	    "Assert that tracee sees its original parent when being traced " \
29211.61Skre	    "(check " descr ")");					\
29221.61Skre}									\
29231.61Skre									\
29241.61SkreATF_TC_BODY(test, tc)							\
29251.61Skre{									\
29261.61Skre									\
29271.61Skre	tracee_sees_its_original_parent(type);				\
29281.1Skamil}
29291.1Skamil
29301.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29311.51Skamil	tracee_sees_its_original_parent_getppid,
29321.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
29331.51Skamil	"getppid(2)");
29341.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29351.51Skamil	tracee_sees_its_original_parent_sysctl_kinfo_proc2,
29361.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
29371.51Skamil	"sysctl(3) and kinfo_proc2");
29381.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29391.51Skamil	tracee_sees_its_original_parent_procfs_status,
29401.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS,
29411.51Skamil	"the status file in procfs");
29421.1Skamil#endif
29431.1Skamil
29441.51Skamil/// ----------------------------------------------------------------------------
29451.1Skamil
29461.53Skamilstatic void
29471.53Skamileventmask_preserved(int event)
29481.1Skamil{
29491.1Skamil	const int exitval = 5;
29501.1Skamil	const int sigval = SIGSTOP;
29511.1Skamil	pid_t child, wpid;
29521.1Skamil#if defined(TWAIT_HAVE_STATUS)
29531.1Skamil	int status;
29541.1Skamil#endif
29551.1Skamil	ptrace_event_t set_event, get_event;
29561.1Skamil	const int len = sizeof(ptrace_event_t);
29571.1Skamil
29581.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
29591.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
29601.1Skamil	if (child == 0) {
29611.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
29621.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
29631.1Skamil
29641.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
29651.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
29661.1Skamil
29671.13Schristos		DPRINTF("Before exiting of the child process\n");
29681.1Skamil		_exit(exitval);
29691.1Skamil	}
29701.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
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_stopped(status, sigval);
29761.1Skamil
29771.53Skamil	set_event.pe_set_event = event;
29781.61Skre	SYSCALL_REQUIRE(
29791.61Skre	    ptrace(PT_SET_EVENT_MASK, child, &set_event, len) != -1);
29801.61Skre	SYSCALL_REQUIRE(
29811.61Skre	    ptrace(PT_GET_EVENT_MASK, child, &get_event, len) != -1);
29821.125Skamil	DPRINTF("set_event=%#x get_event=%#x\n", set_event.pe_set_event,
29831.125Skamil	    get_event.pe_set_event);
29841.1Skamil	ATF_REQUIRE(memcmp(&set_event, &get_event, len) == 0);
29851.1Skamil
29861.13Schristos	DPRINTF("Before resuming the child process where it left off and "
29871.1Skamil	    "without signal to be sent\n");
29881.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
29891.1Skamil
29901.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29911.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
29921.1Skamil
29931.1Skamil	validate_status_exited(status, exitval);
29941.1Skamil
29951.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29961.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
29971.1Skamil}
29981.1Skamil
29991.61Skre#define EVENTMASK_PRESERVED(test, event)				\
30001.61SkreATF_TC(test);								\
30011.61SkreATF_TC_HEAD(test, tc)							\
30021.61Skre{									\
30031.61Skre	atf_tc_set_md_var(tc, "descr",					\
30041.61Skre	    "Verify that eventmask " #event " is preserved");		\
30051.61Skre}									\
30061.61Skre									\
30071.61SkreATF_TC_BODY(test, tc)							\
30081.61Skre{									\
30091.61Skre									\
30101.61Skre	eventmask_preserved(event);					\
30111.1Skamil}
30121.1Skamil
30131.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_empty, 0)
30141.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_fork, PTRACE_FORK)
30151.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_vfork, PTRACE_VFORK)
30161.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_vfork_done, PTRACE_VFORK_DONE)
30171.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_lwp_create, PTRACE_LWP_CREATE)
30181.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_lwp_exit, PTRACE_LWP_EXIT)
30191.125SkamilEVENTMASK_PRESERVED(eventmask_preserved_posix_spawn, PTRACE_POSIX_SPAWN)
30201.1Skamil
30211.53Skamil/// ----------------------------------------------------------------------------
30221.1Skamil
30231.28Skamilstatic void
30241.125Skamilfork_body(const char *fn, bool trackspawn, bool trackfork, bool trackvfork,
30251.105Skamil    bool trackvforkdone)
30261.1Skamil{
30271.1Skamil	const int exitval = 5;
30281.125Skamil	const int exitval2 = 0; /* This matched exit status from /bin/echo */
30291.1Skamil	const int sigval = SIGSTOP;
30301.31Skamil	pid_t child, child2 = 0, wpid;
30311.1Skamil#if defined(TWAIT_HAVE_STATUS)
30321.1Skamil	int status;
30331.1Skamil#endif
30341.1Skamil	ptrace_state_t state;
30351.1Skamil	const int slen = sizeof(state);
30361.1Skamil	ptrace_event_t event;
30371.1Skamil	const int elen = sizeof(event);
30381.1Skamil
30391.124Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
30401.124Skamil
30411.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
30421.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
30431.1Skamil	if (child == 0) {
30441.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
30451.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
30461.1Skamil
30471.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
30481.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
30491.1Skamil
30501.125Skamil		if (strcmp(fn, "spawn") == 0) {
30511.124Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
30521.124Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
30531.125Skamil		} else {
30541.125Skamil			if (strcmp(fn, "fork") == 0) {
30551.125Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
30561.125Skamil			} else if (strcmp(fn, "vfork") == 0) {
30571.125Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
30581.125Skamil			}
30591.1Skamil
30601.124Skamil			if (child2 == 0)
30611.124Skamil				_exit(exitval2);
30621.124Skamil		}
30631.1Skamil		FORKEE_REQUIRE_SUCCESS
30641.1Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
30651.1Skamil
30661.1Skamil		forkee_status_exited(status, exitval2);
30671.1Skamil
30681.13Schristos		DPRINTF("Before exiting of the child process\n");
30691.1Skamil		_exit(exitval);
30701.1Skamil	}
30711.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
30721.1Skamil
30731.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
30741.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
30751.1Skamil
30761.1Skamil	validate_status_stopped(status, sigval);
30771.1Skamil
30781.125Skamil	DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
30791.125Skamil	    trackspawn ? "|PTRACE_POSIX_SPAWN" : "",
30801.61Skre	    trackfork ? "|PTRACE_FORK" : "",
30811.61Skre	    trackvfork ? "|PTRACE_VFORK" : "",
30821.61Skre	    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", child);
30831.30Skamil	event.pe_set_event = 0;
30841.125Skamil	if (trackspawn)
30851.125Skamil		event.pe_set_event |= PTRACE_POSIX_SPAWN;
30861.30Skamil	if (trackfork)
30871.30Skamil		event.pe_set_event |= PTRACE_FORK;
30881.30Skamil	if (trackvfork)
30891.30Skamil		event.pe_set_event |= PTRACE_VFORK;
30901.30Skamil	if (trackvforkdone)
30911.30Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
30921.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
30931.1Skamil
30941.13Schristos	DPRINTF("Before resuming the child process where it left off and "
30951.1Skamil	    "without signal to be sent\n");
30961.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
30971.1Skamil
30981.29Skamil#if defined(TWAIT_HAVE_PID)
30991.125Skamil	if ((trackspawn && strcmp(fn, "spawn") == 0) ||
31001.125Skamil	    (trackfork && strcmp(fn, "fork") == 0) ||
31011.125Skamil	    (trackvfork && strcmp(fn, "vfork") == 0)) {
31021.29Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
31031.61Skre		    child);
31041.29Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
31051.61Skre		    child);
31061.1Skamil
31071.29Skamil		validate_status_stopped(status, SIGTRAP);
31081.1Skamil
31091.61Skre		SYSCALL_REQUIRE(
31101.61Skre		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
31111.125Skamil		if (trackspawn && strcmp(fn, "spawn") == 0) {
31121.125Skamil			ATF_REQUIRE_EQ(
31131.125Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
31141.125Skamil			       PTRACE_POSIX_SPAWN);
31151.125Skamil		}
31161.125Skamil		if (trackfork && strcmp(fn, "fork") == 0) {
31171.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
31181.30Skamil			       PTRACE_FORK);
31191.30Skamil		}
31201.125Skamil		if (trackvfork && strcmp(fn, "vfork") == 0) {
31211.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
31221.30Skamil			       PTRACE_VFORK);
31231.30Skamil		}
31241.29Skamil
31251.29Skamil		child2 = state.pe_other_pid;
31261.30Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
31271.29Skamil
31281.29Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
31291.61Skre		    "%d\n", TWAIT_FNAME, child2, child);
31301.29Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
31311.29Skamil		    child2);
31321.1Skamil
31331.29Skamil		validate_status_stopped(status, SIGTRAP);
31341.1Skamil
31351.61Skre		SYSCALL_REQUIRE(
31361.61Skre		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
31371.125Skamil		if (trackspawn && strcmp(fn, "spawn") == 0) {
31381.125Skamil			ATF_REQUIRE_EQ(
31391.125Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
31401.125Skamil			       PTRACE_POSIX_SPAWN);
31411.125Skamil		}
31421.125Skamil		if (trackfork && strcmp(fn, "fork") == 0) {
31431.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
31441.30Skamil			       PTRACE_FORK);
31451.30Skamil		}
31461.125Skamil		if (trackvfork && strcmp(fn, "vfork") == 0) {
31471.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
31481.30Skamil			       PTRACE_VFORK);
31491.30Skamil		}
31501.30Skamil
31511.29Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
31521.29Skamil
31531.29Skamil		DPRINTF("Before resuming the forkee process where it left off "
31541.29Skamil		    "and without signal to be sent\n");
31551.61Skre		SYSCALL_REQUIRE(
31561.61Skre		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
31571.29Skamil
31581.29Skamil		DPRINTF("Before resuming the child process where it left off "
31591.61Skre		    "and without signal to be sent\n");
31601.29Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31611.30Skamil	}
31621.30Skamil#endif
31631.30Skamil
31641.125Skamil	if (trackvforkdone && strcmp(fn, "vfork") == 0) {
31651.30Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
31661.61Skre		    child);
31671.61Skre		TWAIT_REQUIRE_SUCCESS(
31681.61Skre		    wpid = TWAIT_GENERIC(child, &status, 0), child);
31691.30Skamil
31701.30Skamil		validate_status_stopped(status, SIGTRAP);
31711.30Skamil
31721.61Skre		SYSCALL_REQUIRE(
31731.61Skre		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
31741.30Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
31751.30Skamil
31761.30Skamil		child2 = state.pe_other_pid;
31771.30Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
31781.61Skre		    child2);
31791.30Skamil
31801.30Skamil		DPRINTF("Before resuming the child process where it left off "
31811.61Skre		    "and without signal to be sent\n");
31821.30Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31831.30Skamil	}
31841.29Skamil
31851.30Skamil#if defined(TWAIT_HAVE_PID)
31861.125Skamil	if ((trackspawn && strcmp(fn, "spawn") == 0) ||
31871.125Skamil	    (trackfork && strcmp(fn, "fork") == 0) ||
31881.125Skamil	    (trackvfork && strcmp(fn, "vfork") == 0)) {
31891.29Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
31901.61Skre		    "\n", TWAIT_FNAME);
31911.61Skre		TWAIT_REQUIRE_SUCCESS(
31921.61Skre		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
31931.29Skamil
31941.29Skamil		validate_status_exited(status, exitval2);
31951.29Skamil
31961.29Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
31971.61Skre		    "process\n", TWAIT_FNAME);
31981.29Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
31991.29Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
32001.29Skamil	}
32011.29Skamil#endif
32021.1Skamil
32031.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
32041.1Skamil	    "SIGCHLD\n", TWAIT_FNAME);
32051.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
32061.1Skamil
32071.1Skamil	validate_status_stopped(status, SIGCHLD);
32081.1Skamil
32091.13Schristos	DPRINTF("Before resuming the child process where it left off and "
32101.1Skamil	    "without signal to be sent\n");
32111.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
32121.1Skamil
32131.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
32141.1Skamil	    TWAIT_FNAME);
32151.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
32161.1Skamil
32171.1Skamil	validate_status_exited(status, exitval);
32181.1Skamil
32191.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
32201.1Skamil	    TWAIT_FNAME);
32211.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
32221.1Skamil}
32231.28Skamil
32241.125Skamil#define FORK_TEST(name,fun,tspawn,tfork,tvfork,tvforkdone)		\
32251.61SkreATF_TC(name);								\
32261.61SkreATF_TC_HEAD(name, tc)							\
32271.61Skre{									\
32281.125Skamil	atf_tc_set_md_var(tc, "descr", "Verify " fun "() "		\
32291.125Skamil	    "called with 0%s%s%s%s in EVENT_MASK",			\
32301.126Skamil	    tspawn ? "|PTRACE_POSIX_SPAWN" : "",			\
32311.105Skamil	    tfork ? "|PTRACE_FORK" : "",				\
32321.105Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
32331.105Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
32341.61Skre}									\
32351.61Skre									\
32361.61SkreATF_TC_BODY(name, tc)							\
32371.61Skre{									\
32381.61Skre									\
32391.125Skamil	fork_body(fun, tspawn, tfork, tvfork, tvforkdone);		\
32401.32Skamil}
32411.32Skamil
32421.125SkamilFORK_TEST(fork1, "fork", false, false, false, false)
32431.31Skamil#if defined(TWAIT_HAVE_PID)
32441.125SkamilFORK_TEST(fork2, "fork", false, true, false, false)
32451.125SkamilFORK_TEST(fork3, "fork", false, false, true, false)
32461.125SkamilFORK_TEST(fork4, "fork", false, true, true, false)
32471.31Skamil#endif
32481.125SkamilFORK_TEST(fork5, "fork", false, false, false, true)
32491.31Skamil#if defined(TWAIT_HAVE_PID)
32501.125SkamilFORK_TEST(fork6, "fork", false, true, false, true)
32511.125SkamilFORK_TEST(fork7, "fork", false, false, true, true)
32521.125SkamilFORK_TEST(fork8, "fork", false, true, true, true)
32531.125Skamil#endif
32541.125SkamilFORK_TEST(fork9, "fork", true, false, false, false)
32551.125Skamil#if defined(TWAIT_HAVE_PID)
32561.125SkamilFORK_TEST(fork10, "fork", true, true, false, false)
32571.125SkamilFORK_TEST(fork11, "fork", true, false, true, false)
32581.125SkamilFORK_TEST(fork12, "fork", true, true, true, false)
32591.125Skamil#endif
32601.125SkamilFORK_TEST(fork13, "fork", true, false, false, true)
32611.125Skamil#if defined(TWAIT_HAVE_PID)
32621.125SkamilFORK_TEST(fork14, "fork", true, true, false, true)
32631.125SkamilFORK_TEST(fork15, "fork", true, false, true, true)
32641.125SkamilFORK_TEST(fork16, "fork", true, true, true, true)
32651.31Skamil#endif
32661.1Skamil
32671.125SkamilFORK_TEST(vfork1, "vfork", false, false, false, false)
32681.31Skamil#if defined(TWAIT_HAVE_PID)
32691.125SkamilFORK_TEST(vfork2, "vfork", false, true, false, false)
32701.125SkamilFORK_TEST(vfork3, "vfork", false, false, true, false)
32711.125SkamilFORK_TEST(vfork4, "vfork", false, true, true, false)
32721.31Skamil#endif
32731.125SkamilFORK_TEST(vfork5, "vfork", false, false, false, true)
32741.31Skamil#if defined(TWAIT_HAVE_PID)
32751.125SkamilFORK_TEST(vfork6, "vfork", false, true, false, true)
32761.125SkamilFORK_TEST(vfork7, "vfork", false, false, true, true)
32771.125SkamilFORK_TEST(vfork8, "vfork", false, true, true, true)
32781.31Skamil#endif
32791.125SkamilFORK_TEST(vfork9, "vfork", true, false, false, false)
32801.125Skamil#if defined(TWAIT_HAVE_PID)
32811.125SkamilFORK_TEST(vfork10, "vfork", true, true, false, false)
32821.125SkamilFORK_TEST(vfork11, "vfork", true, false, true, false)
32831.125SkamilFORK_TEST(vfork12, "vfork", true, true, true, false)
32841.110Skamil#endif
32851.125SkamilFORK_TEST(vfork13, "vfork", true, false, false, true)
32861.124Skamil#if defined(TWAIT_HAVE_PID)
32871.125SkamilFORK_TEST(vfork14, "vfork", true, true, false, true)
32881.125SkamilFORK_TEST(vfork15, "vfork", true, false, true, true)
32891.125SkamilFORK_TEST(vfork16, "vfork", true, true, true, true)
32901.124Skamil#endif
32911.125Skamil
32921.125SkamilFORK_TEST(posix_spawn1, "spawn", false, false, false, false)
32931.125SkamilFORK_TEST(posix_spawn2, "spawn", false, true, false, false)
32941.125SkamilFORK_TEST(posix_spawn3, "spawn", false, false, true, false)
32951.125SkamilFORK_TEST(posix_spawn4, "spawn", false, true, true, false)
32961.125SkamilFORK_TEST(posix_spawn5, "spawn", false, false, false, true)
32971.125SkamilFORK_TEST(posix_spawn6, "spawn", false, true, false, true)
32981.125SkamilFORK_TEST(posix_spawn7, "spawn", false, false, true, true)
32991.125SkamilFORK_TEST(posix_spawn8, "spawn", false, true, true, true)
33001.124Skamil#if defined(TWAIT_HAVE_PID)
33011.125SkamilFORK_TEST(posix_spawn9, "spawn", true, false, false, false)
33021.125SkamilFORK_TEST(posix_spawn10, "spawn", true, true, false, false)
33031.125SkamilFORK_TEST(posix_spawn11, "spawn", true, false, true, false)
33041.125SkamilFORK_TEST(posix_spawn12, "spawn", true, true, true, false)
33051.125SkamilFORK_TEST(posix_spawn13, "spawn", true, false, false, true)
33061.125SkamilFORK_TEST(posix_spawn14, "spawn", true, true, false, true)
33071.125SkamilFORK_TEST(posix_spawn15, "spawn", true, false, true, true)
33081.125SkamilFORK_TEST(posix_spawn16, "spawn", true, true, true, true)
33091.124Skamil#endif
33101.124Skamil
33111.54Skamil/// ----------------------------------------------------------------------------
33121.31Skamil
33131.116Skamil#if defined(TWAIT_HAVE_PID)
33141.116Skamilstatic void
33151.126Skamilfork_detach_forker_body(const char *fn, bool kill_process)
33161.116Skamil{
33171.116Skamil	const int exitval = 5;
33181.126Skamil	const int exitval2 = 0; /* Matches exit value from /bin/echo */
33191.116Skamil	const int sigval = SIGSTOP;
33201.116Skamil	pid_t child, child2 = 0, wpid;
33211.116Skamil#if defined(TWAIT_HAVE_STATUS)
33221.116Skamil	int status;
33231.116Skamil#endif
33241.116Skamil	ptrace_state_t state;
33251.116Skamil	const int slen = sizeof(state);
33261.116Skamil	ptrace_event_t event;
33271.116Skamil	const int elen = sizeof(event);
33281.116Skamil
33291.116Skamil	int op;
33301.116Skamil
33311.126Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
33321.116Skamil
33331.116Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
33341.116Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
33351.116Skamil	if (child == 0) {
33361.116Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
33371.116Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
33381.116Skamil
33391.116Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
33401.116Skamil		FORKEE_ASSERT(raise(sigval) == 0);
33411.116Skamil
33421.126Skamil		if (strcmp(fn, "spawn") == 0) {
33431.126Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
33441.126Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
33451.126Skamil		} else  {
33461.126Skamil			if (strcmp(fn, "fork") == 0) {
33471.126Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
33481.126Skamil			} else {
33491.126Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
33501.126Skamil			}
33511.116Skamil
33521.126Skamil			if (child2 == 0)
33531.126Skamil				_exit(exitval2);
33541.126Skamil		}
33551.116Skamil
33561.116Skamil		FORKEE_REQUIRE_SUCCESS
33571.116Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
33581.116Skamil
33591.116Skamil		forkee_status_exited(status, exitval2);
33601.116Skamil
33611.116Skamil		DPRINTF("Before exiting of the child process\n");
33621.116Skamil		_exit(exitval);
33631.116Skamil	}
33641.116Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
33651.116Skamil
33661.116Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
33671.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
33681.116Skamil
33691.116Skamil	validate_status_stopped(status, sigval);
33701.116Skamil
33711.116Skamil	DPRINTF("Set EVENT_MASK for the child %d\n", child);
33721.126Skamil	event.pe_set_event = PTRACE_POSIX_SPAWN | PTRACE_FORK | PTRACE_VFORK
33731.126Skamil		| PTRACE_VFORK_DONE;
33741.116Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
33751.116Skamil
33761.116Skamil	DPRINTF("Before resuming the child process where it left off and "
33771.116Skamil	    "without signal to be sent\n");
33781.116Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
33791.116Skamil
33801.116Skamil	DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME, child);
33811.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
33821.116Skamil
33831.116Skamil	validate_status_stopped(status, SIGTRAP);
33841.116Skamil
33851.116Skamil	SYSCALL_REQUIRE(
33861.116Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
33871.126Skamil
33881.126Skamil	if (strcmp(fn, "spawn") == 0)
33891.126Skamil		op = PTRACE_POSIX_SPAWN;
33901.126Skamil	else if (strcmp(fn, "fork") == 0)
33911.126Skamil		op = PTRACE_FORK;
33921.126Skamil	else
33931.126Skamil		op = PTRACE_VFORK;
33941.126Skamil
33951.116Skamil	ATF_REQUIRE_EQ(state.pe_report_event & op, op);
33961.116Skamil
33971.116Skamil	child2 = state.pe_other_pid;
33981.116Skamil	DPRINTF("Reported ptrace event with forkee %d\n", child2);
33991.116Skamil
34001.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
34011.126Skamil	    strcmp(fn, "vfork") == 0)
34021.116Skamil		op = kill_process ? PT_KILL : PT_DETACH;
34031.116Skamil	else
34041.116Skamil		op = PT_CONTINUE;
34051.116Skamil	SYSCALL_REQUIRE(ptrace(op, child, (void *)1, 0) != -1);
34061.116Skamil
34071.116Skamil	DPRINTF("Before calling %s() for the forkee %d of the child %d\n",
34081.116Skamil	    TWAIT_FNAME, child2, child);
34091.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0), child2);
34101.116Skamil
34111.116Skamil	validate_status_stopped(status, SIGTRAP);
34121.116Skamil
34131.116Skamil	SYSCALL_REQUIRE(
34141.116Skamil	    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
34151.126Skamil	if (strcmp(fn, "spawn") == 0)
34161.126Skamil		op = PTRACE_POSIX_SPAWN;
34171.126Skamil	else if (strcmp(fn, "fork") == 0)
34181.126Skamil		op = PTRACE_FORK;
34191.126Skamil	else
34201.126Skamil		op = PTRACE_VFORK;
34211.126Skamil
34221.116Skamil	ATF_REQUIRE_EQ(state.pe_report_event & op, op);
34231.116Skamil	ATF_REQUIRE_EQ(state.pe_other_pid, child);
34241.116Skamil
34251.116Skamil	DPRINTF("Before resuming the forkee process where it left off "
34261.116Skamil	    "and without signal to be sent\n");
34271.116Skamil 	SYSCALL_REQUIRE(
34281.116Skamil	    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
34291.116Skamil
34301.126Skamil	if (strcmp(fn, "vforkdone") == 0) {
34311.116Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
34321.116Skamil		    child);
34331.116Skamil		TWAIT_REQUIRE_SUCCESS(
34341.116Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
34351.116Skamil
34361.116Skamil		validate_status_stopped(status, SIGTRAP);
34371.116Skamil
34381.116Skamil		SYSCALL_REQUIRE(
34391.116Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
34401.116Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
34411.116Skamil
34421.116Skamil		child2 = state.pe_other_pid;
34431.116Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
34441.116Skamil		    child2);
34451.116Skamil
34461.116Skamil		op = kill_process ? PT_KILL : PT_DETACH;
34471.116Skamil		DPRINTF("Before resuming the child process where it left off "
34481.116Skamil		    "and without signal to be sent\n");
34491.116Skamil		SYSCALL_REQUIRE(ptrace(op, child, (void *)1, 0) != -1);
34501.116Skamil	}
34511.116Skamil
34521.116Skamil	DPRINTF("Before calling %s() for the forkee - expected exited\n",
34531.116Skamil	    TWAIT_FNAME);
34541.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0), child2);
34551.116Skamil
34561.116Skamil	validate_status_exited(status, exitval2);
34571.116Skamil
34581.116Skamil	DPRINTF("Before calling %s() for the forkee - expected no process\n",
34591.116Skamil	    TWAIT_FNAME);
34601.116Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child2, &status, 0));
34611.116Skamil
34621.116Skamil	DPRINTF("Before calling %s() for the forkee - expected exited\n",
34631.116Skamil	    TWAIT_FNAME);
34641.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
34651.116Skamil
34661.116Skamil	if (kill_process) {
34671.116Skamil		validate_status_signaled(status, SIGKILL, 0);
34681.116Skamil	} else {
34691.116Skamil		validate_status_exited(status, exitval);
34701.116Skamil	}
34711.116Skamil
34721.116Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
34731.116Skamil	    TWAIT_FNAME);
34741.116Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
34751.116Skamil}
34761.116Skamil
34771.126Skamil#define FORK_DETACH_FORKER(name,event,kprocess)				\
34781.116SkamilATF_TC(name);								\
34791.116SkamilATF_TC_HEAD(name, tc)							\
34801.116Skamil{									\
34811.126Skamil	atf_tc_set_md_var(tc, "descr", "Verify %s " event,		\
34821.126Skamil	    kprocess ? "killed" : "detached");				\
34831.116Skamil}									\
34841.116Skamil									\
34851.116SkamilATF_TC_BODY(name, tc)							\
34861.116Skamil{									\
34871.116Skamil									\
34881.126Skamil	fork_detach_forker_body(event, kprocess);			\
34891.116Skamil}
34901.116Skamil
34911.126SkamilFORK_DETACH_FORKER(posix_spawn_detach_spawner, "spawn", false)
34921.126SkamilFORK_DETACH_FORKER(fork_detach_forker, "fork", false)
34931.126SkamilFORK_DETACH_FORKER(vfork_detach_vforker, "vfork", false)
34941.126SkamilFORK_DETACH_FORKER(vfork_detach_vforkerdone, "vforkdone", false)
34951.126Skamil
34961.126SkamilFORK_DETACH_FORKER(posix_spawn_kill_spawner, "spawn", true)
34971.126SkamilFORK_DETACH_FORKER(fork_kill_forker, "fork", true)
34981.126SkamilFORK_DETACH_FORKER(vfork_kill_vforker, "vfork", true)
34991.126SkamilFORK_DETACH_FORKER(vfork_kill_vforkerdone, "vforkdone", true)
35001.116Skamil#endif
35011.116Skamil
35021.116Skamil/// ----------------------------------------------------------------------------
35031.116Skamil
35041.108Skamilstatic void
35051.108Skamiltraceme_vfork_fork_body(pid_t (*fn)(void))
35061.108Skamil{
35071.108Skamil	const int exitval = 5;
35081.108Skamil	const int exitval2 = 15;
35091.108Skamil	pid_t child, child2 = 0, wpid;
35101.108Skamil#if defined(TWAIT_HAVE_STATUS)
35111.108Skamil	int status;
35121.108Skamil#endif
35131.108Skamil
35141.108Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
35151.108Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
35161.108Skamil	if (child == 0) {
35171.108Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
35181.108Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
35191.108Skamil
35201.108Skamil		FORKEE_ASSERT((child2 = (fn)()) != -1);
35211.108Skamil
35221.108Skamil		if (child2 == 0)
35231.108Skamil			_exit(exitval2);
35241.108Skamil
35251.108Skamil		FORKEE_REQUIRE_SUCCESS
35261.108Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
35271.108Skamil
35281.108Skamil		forkee_status_exited(status, exitval2);
35291.108Skamil
35301.108Skamil		DPRINTF("Before exiting of the child process\n");
35311.108Skamil		_exit(exitval);
35321.108Skamil	}
35331.108Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
35341.108Skamil
35351.108Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
35361.108Skamil	    TWAIT_FNAME);
35371.108Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
35381.108Skamil
35391.108Skamil	validate_status_exited(status, exitval);
35401.108Skamil
35411.108Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
35421.108Skamil	    TWAIT_FNAME);
35431.108Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
35441.108Skamil}
35451.108Skamil
35461.108Skamil#define TRACEME_VFORK_FORK_TEST(name,fun)				\
35471.108SkamilATF_TC(name);								\
35481.108SkamilATF_TC_HEAD(name, tc)							\
35491.108Skamil{									\
35501.108Skamil	atf_tc_set_md_var(tc, "descr", "Verify " #fun "(2) "		\
35511.108Skamil	    "called from vfork(2)ed child");				\
35521.108Skamil}									\
35531.108Skamil									\
35541.108SkamilATF_TC_BODY(name, tc)							\
35551.108Skamil{									\
35561.108Skamil									\
35571.108Skamil	traceme_vfork_fork_body(fun);					\
35581.108Skamil}
35591.108Skamil
35601.108SkamilTRACEME_VFORK_FORK_TEST(traceme_vfork_fork, fork)
35611.108SkamilTRACEME_VFORK_FORK_TEST(traceme_vfork_vfork, vfork)
35621.108Skamil
35631.108Skamil/// ----------------------------------------------------------------------------
35641.108Skamil
35651.54Skamilenum bytes_transfer_type {
35661.54Skamil	BYTES_TRANSFER_DATA,
35671.54Skamil	BYTES_TRANSFER_DATAIO,
35681.54Skamil	BYTES_TRANSFER_TEXT,
35691.54Skamil	BYTES_TRANSFER_TEXTIO,
35701.54Skamil	BYTES_TRANSFER_AUXV
35711.54Skamil};
35721.31Skamil
35731.54Skamilstatic int __used
35741.54Skamilbytes_transfer_dummy(int a, int b, int c, int d)
35751.54Skamil{
35761.54Skamil	int e, f, g, h;
35771.1Skamil
35781.54Skamil	a *= 4;
35791.54Skamil	b += 3;
35801.54Skamil	c -= 2;
35811.54Skamil	d /= 1;
35821.1Skamil
35831.54Skamil	e = strtol("10", NULL, 10);
35841.54Skamil	f = strtol("20", NULL, 10);
35851.54Skamil	g = strtol("30", NULL, 10);
35861.54Skamil	h = strtol("40", NULL, 10);
35871.1Skamil
35881.54Skamil	return (a + b * c - d) + (e * f - g / h);
35891.1Skamil}
35901.1Skamil
35911.54Skamilstatic void
35921.55Schristosbytes_transfer(int operation, size_t size, enum bytes_transfer_type type)
35931.1Skamil{
35941.1Skamil	const int exitval = 5;
35951.1Skamil	const int sigval = SIGSTOP;
35961.1Skamil	pid_t child, wpid;
35971.54Skamil	bool skip = false;
35981.1Skamil
35991.54Skamil	int lookup_me = 0;
36001.54Skamil	uint8_t lookup_me8 = 0;
36011.54Skamil	uint16_t lookup_me16 = 0;
36021.54Skamil	uint32_t lookup_me32 = 0;
36031.54Skamil	uint64_t lookup_me64 = 0;
36041.1Skamil
36051.54Skamil	int magic = 0x13579246;
36061.54Skamil	uint8_t magic8 = 0xab;
36071.54Skamil	uint16_t magic16 = 0x1234;
36081.54Skamil	uint32_t magic32 = 0x98765432;
36091.54Skamil	uint64_t magic64 = 0xabcdef0123456789;
36101.1Skamil
36111.54Skamil	struct ptrace_io_desc io;
36121.1Skamil#if defined(TWAIT_HAVE_STATUS)
36131.1Skamil	int status;
36141.1Skamil#endif
36151.60Skre	/* 513 is just enough, for the purposes of ATF it's good enough */
36161.60Skre	AuxInfo ai[513], *aip;
36171.55Schristos
36181.55Schristos	ATF_REQUIRE(size < sizeof(ai));
36191.1Skamil
36201.54Skamil	/* Prepare variables for .TEXT transfers */
36211.54Skamil	switch (type) {
36221.54Skamil	case BYTES_TRANSFER_TEXT:
36231.54Skamil		memcpy(&magic, bytes_transfer_dummy, sizeof(magic));
36241.54Skamil		break;
36251.54Skamil	case BYTES_TRANSFER_TEXTIO:
36261.54Skamil		switch (size) {
36271.54Skamil		case 8:
36281.54Skamil			memcpy(&magic8, bytes_transfer_dummy, sizeof(magic8));
36291.54Skamil			break;
36301.54Skamil		case 16:
36311.54Skamil			memcpy(&magic16, bytes_transfer_dummy, sizeof(magic16));
36321.54Skamil			break;
36331.54Skamil		case 32:
36341.54Skamil			memcpy(&magic32, bytes_transfer_dummy, sizeof(magic32));
36351.54Skamil			break;
36361.54Skamil		case 64:
36371.54Skamil			memcpy(&magic64, bytes_transfer_dummy, sizeof(magic64));
36381.54Skamil			break;
36391.54Skamil		}
36401.54Skamil		break;
36411.54Skamil	default:
36421.54Skamil		break;
36431.54Skamil	}
36441.1Skamil
36451.54Skamil	/* Prepare variables for PIOD and AUXV transfers */
36461.54Skamil	switch (type) {
36471.54Skamil	case BYTES_TRANSFER_TEXTIO:
36481.54Skamil	case BYTES_TRANSFER_DATAIO:
36491.54Skamil		io.piod_op = operation;
36501.54Skamil		switch (size) {
36511.54Skamil		case 8:
36521.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
36531.54Skamil			               (void *)bytes_transfer_dummy :
36541.54Skamil			               &lookup_me8;
36551.54Skamil			io.piod_addr = &lookup_me8;
36561.54Skamil			io.piod_len = sizeof(lookup_me8);
36571.54Skamil			break;
36581.54Skamil		case 16:
36591.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
36601.54Skamil			               (void *)bytes_transfer_dummy :
36611.54Skamil			               &lookup_me16;
36621.54Skamil			io.piod_addr = &lookup_me16;
36631.54Skamil			io.piod_len = sizeof(lookup_me16);
36641.54Skamil			break;
36651.54Skamil		case 32:
36661.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
36671.54Skamil			               (void *)bytes_transfer_dummy :
36681.54Skamil			               &lookup_me32;
36691.54Skamil			io.piod_addr = &lookup_me32;
36701.54Skamil			io.piod_len = sizeof(lookup_me32);
36711.54Skamil			break;
36721.54Skamil		case 64:
36731.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
36741.54Skamil			               (void *)bytes_transfer_dummy :
36751.54Skamil			               &lookup_me64;
36761.54Skamil			io.piod_addr = &lookup_me64;
36771.54Skamil			io.piod_len = sizeof(lookup_me64);
36781.54Skamil			break;
36791.54Skamil		default:
36801.54Skamil			break;
36811.54Skamil		}
36821.54Skamil		break;
36831.54Skamil	case BYTES_TRANSFER_AUXV:
36841.54Skamil		io.piod_op = operation;
36851.54Skamil		io.piod_offs = 0;
36861.54Skamil		io.piod_addr = ai;
36871.54Skamil		io.piod_len = size;
36881.54Skamil		break;
36891.54Skamil	default:
36901.54Skamil		break;
36911.1Skamil	}
36921.1Skamil
36931.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
36941.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
36951.1Skamil	if (child == 0) {
36961.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
36971.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
36981.1Skamil
36991.54Skamil		switch (type) {
37001.54Skamil		case BYTES_TRANSFER_DATA:
37011.54Skamil			switch (operation) {
37021.54Skamil			case PT_READ_D:
37031.54Skamil			case PT_READ_I:
37041.54Skamil				lookup_me = magic;
37051.54Skamil				break;
37061.54Skamil			default:
37071.54Skamil				break;
37081.54Skamil			}
37091.54Skamil			break;
37101.54Skamil		case BYTES_TRANSFER_DATAIO:
37111.54Skamil			switch (operation) {
37121.54Skamil			case PIOD_READ_D:
37131.54Skamil			case PIOD_READ_I:
37141.54Skamil				switch (size) {
37151.54Skamil				case 8:
37161.54Skamil					lookup_me8 = magic8;
37171.54Skamil					break;
37181.54Skamil				case 16:
37191.54Skamil					lookup_me16 = magic16;
37201.54Skamil					break;
37211.54Skamil				case 32:
37221.54Skamil					lookup_me32 = magic32;
37231.54Skamil					break;
37241.54Skamil				case 64:
37251.54Skamil					lookup_me64 = magic64;
37261.54Skamil					break;
37271.54Skamil				default:
37281.54Skamil					break;
37291.54Skamil				}
37301.54Skamil				break;
37311.54Skamil			default:
37321.54Skamil				break;
37331.54Skamil			}
37341.54Skamil		default:
37351.54Skamil			break;
37361.54Skamil		}
37371.54Skamil
37381.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
37391.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
37401.1Skamil
37411.54Skamil		/* Handle PIOD and PT separately as operation values overlap */
37421.54Skamil		switch (type) {
37431.54Skamil		case BYTES_TRANSFER_DATA:
37441.54Skamil			switch (operation) {
37451.54Skamil			case PT_WRITE_D:
37461.54Skamil			case PT_WRITE_I:
37471.54Skamil				FORKEE_ASSERT_EQ(lookup_me, magic);
37481.54Skamil				break;
37491.54Skamil			default:
37501.54Skamil				break;
37511.54Skamil			}
37521.54Skamil			break;
37531.54Skamil		case BYTES_TRANSFER_DATAIO:
37541.54Skamil			switch (operation) {
37551.54Skamil			case PIOD_WRITE_D:
37561.54Skamil			case PIOD_WRITE_I:
37571.54Skamil				switch (size) {
37581.54Skamil				case 8:
37591.54Skamil					FORKEE_ASSERT_EQ(lookup_me8, magic8);
37601.54Skamil					break;
37611.54Skamil				case 16:
37621.54Skamil					FORKEE_ASSERT_EQ(lookup_me16, magic16);
37631.54Skamil					break;
37641.54Skamil				case 32:
37651.54Skamil					FORKEE_ASSERT_EQ(lookup_me32, magic32);
37661.54Skamil					break;
37671.54Skamil				case 64:
37681.54Skamil					FORKEE_ASSERT_EQ(lookup_me64, magic64);
37691.54Skamil					break;
37701.54Skamil				default:
37711.54Skamil					break;
37721.54Skamil				}
37731.54Skamil				break;
37741.54Skamil			default:
37751.54Skamil				break;
37761.54Skamil			}
37771.54Skamil			break;
37781.54Skamil		case BYTES_TRANSFER_TEXT:
37791.54Skamil			FORKEE_ASSERT(memcmp(&magic, bytes_transfer_dummy,
37801.54Skamil			                     sizeof(magic)) == 0);
37811.54Skamil			break;
37821.54Skamil		case BYTES_TRANSFER_TEXTIO:
37831.54Skamil			switch (size) {
37841.54Skamil			case 8:
37851.54Skamil				FORKEE_ASSERT(memcmp(&magic8,
37861.54Skamil				                     bytes_transfer_dummy,
37871.54Skamil				                     sizeof(magic8)) == 0);
37881.54Skamil				break;
37891.54Skamil			case 16:
37901.54Skamil				FORKEE_ASSERT(memcmp(&magic16,
37911.54Skamil				                     bytes_transfer_dummy,
37921.54Skamil				                     sizeof(magic16)) == 0);
37931.54Skamil				break;
37941.54Skamil			case 32:
37951.54Skamil				FORKEE_ASSERT(memcmp(&magic32,
37961.54Skamil				                     bytes_transfer_dummy,
37971.54Skamil				                     sizeof(magic32)) == 0);
37981.54Skamil				break;
37991.54Skamil			case 64:
38001.54Skamil				FORKEE_ASSERT(memcmp(&magic64,
38011.54Skamil				                     bytes_transfer_dummy,
38021.54Skamil				                     sizeof(magic64)) == 0);
38031.54Skamil				break;
38041.54Skamil			}
38051.54Skamil			break;
38061.54Skamil		default:
38071.54Skamil			break;
38081.54Skamil		}
38091.54Skamil
38101.13Schristos		DPRINTF("Before exiting of the child process\n");
38111.1Skamil		_exit(exitval);
38121.1Skamil	}
38131.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
38141.1Skamil
38151.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
38161.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
38171.1Skamil
38181.1Skamil	validate_status_stopped(status, sigval);
38191.1Skamil
38201.54Skamil	/* Check PaX MPROTECT */
38211.54Skamil	if (!can_we_write_to_text(child)) {
38221.54Skamil		switch (type) {
38231.54Skamil		case BYTES_TRANSFER_TEXTIO:
38241.54Skamil			switch (operation) {
38251.54Skamil			case PIOD_WRITE_D:
38261.54Skamil			case PIOD_WRITE_I:
38271.54Skamil				skip = true;
38281.54Skamil				break;
38291.54Skamil			default:
38301.54Skamil				break;
38311.54Skamil			}
38321.54Skamil			break;
38331.54Skamil		case BYTES_TRANSFER_TEXT:
38341.54Skamil			switch (operation) {
38351.54Skamil			case PT_WRITE_D:
38361.54Skamil			case PT_WRITE_I:
38371.54Skamil				skip = true;
38381.54Skamil				break;
38391.54Skamil			default:
38401.54Skamil				break;
38411.54Skamil			}
38421.54Skamil			break;
38431.54Skamil		default:
38441.54Skamil			break;
38451.54Skamil		}
38461.54Skamil	}
38471.1Skamil
38481.54Skamil	/* Bailout cleanly killing the child process */
38491.54Skamil	if (skip) {
38501.54Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
38511.54Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
38521.54Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
38531.54Skamil		                      child);
38541.1Skamil
38551.54Skamil		validate_status_signaled(status, SIGKILL, 0);
38561.1Skamil
38571.54Skamil		atf_tc_skip("PaX MPROTECT setup prevents writes to .text");
38581.54Skamil	}
38591.1Skamil
38601.54Skamil	DPRINTF("Calling operation to transfer bytes between child=%d and "
38611.54Skamil	       "parent=%d\n", child, getpid());
38621.1Skamil
38631.54Skamil	switch (type) {
38641.54Skamil	case BYTES_TRANSFER_TEXTIO:
38651.54Skamil	case BYTES_TRANSFER_DATAIO:
38661.54Skamil	case BYTES_TRANSFER_AUXV:
38671.54Skamil		switch (operation) {
38681.54Skamil		case PIOD_WRITE_D:
38691.54Skamil		case PIOD_WRITE_I:
38701.54Skamil			switch (size) {
38711.54Skamil			case 8:
38721.54Skamil				lookup_me8 = magic8;
38731.54Skamil				break;
38741.54Skamil			case 16:
38751.54Skamil				lookup_me16 = magic16;
38761.54Skamil				break;
38771.54Skamil			case 32:
38781.54Skamil				lookup_me32 = magic32;
38791.54Skamil				break;
38801.54Skamil			case 64:
38811.54Skamil				lookup_me64 = magic64;
38821.54Skamil				break;
38831.54Skamil			default:
38841.54Skamil				break;
38851.54Skamil			}
38861.54Skamil			break;
38871.54Skamil		default:
38881.54Skamil			break;
38891.54Skamil		}
38901.54Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
38911.54Skamil		switch (operation) {
38921.54Skamil		case PIOD_READ_D:
38931.54Skamil		case PIOD_READ_I:
38941.54Skamil			switch (size) {
38951.54Skamil			case 8:
38961.54Skamil				ATF_REQUIRE_EQ(lookup_me8, magic8);
38971.54Skamil				break;
38981.54Skamil			case 16:
38991.54Skamil				ATF_REQUIRE_EQ(lookup_me16, magic16);
39001.54Skamil				break;
39011.54Skamil			case 32:
39021.54Skamil				ATF_REQUIRE_EQ(lookup_me32, magic32);
39031.54Skamil				break;
39041.54Skamil			case 64:
39051.54Skamil				ATF_REQUIRE_EQ(lookup_me64, magic64);
39061.54Skamil				break;
39071.54Skamil			default:
39081.54Skamil				break;
39091.54Skamil			}
39101.54Skamil			break;
39111.54Skamil		case PIOD_READ_AUXV:
39121.54Skamil			DPRINTF("Asserting that AUXV length (%zu) is > 0\n",
39131.54Skamil			        io.piod_len);
39141.54Skamil			ATF_REQUIRE(io.piod_len > 0);
39151.54Skamil			for (aip = ai; aip->a_type != AT_NULL; aip++)
39161.54Skamil				DPRINTF("a_type=%#llx a_v=%#llx\n",
39171.54Skamil				    (long long int)aip->a_type,
39181.54Skamil				    (long long int)aip->a_v);
39191.54Skamil			break;
39201.54Skamil		default:
39211.54Skamil			break;
39221.54Skamil		}
39231.54Skamil		break;
39241.54Skamil	case BYTES_TRANSFER_TEXT:
39251.54Skamil		switch (operation) {
39261.54Skamil		case PT_READ_D:
39271.54Skamil		case PT_READ_I:
39281.54Skamil			errno = 0;
39291.54Skamil			lookup_me = ptrace(operation, child,
39301.54Skamil			                   bytes_transfer_dummy, 0);
39311.54Skamil			ATF_REQUIRE_EQ(lookup_me, magic);
39321.54Skamil			SYSCALL_REQUIRE_ERRNO(errno, 0);
39331.54Skamil			break;
39341.54Skamil		case PT_WRITE_D:
39351.54Skamil		case PT_WRITE_I:
39361.54Skamil			SYSCALL_REQUIRE(ptrace(operation, child,
39371.54Skamil			                       bytes_transfer_dummy, magic)
39381.54Skamil			                != -1);
39391.54Skamil			break;
39401.54Skamil		default:
39411.54Skamil			break;
39421.54Skamil		}
39431.54Skamil		break;
39441.54Skamil	case BYTES_TRANSFER_DATA:
39451.54Skamil		switch (operation) {
39461.54Skamil		case PT_READ_D:
39471.54Skamil		case PT_READ_I:
39481.54Skamil			errno = 0;
39491.54Skamil			lookup_me = ptrace(operation, child, &lookup_me, 0);
39501.54Skamil			ATF_REQUIRE_EQ(lookup_me, magic);
39511.54Skamil			SYSCALL_REQUIRE_ERRNO(errno, 0);
39521.54Skamil			break;
39531.54Skamil		case PT_WRITE_D:
39541.54Skamil		case PT_WRITE_I:
39551.54Skamil			lookup_me = magic;
39561.54Skamil			SYSCALL_REQUIRE(ptrace(operation, child, &lookup_me,
39571.54Skamil			                       magic) != -1);
39581.54Skamil			break;
39591.54Skamil		default:
39601.54Skamil			break;
39611.54Skamil		}
39621.54Skamil		break;
39631.54Skamil	default:
39641.54Skamil		break;
39651.54Skamil	}
39661.1Skamil
39671.13Schristos	DPRINTF("Before resuming the child process where it left off and "
39681.1Skamil	    "without signal to be sent\n");
39691.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
39701.1Skamil
39711.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
39721.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
39731.1Skamil
39741.1Skamil	validate_status_exited(status, exitval);
39751.1Skamil
39761.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
39771.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
39781.1Skamil}
39791.1Skamil
39801.61Skre#define BYTES_TRANSFER(test, operation, size, type)			\
39811.61SkreATF_TC(test);								\
39821.61SkreATF_TC_HEAD(test, tc)							\
39831.61Skre{									\
39841.61Skre	atf_tc_set_md_var(tc, "descr",					\
39851.61Skre	    "Verify bytes transfer operation" #operation " and size " #size \
39861.61Skre	    " of type " #type);						\
39871.61Skre}									\
39881.61Skre									\
39891.61SkreATF_TC_BODY(test, tc)							\
39901.61Skre{									\
39911.61Skre									\
39921.61Skre	bytes_transfer(operation, size, BYTES_TRANSFER_##type);		\
39931.1Skamil}
39941.1Skamil
39951.54Skamil// DATA
39961.1Skamil
39971.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_8, PIOD_READ_D, 8, DATAIO)
39981.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_16, PIOD_READ_D, 16, DATAIO)
39991.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_32, PIOD_READ_D, 32, DATAIO)
40001.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_64, PIOD_READ_D, 64, DATAIO)
40011.54Skamil
40021.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_8, PIOD_READ_I, 8, DATAIO)
40031.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_16, PIOD_READ_I, 16, DATAIO)
40041.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_32, PIOD_READ_I, 32, DATAIO)
40051.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_64, PIOD_READ_I, 64, DATAIO)
40061.54Skamil
40071.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_8, PIOD_WRITE_D, 8, DATAIO)
40081.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_16, PIOD_WRITE_D, 16, DATAIO)
40091.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_32, PIOD_WRITE_D, 32, DATAIO)
40101.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_64, PIOD_WRITE_D, 64, DATAIO)
40111.54Skamil
40121.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_8, PIOD_WRITE_I, 8, DATAIO)
40131.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_16, PIOD_WRITE_I, 16, DATAIO)
40141.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_32, PIOD_WRITE_I, 32, DATAIO)
40151.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_64, PIOD_WRITE_I, 64, DATAIO)
40161.54Skamil
40171.54SkamilBYTES_TRANSFER(bytes_transfer_read_d, PT_READ_D, 32, DATA)
40181.54SkamilBYTES_TRANSFER(bytes_transfer_read_i, PT_READ_I, 32, DATA)
40191.54SkamilBYTES_TRANSFER(bytes_transfer_write_d, PT_WRITE_D, 32, DATA)
40201.54SkamilBYTES_TRANSFER(bytes_transfer_write_i, PT_WRITE_I, 32, DATA)
40211.54Skamil
40221.54Skamil// TEXT
40231.54Skamil
40241.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_8_text, PIOD_READ_D, 8, TEXTIO)
40251.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_16_text, PIOD_READ_D, 16, TEXTIO)
40261.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_32_text, PIOD_READ_D, 32, TEXTIO)
40271.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_64_text, PIOD_READ_D, 64, TEXTIO)
40281.54Skamil
40291.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_8_text, PIOD_READ_I, 8, TEXTIO)
40301.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_16_text, PIOD_READ_I, 16, TEXTIO)
40311.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_32_text, PIOD_READ_I, 32, TEXTIO)
40321.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_64_text, PIOD_READ_I, 64, TEXTIO)
40331.54Skamil
40341.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_8_text, PIOD_WRITE_D, 8, TEXTIO)
40351.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_16_text, PIOD_WRITE_D, 16, TEXTIO)
40361.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_32_text, PIOD_WRITE_D, 32, TEXTIO)
40371.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_64_text, PIOD_WRITE_D, 64, TEXTIO)
40381.54Skamil
40391.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_8_text, PIOD_WRITE_I, 8, TEXTIO)
40401.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_16_text, PIOD_WRITE_I, 16, TEXTIO)
40411.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_32_text, PIOD_WRITE_I, 32, TEXTIO)
40421.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_64_text, PIOD_WRITE_I, 64, TEXTIO)
40431.54Skamil
40441.54SkamilBYTES_TRANSFER(bytes_transfer_read_d_text, PT_READ_D, 32, TEXT)
40451.54SkamilBYTES_TRANSFER(bytes_transfer_read_i_text, PT_READ_I, 32, TEXT)
40461.54SkamilBYTES_TRANSFER(bytes_transfer_write_d_text, PT_WRITE_D, 32, TEXT)
40471.54SkamilBYTES_TRANSFER(bytes_transfer_write_i_text, PT_WRITE_I, 32, TEXT)
40481.1Skamil
40491.54Skamil// AUXV
40501.1Skamil
40511.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_auxv, PIOD_READ_AUXV, 4096, AUXV)
40521.1Skamil
40531.54Skamil/// ----------------------------------------------------------------------------
40541.1Skamil
40551.101Skamilstatic void
40561.101Skamilbytes_transfer_alignment(const char *operation)
40571.101Skamil{
40581.101Skamil	const int exitval = 5;
40591.101Skamil	const int sigval = SIGSTOP;
40601.101Skamil	pid_t child, wpid;
40611.101Skamil#if defined(TWAIT_HAVE_STATUS)
40621.101Skamil	int status;
40631.101Skamil#endif
40641.101Skamil	char *buffer;
40651.101Skamil	int vector;
40661.101Skamil	size_t len;
40671.101Skamil	size_t i;
40681.101Skamil	int op;
40691.101Skamil
40701.101Skamil	struct ptrace_io_desc io;
40711.101Skamil	struct ptrace_siginfo info;
40721.101Skamil
40731.101Skamil	memset(&io, 0, sizeof(io));
40741.101Skamil	memset(&info, 0, sizeof(info));
40751.101Skamil
40761.101Skamil	/* Testing misaligned byte transfer crossing page boundaries */
40771.101Skamil	len = sysconf(_SC_PAGESIZE) * 2;
40781.101Skamil	buffer = malloc(len);
40791.101Skamil	ATF_REQUIRE(buffer != NULL);
40801.101Skamil
40811.101Skamil	/* Initialize the buffer with random data */
40821.101Skamil	for (i = 0; i < len; i++)
40831.101Skamil		buffer[i] = i & 0xff;
40841.101Skamil
40851.101Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
40861.101Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
40871.101Skamil	if (child == 0) {
40881.101Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
40891.101Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
40901.101Skamil
40911.101Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
40921.101Skamil		FORKEE_ASSERT(raise(sigval) == 0);
40931.101Skamil
40941.101Skamil		DPRINTF("Before exiting of the child process\n");
40951.101Skamil		_exit(exitval);
40961.101Skamil	}
40971.101Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
40981.101Skamil
40991.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
41001.101Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
41011.101Skamil
41021.101Skamil	validate_status_stopped(status, sigval);
41031.101Skamil
41041.101Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
41051.101Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info))
41061.101Skamil		!= -1);
41071.101Skamil
41081.101Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
41091.101Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
41101.101Skamil		"si_errno=%#x\n",
41111.101Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
41121.101Skamil		info.psi_siginfo.si_errno);
41131.101Skamil
41141.101Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
41151.101Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
41161.101Skamil
41171.101Skamil	if (strcmp(operation, "PT_READ_I") == 0 ||
41181.101Skamil	    strcmp(operation, "PT_READ_D") == 0) {
41191.101Skamil		if (strcmp(operation, "PT_READ_I"))
41201.101Skamil			op = PT_READ_I;
41211.101Skamil		else
41221.101Skamil			op = PT_READ_D;
41231.101Skamil
41241.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
41251.101Skamil			errno = 0;
41261.101Skamil			vector = ptrace(op, child, buffer + i, 0);
41271.101Skamil			ATF_REQUIRE_EQ(errno, 0);
41281.101Skamil			ATF_REQUIRE(!memcmp(&vector, buffer + i, sizeof(int)));
41291.101Skamil		}
41301.101Skamil	} else if (strcmp(operation, "PT_WRITE_I") == 0 ||
41311.101Skamil	           strcmp(operation, "PT_WRITE_D") == 0) {
41321.101Skamil		if (strcmp(operation, "PT_WRITE_I"))
41331.101Skamil			op = PT_WRITE_I;
41341.101Skamil		else
41351.101Skamil			op = PT_WRITE_D;
41361.101Skamil
41371.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
41381.101Skamil			memcpy(&vector, buffer + i, sizeof(int));
41391.101Skamil			SYSCALL_REQUIRE(ptrace(op, child, buffer + 1, vector)
41401.101Skamil			    != -1);
41411.101Skamil		}
41421.101Skamil	} else if (strcmp(operation, "PIOD_READ_I") == 0 ||
41431.101Skamil	           strcmp(operation, "PIOD_READ_D") == 0) {
41441.101Skamil		if (strcmp(operation, "PIOD_READ_I"))
41451.101Skamil			op = PIOD_READ_I;
41461.101Skamil		else
41471.101Skamil			op = PIOD_READ_D;
41481.101Skamil
41491.101Skamil		io.piod_op = op;
41501.101Skamil		io.piod_addr = &vector;
41511.101Skamil		io.piod_len = sizeof(int);
41521.101Skamil
41531.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
41541.101Skamil			io.piod_offs = buffer + i;
41551.101Skamil
41561.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
41571.101Skamil			                != -1);
41581.101Skamil			ATF_REQUIRE(!memcmp(&vector, buffer + i, sizeof(int)));
41591.101Skamil		}
41601.101Skamil	} else if (strcmp(operation, "PIOD_WRITE_I") == 0 ||
41611.101Skamil	           strcmp(operation, "PIOD_WRITE_D") == 0) {
41621.101Skamil		if (strcmp(operation, "PIOD_WRITE_I"))
41631.101Skamil			op = PIOD_WRITE_I;
41641.101Skamil		else
41651.101Skamil			op = PIOD_WRITE_D;
41661.101Skamil
41671.101Skamil		io.piod_op = op;
41681.101Skamil		io.piod_addr = &vector;
41691.101Skamil		io.piod_len = sizeof(int);
41701.101Skamil
41711.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
41721.101Skamil			io.piod_offs = buffer + i;
41731.101Skamil
41741.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
41751.101Skamil			                != -1);
41761.101Skamil		}
41771.101Skamil	} else if (strcmp(operation, "PIOD_READ_AUXV") == 0) {
41781.101Skamil		io.piod_op = PIOD_READ_AUXV;
41791.101Skamil		io.piod_addr = &vector;
41801.101Skamil		io.piod_len = sizeof(int);
41811.101Skamil
41821.101Skamil		errno = 0;
41831.101Skamil		i = 0;
41841.101Skamil		/* Read the whole AUXV vector, it has no clear length */
41851.120Skamil		while (io.piod_len > 0) {
41861.101Skamil			io.piod_offs = (void *)(intptr_t)i;
41871.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
41881.120Skamil			                != -1 || (io.piod_len == 0 && i > 0));
41891.101Skamil			++i;
41901.101Skamil		}
41911.101Skamil	}
41921.101Skamil
41931.101Skamil	DPRINTF("Before resuming the child process where it left off "
41941.101Skamil	    "and without signal to be sent\n");
41951.101Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
41961.101Skamil
41971.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
41981.101Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
41991.101Skamil	    child);
42001.101Skamil
42011.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
42021.101Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
42031.101Skamil}
42041.101Skamil
42051.101Skamil#define BYTES_TRANSFER_ALIGNMENT(test, operation)			\
42061.101SkamilATF_TC(test);								\
42071.101SkamilATF_TC_HEAD(test, tc)							\
42081.101Skamil{									\
42091.101Skamil	atf_tc_set_md_var(tc, "descr",					\
42101.101Skamil	    "Verify bytes transfer for potentially misaligned "		\
42111.101Skamil	    "operation " operation);					\
42121.101Skamil}									\
42131.101Skamil									\
42141.101SkamilATF_TC_BODY(test, tc)							\
42151.101Skamil{									\
42161.101Skamil									\
42171.101Skamil	bytes_transfer_alignment(operation);				\
42181.101Skamil}
42191.101Skamil
42201.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_read_i, "PT_READ_I")
42211.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_read_d, "PT_READ_D")
42221.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_write_i, "PT_WRITE_I")
42231.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_write_d, "PT_WRITE_D")
42241.101Skamil
42251.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_i, "PIOD_READ_I")
42261.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_d, "PIOD_READ_D")
42271.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_write_i, "PIOD_WRITE_I")
42281.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_write_d, "PIOD_WRITE_D")
42291.101Skamil
42301.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_auxv, "PIOD_READ_AUXV")
42311.101Skamil
42321.101Skamil/// ----------------------------------------------------------------------------
42331.101Skamil
42341.115Skamilstatic void
42351.115Skamilbytes_transfer_eof(const char *operation)
42361.115Skamil{
42371.115Skamil	const int exitval = 5;
42381.115Skamil	const int sigval = SIGSTOP;
42391.115Skamil	pid_t child, wpid;
42401.115Skamil#if defined(TWAIT_HAVE_STATUS)
42411.115Skamil	int status;
42421.115Skamil#endif
42431.115Skamil	FILE *fp;
42441.115Skamil	char *p;
42451.115Skamil	int vector;
42461.115Skamil	int op;
42471.115Skamil
42481.115Skamil	struct ptrace_io_desc io;
42491.115Skamil	struct ptrace_siginfo info;
42501.115Skamil
42511.115Skamil	memset(&io, 0, sizeof(io));
42521.115Skamil	memset(&info, 0, sizeof(info));
42531.115Skamil
42541.115Skamil	vector = 0;
42551.115Skamil
42561.115Skamil	fp = tmpfile();
42571.115Skamil	ATF_REQUIRE(fp != NULL);
42581.115Skamil
42591.115Skamil	p = mmap(0, 1, PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(fp), 0);
42601.115Skamil	ATF_REQUIRE(p != MAP_FAILED);
42611.115Skamil
42621.115Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
42631.115Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
42641.115Skamil	if (child == 0) {
42651.115Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
42661.115Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
42671.115Skamil
42681.115Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
42691.115Skamil		FORKEE_ASSERT(raise(sigval) == 0);
42701.115Skamil
42711.115Skamil		DPRINTF("Before exiting of the child process\n");
42721.115Skamil		_exit(exitval);
42731.115Skamil	}
42741.115Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
42751.115Skamil
42761.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
42771.115Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
42781.115Skamil
42791.115Skamil	validate_status_stopped(status, sigval);
42801.115Skamil
42811.115Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
42821.115Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info))
42831.115Skamil		!= -1);
42841.115Skamil
42851.115Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
42861.115Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
42871.115Skamil		"si_errno=%#x\n",
42881.115Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
42891.115Skamil		info.psi_siginfo.si_errno);
42901.115Skamil
42911.115Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
42921.115Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
42931.115Skamil
42941.115Skamil	if (strcmp(operation, "PT_READ_I") == 0 ||
42951.115Skamil	    strcmp(operation, "PT_READ_D") == 0) {
42961.115Skamil		if (strcmp(operation, "PT_READ_I"))
42971.115Skamil			op = PT_READ_I;
42981.115Skamil		else
42991.115Skamil			op = PT_READ_D;
43001.115Skamil
43011.115Skamil		errno = 0;
43021.115Skamil		SYSCALL_REQUIRE(ptrace(op, child, p, 0) == -1);
43031.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
43041.115Skamil	} else if (strcmp(operation, "PT_WRITE_I") == 0 ||
43051.115Skamil	           strcmp(operation, "PT_WRITE_D") == 0) {
43061.115Skamil		if (strcmp(operation, "PT_WRITE_I"))
43071.115Skamil			op = PT_WRITE_I;
43081.115Skamil		else
43091.115Skamil			op = PT_WRITE_D;
43101.115Skamil
43111.115Skamil		errno = 0;
43121.115Skamil		SYSCALL_REQUIRE(ptrace(op, child, p, vector) == -1);
43131.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
43141.115Skamil	} else if (strcmp(operation, "PIOD_READ_I") == 0 ||
43151.115Skamil	           strcmp(operation, "PIOD_READ_D") == 0) {
43161.115Skamil		if (strcmp(operation, "PIOD_READ_I"))
43171.115Skamil			op = PIOD_READ_I;
43181.115Skamil		else
43191.115Skamil			op = PIOD_READ_D;
43201.115Skamil
43211.115Skamil		io.piod_op = op;
43221.115Skamil		io.piod_addr = &vector;
43231.115Skamil		io.piod_len = sizeof(int);
43241.115Skamil		io.piod_offs = p;
43251.115Skamil
43261.115Skamil		errno = 0;
43271.115Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io)) == -1);
43281.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
43291.115Skamil	} else if (strcmp(operation, "PIOD_WRITE_I") == 0 ||
43301.115Skamil	           strcmp(operation, "PIOD_WRITE_D") == 0) {
43311.115Skamil		if (strcmp(operation, "PIOD_WRITE_I"))
43321.115Skamil			op = PIOD_WRITE_I;
43331.115Skamil		else
43341.115Skamil			op = PIOD_WRITE_D;
43351.115Skamil
43361.115Skamil		io.piod_op = op;
43371.115Skamil		io.piod_addr = &vector;
43381.115Skamil		io.piod_len = sizeof(int);
43391.115Skamil		io.piod_offs = p;
43401.115Skamil
43411.115Skamil		errno = 0;
43421.115Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io)) == -1);
43431.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
43441.115Skamil	}
43451.115Skamil
43461.115Skamil	DPRINTF("Before resuming the child process where it left off "
43471.115Skamil	    "and without signal to be sent\n");
43481.115Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
43491.115Skamil
43501.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
43511.115Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
43521.115Skamil	    child);
43531.115Skamil
43541.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
43551.115Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
43561.115Skamil}
43571.115Skamil
43581.115Skamil#define BYTES_TRANSFER_EOF(test, operation)				\
43591.115SkamilATF_TC(test);								\
43601.115SkamilATF_TC_HEAD(test, tc)							\
43611.115Skamil{									\
43621.115Skamil	atf_tc_set_md_var(tc, "descr",					\
43631.115Skamil	    "Verify bytes EOF byte transfer for the " operation		\
43641.115Skamil	    " operation");						\
43651.115Skamil}									\
43661.115Skamil									\
43671.115SkamilATF_TC_BODY(test, tc)							\
43681.115Skamil{									\
43691.115Skamil									\
43701.115Skamil	bytes_transfer_eof(operation);					\
43711.115Skamil}
43721.115Skamil
43731.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_read_i, "PT_READ_I")
43741.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_read_d, "PT_READ_D")
43751.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_write_i, "PT_WRITE_I")
43761.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_write_d, "PT_WRITE_D")
43771.115Skamil
43781.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_read_i, "PIOD_READ_I")
43791.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_read_d, "PIOD_READ_D")
43801.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_i, "PIOD_WRITE_I")
43811.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_d, "PIOD_WRITE_D")
43821.115Skamil
43831.115Skamil/// ----------------------------------------------------------------------------
43841.115Skamil
43851.76Sscole#if defined(HAVE_GPREGS) || defined(HAVE_FPREGS)
43861.72Skamilstatic void
43871.72Skamilaccess_regs(const char *regset, const char *aux)
43881.1Skamil{
43891.1Skamil	const int exitval = 5;
43901.1Skamil	const int sigval = SIGSTOP;
43911.1Skamil	pid_t child, wpid;
43921.1Skamil#if defined(TWAIT_HAVE_STATUS)
43931.1Skamil	int status;
43941.1Skamil#endif
43951.72Skamil#if defined(HAVE_GPREGS)
43961.72Skamil	struct reg gpr;
43971.76Sscole	register_t rgstr;
43981.1Skamil#endif
43991.72Skamil#if defined(HAVE_FPREGS)
44001.72Skamil	struct fpreg fpr;
44011.1Skamil#endif
44021.76Sscole
44031.72Skamil#if !defined(HAVE_GPREGS)
44041.72Skamil	if (strcmp(regset, "regs") == 0)
44051.72Skamil		atf_tc_fail("Impossible test scenario!");
44061.1Skamil#endif
44071.1Skamil
44081.72Skamil#if !defined(HAVE_FPREGS)
44091.72Skamil	if (strcmp(regset, "fpregs") == 0)
44101.72Skamil		atf_tc_fail("Impossible test scenario!");
44111.1Skamil#endif
44121.1Skamil
44131.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
44141.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
44151.1Skamil	if (child == 0) {
44161.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
44171.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
44181.1Skamil
44191.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
44201.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
44211.1Skamil
44221.13Schristos		DPRINTF("Before exiting of the child process\n");
44231.1Skamil		_exit(exitval);
44241.1Skamil	}
44251.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
44261.1Skamil
44271.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
44281.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
44291.1Skamil
44301.1Skamil	validate_status_stopped(status, sigval);
44311.1Skamil
44321.1Skamil#if defined(HAVE_GPREGS)
44331.72Skamil	if (strcmp(regset, "regs") == 0) {
44341.72Skamil		DPRINTF("Call GETREGS for the child process\n");
44351.72Skamil		SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1);
44361.72Skamil
44371.72Skamil		if (strcmp(aux, "none") == 0) {
44381.72Skamil			DPRINTF("Retrieved registers\n");
44391.72Skamil		} else if (strcmp(aux, "pc") == 0) {
44401.72Skamil			rgstr = PTRACE_REG_PC(&gpr);
44411.72Skamil			DPRINTF("Retrieved %" PRIxREGISTER "\n", rgstr);
44421.147Skamil		} else if (strstr(aux, "set_pc") != NULL) {
44431.72Skamil			rgstr = PTRACE_REG_PC(&gpr);
44441.147Skamil			DPRINTF("Retrieved PC %" PRIxREGISTER "\n", rgstr);
44451.147Skamil			if (strstr(aux, "0x1") != NULL) {
44461.147Skamil				rgstr |= 0x1;
44471.147Skamil			} else if (strstr(aux, "0x3") != NULL) {
44481.147Skamil				rgstr |= 0x3;
44491.147Skamil			} else if (strstr(aux, "0x7") != NULL) {
44501.147Skamil				rgstr |= 0x7;
44511.147Skamil			}
44521.147Skamil			DPRINTF("Set PC %" PRIxREGISTER "\n", rgstr);
44531.72Skamil			PTRACE_REG_SET_PC(&gpr, rgstr);
44541.147Skamil			if (strcmp(aux, "set_pc") != 0) {
44551.147Skamil				/* This call can fail with EINVAL or similar. */
44561.147Skamil				ptrace(PT_SETREGS, child, &gpr, 0);
44571.147Skamil			}
44581.72Skamil		} else if (strcmp(aux, "sp") == 0) {
44591.72Skamil			rgstr = PTRACE_REG_SP(&gpr);
44601.72Skamil			DPRINTF("Retrieved %" PRIxREGISTER "\n", rgstr);
44611.72Skamil		} else if (strcmp(aux, "intrv") == 0) {
44621.72Skamil			rgstr = PTRACE_REG_INTRV(&gpr);
44631.72Skamil			DPRINTF("Retrieved %" PRIxREGISTER "\n", rgstr);
44641.72Skamil		} else if (strcmp(aux, "setregs") == 0) {
44651.72Skamil			DPRINTF("Call SETREGS for the child process\n");
44661.72Skamil			SYSCALL_REQUIRE(
44671.147Skamil			    ptrace(PT_SETREGS, child, &gpr, 0) != -1);
44681.72Skamil		}
44691.72Skamil	}
44701.1Skamil#endif
44711.1Skamil
44721.72Skamil#if defined(HAVE_FPREGS)
44731.72Skamil	if (strcmp(regset, "fpregs") == 0) {
44741.72Skamil		DPRINTF("Call GETFPREGS for the child process\n");
44751.72Skamil		SYSCALL_REQUIRE(ptrace(PT_GETFPREGS, child, &fpr, 0) != -1);
44761.72Skamil
44771.72Skamil		if (strcmp(aux, "getfpregs") == 0) {
44781.72Skamil			DPRINTF("Retrieved FP registers\n");
44791.72Skamil		} else if (strcmp(aux, "setfpregs") == 0) {
44801.72Skamil			DPRINTF("Call SETFPREGS for the child\n");
44811.72Skamil			SYSCALL_REQUIRE(
44821.72Skamil			    ptrace(PT_SETFPREGS, child, &fpr, 0) != -1);
44831.72Skamil		}
44841.1Skamil	}
44851.1Skamil#endif
44861.1Skamil
44871.13Schristos	DPRINTF("Before resuming the child process where it left off and "
44881.1Skamil	    "without signal to be sent\n");
44891.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
44901.1Skamil
44911.147Skamil	if (strstr(aux, "unaligned") != NULL) {
44921.147Skamil		DPRINTF("Before resuming the child process where it left off "
44931.147Skamil		    "and without signal to be sent\n");
44941.147Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
44951.147Skamil
44961.147Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
44971.147Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
44981.147Skamil		    child);
44991.147Skamil
45001.147Skamil		validate_status_signaled(status, SIGKILL, 0);
45011.147Skamil
45021.147Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
45031.147Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
45041.147Skamil		    wpid = TWAIT_GENERIC(child, &status, 0));
45051.147Skamil	} else {
45061.147Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
45071.147Skamil		TWAIT_REQUIRE_SUCCESS(
45081.147Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
45091.1Skamil
45101.147Skamil		validate_status_exited(status, exitval);
45111.1Skamil
45121.147Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
45131.147Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
45141.147Skamil		    wpid = TWAIT_GENERIC(child, &status, 0));
45151.147Skamil	}
45161.1Skamil}
45171.1Skamil
45181.72Skamil#define ACCESS_REGS(test, regset, aux)					\
45191.72SkamilATF_TC(test);								\
45201.72SkamilATF_TC_HEAD(test, tc)							\
45211.72Skamil{									\
45221.72Skamil        atf_tc_set_md_var(tc, "descr",					\
45231.72Skamil            "Verify " regset " with auxiliary operation: " aux);	\
45241.72Skamil}									\
45251.72Skamil									\
45261.72SkamilATF_TC_BODY(test, tc)							\
45271.72Skamil{									\
45281.72Skamil									\
45291.72Skamil        access_regs(regset, aux);					\
45301.1Skamil}
45311.1Skamil#endif
45321.1Skamil
45331.72Skamil#if defined(HAVE_GPREGS)
45341.72SkamilACCESS_REGS(access_regs1, "regs", "none")
45351.72SkamilACCESS_REGS(access_regs2, "regs", "pc")
45361.72SkamilACCESS_REGS(access_regs3, "regs", "set_pc")
45371.72SkamilACCESS_REGS(access_regs4, "regs", "sp")
45381.72SkamilACCESS_REGS(access_regs5, "regs", "intrv")
45391.72SkamilACCESS_REGS(access_regs6, "regs", "setregs")
45401.147SkamilACCESS_REGS(access_regs_set_unaligned_pc_0x1, "regs", "set_pc+unaligned+0x1")
45411.147SkamilACCESS_REGS(access_regs_set_unaligned_pc_0x3, "regs", "set_pc+unaligned+0x3")
45421.147SkamilACCESS_REGS(access_regs_set_unaligned_pc_0x7, "regs", "set_pc+unaligned+0x7")
45431.1Skamil#endif
45441.1Skamil#if defined(HAVE_FPREGS)
45451.72SkamilACCESS_REGS(access_fpregs1, "fpregs", "getfpregs")
45461.72SkamilACCESS_REGS(access_fpregs2, "fpregs", "setfpregs")
45471.1Skamil#endif
45481.1Skamil
45491.72Skamil/// ----------------------------------------------------------------------------
45501.1Skamil
45511.1Skamil#if defined(PT_STEP)
45521.1Skamilstatic void
45531.95Skamilptrace_step(int N, int setstep, bool masked, bool ignored)
45541.1Skamil{
45551.1Skamil	const int exitval = 5;
45561.1Skamil	const int sigval = SIGSTOP;
45571.1Skamil	pid_t child, wpid;
45581.1Skamil#if defined(TWAIT_HAVE_STATUS)
45591.1Skamil	int status;
45601.1Skamil#endif
45611.1Skamil	int happy;
45621.95Skamil	struct sigaction sa;
45631.81Skamil	struct ptrace_siginfo info;
45641.95Skamil	sigset_t intmask;
45651.95Skamil	struct kinfo_proc2 kp;
45661.95Skamil	size_t len = sizeof(kp);
45671.95Skamil
45681.95Skamil	int name[6];
45691.95Skamil	const size_t namelen = __arraycount(name);
45701.95Skamil	ki_sigset_t kp_sigmask;
45711.95Skamil	ki_sigset_t kp_sigignore;
45721.1Skamil
45731.1Skamil#if defined(__arm__)
45741.1Skamil	/* PT_STEP not supported on arm 32-bit */
45751.1Skamil	atf_tc_expect_fail("PR kern/52119");
45761.1Skamil#endif
45771.1Skamil
45781.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
45791.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
45801.1Skamil	if (child == 0) {
45811.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
45821.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
45831.1Skamil
45841.95Skamil		if (masked) {
45851.95Skamil			sigemptyset(&intmask);
45861.95Skamil			sigaddset(&intmask, SIGTRAP);
45871.95Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
45881.95Skamil		}
45891.95Skamil
45901.95Skamil		if (ignored) {
45911.95Skamil			memset(&sa, 0, sizeof(sa));
45921.95Skamil			sa.sa_handler = SIG_IGN;
45931.95Skamil			sigemptyset(&sa.sa_mask);
45941.95Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
45951.95Skamil		}
45961.95Skamil
45971.1Skamil		happy = check_happy(999);
45981.1Skamil
45991.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
46001.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
46011.1Skamil
46021.1Skamil		FORKEE_ASSERT_EQ(happy, check_happy(999));
46031.1Skamil
46041.13Schristos		DPRINTF("Before exiting of the child process\n");
46051.1Skamil		_exit(exitval);
46061.1Skamil	}
46071.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
46081.1Skamil
46091.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46101.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
46111.1Skamil
46121.1Skamil	validate_status_stopped(status, sigval);
46131.1Skamil
46141.81Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
46151.81Skamil	SYSCALL_REQUIRE(
46161.81Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
46171.81Skamil
46181.81Skamil	DPRINTF("Before checking siginfo_t\n");
46191.81Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
46201.81Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
46211.81Skamil
46221.95Skamil	name[0] = CTL_KERN,
46231.95Skamil	name[1] = KERN_PROC2,
46241.95Skamil	name[2] = KERN_PROC_PID;
46251.95Skamil	name[3] = child;
46261.95Skamil	name[4] = sizeof(kp);
46271.95Skamil	name[5] = 1;
46281.95Skamil
46291.95Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
46301.95Skamil
46311.95Skamil	if (masked)
46321.95Skamil		kp_sigmask = kp.p_sigmask;
46331.95Skamil
46341.95Skamil	if (ignored)
46351.95Skamil		kp_sigignore = kp.p_sigignore;
46361.95Skamil
46371.1Skamil	while (N --> 0) {
46381.2Skamil		if (setstep) {
46391.13Schristos			DPRINTF("Before resuming the child process where it "
46401.2Skamil			    "left off and without signal to be sent (use "
46411.9Skamil			    "PT_SETSTEP and PT_CONTINUE)\n");
46421.13Schristos			SYSCALL_REQUIRE(ptrace(PT_SETSTEP, child, 0, 0) != -1);
46431.13Schristos			SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0)
46441.2Skamil			    != -1);
46451.2Skamil		} else {
46461.13Schristos			DPRINTF("Before resuming the child process where it "
46471.2Skamil			    "left off and without signal to be sent (use "
46481.2Skamil			    "PT_STEP)\n");
46491.13Schristos			SYSCALL_REQUIRE(ptrace(PT_STEP, child, (void *)1, 0)
46501.2Skamil			    != -1);
46511.2Skamil		}
46521.1Skamil
46531.13Schristos		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46541.1Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
46551.1Skamil		    child);
46561.1Skamil
46571.1Skamil		validate_status_stopped(status, SIGTRAP);
46581.2Skamil
46591.81Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
46601.81Skamil		SYSCALL_REQUIRE(
46611.81Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
46621.81Skamil
46631.81Skamil		DPRINTF("Before checking siginfo_t\n");
46641.81Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
46651.81Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_TRACE);
46661.81Skamil
46671.2Skamil		if (setstep) {
46681.13Schristos			SYSCALL_REQUIRE(ptrace(PT_CLEARSTEP, child, 0, 0) != -1);
46691.2Skamil		}
46701.95Skamil
46711.95Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
46721.95Skamil
46731.95Skamil		if (masked) {
46741.95Skamil			DPRINTF("kp_sigmask="
46751.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
46761.95Skamil			    PRIx32 "\n",
46771.95Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
46781.95Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
46791.95Skamil
46801.95Skamil			DPRINTF("kp.p_sigmask="
46811.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
46821.95Skamil			    PRIx32 "\n",
46831.95Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
46841.95Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
46851.95Skamil
46861.95Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
46871.95Skamil			    sizeof(kp_sigmask)));
46881.95Skamil		}
46891.95Skamil
46901.95Skamil		if (ignored) {
46911.95Skamil			DPRINTF("kp_sigignore="
46921.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
46931.95Skamil			    PRIx32 "\n",
46941.95Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
46951.95Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
46961.95Skamil
46971.95Skamil			DPRINTF("kp.p_sigignore="
46981.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
46991.95Skamil			    PRIx32 "\n",
47001.95Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
47011.95Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
47021.95Skamil
47031.95Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
47041.95Skamil			    sizeof(kp_sigignore)));
47051.95Skamil		}
47061.1Skamil	}
47071.1Skamil
47081.13Schristos	DPRINTF("Before resuming the child process where it left off and "
47091.1Skamil	    "without signal to be sent\n");
47101.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
47111.1Skamil
47121.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
47131.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
47141.1Skamil
47151.1Skamil	validate_status_exited(status, exitval);
47161.1Skamil
47171.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
47181.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
47191.1Skamil}
47201.1Skamil
47211.73Skamil#define PTRACE_STEP(test, N, setstep)					\
47221.73SkamilATF_TC(test);								\
47231.73SkamilATF_TC_HEAD(test, tc)							\
47241.73Skamil{									\
47251.73Skamil        atf_tc_set_md_var(tc, "descr",					\
47261.74Skamil            "Verify " #N " (PT_SETSTEP set to: " #setstep ")");		\
47271.73Skamil}									\
47281.73Skamil									\
47291.73SkamilATF_TC_BODY(test, tc)							\
47301.73Skamil{									\
47311.73Skamil									\
47321.95Skamil        ptrace_step(N, setstep, false, false);				\
47331.1Skamil}
47341.1Skamil
47351.73SkamilPTRACE_STEP(step1, 1, 0)
47361.73SkamilPTRACE_STEP(step2, 2, 0)
47371.73SkamilPTRACE_STEP(step3, 3, 0)
47381.73SkamilPTRACE_STEP(step4, 4, 0)
47391.73SkamilPTRACE_STEP(setstep1, 1, 1)
47401.73SkamilPTRACE_STEP(setstep2, 2, 1)
47411.73SkamilPTRACE_STEP(setstep3, 3, 1)
47421.73SkamilPTRACE_STEP(setstep4, 4, 1)
47431.95Skamil
47441.95SkamilATF_TC(step_signalmasked);
47451.95SkamilATF_TC_HEAD(step_signalmasked, tc)
47461.95Skamil{
47471.95Skamil	atf_tc_set_md_var(tc, "descr", "Verify PT_STEP with masked SIGTRAP");
47481.95Skamil}
47491.95Skamil
47501.95SkamilATF_TC_BODY(step_signalmasked, tc)
47511.95Skamil{
47521.95Skamil
47531.95Skamil	ptrace_step(1, 0, true, false);
47541.95Skamil}
47551.95Skamil
47561.95SkamilATF_TC(step_signalignored);
47571.95SkamilATF_TC_HEAD(step_signalignored, tc)
47581.95Skamil{
47591.95Skamil	atf_tc_set_md_var(tc, "descr", "Verify PT_STEP with ignored SIGTRAP");
47601.95Skamil}
47611.95Skamil
47621.95SkamilATF_TC_BODY(step_signalignored, tc)
47631.95Skamil{
47641.95Skamil
47651.95Skamil	ptrace_step(1, 0, false, true);
47661.95Skamil}
47671.1Skamil#endif
47681.1Skamil
47691.73Skamil/// ----------------------------------------------------------------------------
47701.1Skamil
47711.75Skamilstatic void
47721.75Skamilptrace_kill(const char *type)
47731.1Skamil{
47741.75Skamil	const int sigval = SIGSTOP;
47751.1Skamil	pid_t child, wpid;
47761.1Skamil#if defined(TWAIT_HAVE_STATUS)
47771.1Skamil	int status;
47781.1Skamil#endif
47791.1Skamil
47801.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
47811.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
47821.1Skamil	if (child == 0) {
47831.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
47841.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
47851.1Skamil
47861.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
47871.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
47881.1Skamil
47891.1Skamil		/* NOTREACHED */
47901.1Skamil		FORKEE_ASSERTX(0 &&
47911.1Skamil		    "Child should be terminated by a signal from its parent");
47921.1Skamil	}
47931.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
47941.1Skamil
47951.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
47961.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
47971.1Skamil
47981.1Skamil	validate_status_stopped(status, sigval);
47991.1Skamil
48001.75Skamil	DPRINTF("Before killing the child process with %s\n", type);
48011.75Skamil	if (strcmp(type, "ptrace(PT_KILL)") == 0) {
48021.75Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void*)1, 0) != -1);
48031.75Skamil	} else if (strcmp(type, "kill(SIGKILL)") == 0) {
48041.75Skamil		kill(child, SIGKILL);
48051.75Skamil	} else if (strcmp(type, "killpg(SIGKILL)") == 0) {
48061.75Skamil		setpgid(child, 0);
48071.75Skamil		killpg(getpgid(child), SIGKILL);
48081.75Skamil	}
48091.1Skamil
48101.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48111.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
48121.1Skamil
48131.75Skamil	validate_status_signaled(status, SIGKILL, 0);
48141.1Skamil
48151.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48161.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
48171.1Skamil}
48181.1Skamil
48191.75Skamil#define PTRACE_KILL(test, type)						\
48201.75SkamilATF_TC(test);								\
48211.75SkamilATF_TC_HEAD(test, tc)							\
48221.75Skamil{									\
48231.75Skamil        atf_tc_set_md_var(tc, "descr",					\
48241.75Skamil            "Verify killing the child with " type);			\
48251.75Skamil}									\
48261.75Skamil									\
48271.75SkamilATF_TC_BODY(test, tc)							\
48281.75Skamil{									\
48291.75Skamil									\
48301.75Skamil        ptrace_kill(type);						\
48311.1Skamil}
48321.1Skamil
48331.75Skamil// PT_CONTINUE with SIGKILL is covered by traceme_sendsignal_simple1
48341.75SkamilPTRACE_KILL(kill1, "ptrace(PT_KILL)")
48351.75SkamilPTRACE_KILL(kill2, "kill(SIGKILL)")
48361.75SkamilPTRACE_KILL(kill3, "killpg(SIGKILL)")
48371.1Skamil
48381.75Skamil/// ----------------------------------------------------------------------------
48391.1Skamil
48401.143Skamilstatic int lwpinfo_thread_sigmask[] = {SIGXCPU, SIGPIPE, SIGALRM, SIGURG};
48411.143Skamil
48421.143Skamilstatic pthread_mutex_t lwpinfo_thread_mtx = PTHREAD_MUTEX_INITIALIZER;
48431.143Skamilstatic pthread_cond_t lwpinfo_thread_cnd = PTHREAD_COND_INITIALIZER;
48441.143Skamilstatic volatile size_t lwpinfo_thread_done;
48451.143Skamil
48461.143Skamilstatic void *
48471.143Skamillwpinfo_thread(void *arg)
48481.143Skamil{
48491.143Skamil	sigset_t s;
48501.143Skamil	volatile void **tcb;
48511.143Skamil
48521.143Skamil	tcb = (volatile void **)arg;
48531.143Skamil
48541.145Skamil	*tcb = _lwp_getprivate();
48551.143Skamil	DPRINTF("Storing tcb[] = %p from thread %d\n", *tcb, _lwp_self());
48561.143Skamil
48571.143Skamil	pthread_setname_np(pthread_self(), "thread %d",
48581.143Skamil	    (void *)(intptr_t)_lwp_self());
48591.143Skamil
48601.143Skamil	sigemptyset(&s);
48611.143Skamil	pthread_mutex_lock(&lwpinfo_thread_mtx);
48621.143Skamil	sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
48631.143Skamil	lwpinfo_thread_done++;
48641.143Skamil	pthread_sigmask(SIG_BLOCK, &s, NULL);
48651.143Skamil	pthread_cond_signal(&lwpinfo_thread_cnd);
48661.143Skamil	pthread_mutex_unlock(&lwpinfo_thread_mtx);
48671.143Skamil
48681.143Skamil	return infinite_thread(NULL);
48691.143Skamil}
48701.143Skamil
48711.77Skamilstatic void
48721.143Skamiltraceme_lwpinfo(const size_t threads, const char *iter)
48731.1Skamil{
48741.1Skamil	const int sigval = SIGSTOP;
48751.77Skamil	const int sigval2 = SIGINT;
48761.1Skamil	pid_t child, wpid;
48771.1Skamil#if defined(TWAIT_HAVE_STATUS)
48781.1Skamil	int status;
48791.1Skamil#endif
48801.77Skamil	struct ptrace_lwpinfo lwp = {0, 0};
48811.143Skamil	struct ptrace_lwpstatus lwpstatus = {0};
48821.77Skamil	struct ptrace_siginfo info;
48831.143Skamil	void *private;
48841.143Skamil	char *name;
48851.143Skamil	char namebuf[PL_LNAMELEN];
48861.143Skamil	volatile void *tcb[4];
48871.143Skamil	bool found;
48881.143Skamil	sigset_t s;
48891.77Skamil
48901.77Skamil	/* Maximum number of supported threads in this test */
48911.143Skamil	pthread_t t[__arraycount(tcb) - 1];
48921.143Skamil	size_t n, m;
48931.143Skamil	int rv;
48941.143Skamil	size_t bytes_read;
48951.143Skamil
48961.143Skamil	struct ptrace_io_desc io;
48971.143Skamil	sigset_t sigmask;
48981.77Skamil
48991.143Skamil	ATF_REQUIRE(__arraycount(t) >= threads);
49001.143Skamil	memset(tcb, 0, sizeof(tcb));
49011.1Skamil
49021.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
49031.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
49041.1Skamil	if (child == 0) {
49051.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
49061.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
49071.1Skamil
49081.145Skamil		tcb[0] = _lwp_getprivate();
49091.143Skamil		DPRINTF("Storing tcb[0] = %p\n", tcb[0]);
49101.143Skamil
49111.143Skamil		pthread_setname_np(pthread_self(), "thread %d",
49121.143Skamil		    (void *)(intptr_t)_lwp_self());
49131.143Skamil
49141.143Skamil		sigemptyset(&s);
49151.143Skamil		sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
49161.143Skamil		pthread_sigmask(SIG_BLOCK, &s, NULL);
49171.143Skamil
49181.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
49191.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
49201.1Skamil
49211.77Skamil		for (n = 0; n < threads; n++) {
49221.143Skamil			rv = pthread_create(&t[n], NULL, lwpinfo_thread,
49231.143Skamil			    &tcb[n + 1]);
49241.77Skamil			FORKEE_ASSERT(rv == 0);
49251.77Skamil		}
49261.77Skamil
49271.143Skamil		pthread_mutex_lock(&lwpinfo_thread_mtx);
49281.143Skamil		while (lwpinfo_thread_done < threads) {
49291.143Skamil			pthread_cond_wait(&lwpinfo_thread_cnd,
49301.143Skamil			    &lwpinfo_thread_mtx);
49311.143Skamil		}
49321.143Skamil		pthread_mutex_unlock(&lwpinfo_thread_mtx);
49331.143Skamil
49341.77Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval2));
49351.77Skamil		FORKEE_ASSERT(raise(sigval2) == 0);
49361.77Skamil
49371.77Skamil		/* NOTREACHED */
49381.77Skamil		FORKEE_ASSERTX(0 && "Not reached");
49391.1Skamil	}
49401.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
49411.1Skamil
49421.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
49431.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
49441.1Skamil
49451.1Skamil	validate_status_stopped(status, sigval);
49461.1Skamil
49471.77Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
49481.77Skamil	SYSCALL_REQUIRE(
49491.77Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
49501.77Skamil
49511.77Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
49521.77Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
49531.77Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
49541.77Skamil	    info.psi_siginfo.si_errno);
49551.77Skamil
49561.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
49571.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
49581.77Skamil
49591.143Skamil	if (strstr(iter, "LWPINFO") != NULL) {
49601.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
49611.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
49621.143Skamil		    != -1);
49631.1Skamil
49641.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
49651.143Skamil		ATF_REQUIRE(lwp.pl_lwpid > 0);
49661.1Skamil
49671.143Skamil		DPRINTF("Assert that lwp thread %d received event "
49681.143Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
49691.143Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
49701.143Skamil
49711.143Skamil		if (strstr(iter, "LWPSTATUS") != NULL) {
49721.143Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPSTATUS "
49731.143Skamil			    "for child\n");
49741.143Skamil			lwpstatus.pl_lwpid = lwp.pl_lwpid;
49751.143Skamil			SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child, &lwpstatus,
49761.143Skamil			    sizeof(lwpstatus)) != -1);
49771.143Skamil		}
49781.1Skamil
49791.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
49801.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
49811.143Skamil		    != -1);
49821.1Skamil
49831.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
49841.143Skamil		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
49851.143Skamil	} else {
49861.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
49871.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
49881.143Skamil		    sizeof(lwpstatus)) != -1);
49891.143Skamil
49901.143Skamil		DPRINTF("Assert that there exists a single thread only %d\n", lwpstatus.pl_lwpid);
49911.143Skamil		ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
49921.143Skamil
49931.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
49941.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
49951.143Skamil		    sizeof(lwpstatus)) != -1);
49961.143Skamil
49971.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
49981.143Skamil		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
49991.143Skamil	}
50001.1Skamil
50011.13Schristos	DPRINTF("Before resuming the child process where it left off and "
50021.1Skamil	    "without signal to be sent\n");
50031.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
50041.1Skamil
50051.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
50061.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
50071.1Skamil
50081.77Skamil	validate_status_stopped(status, sigval2);
50091.77Skamil
50101.77Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
50111.77Skamil	SYSCALL_REQUIRE(
50121.77Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
50131.77Skamil
50141.77Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
50151.77Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
50161.77Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
50171.77Skamil	    info.psi_siginfo.si_errno);
50181.77Skamil
50191.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval2);
50201.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
50211.77Skamil
50221.77Skamil	memset(&lwp, 0, sizeof(lwp));
50231.143Skamil	memset(&lwpstatus, 0, sizeof(lwpstatus));
50241.143Skamil
50251.143Skamil	memset(&io, 0, sizeof(io));
50261.143Skamil
50271.143Skamil	bytes_read = 0;
50281.143Skamil	io.piod_op = PIOD_READ_D;
50291.143Skamil	io.piod_len = sizeof(tcb);
50301.143Skamil
50311.143Skamil	do {
50321.143Skamil		io.piod_addr = (char *)&tcb + bytes_read;
50331.143Skamil		io.piod_offs = io.piod_addr;
50341.143Skamil
50351.143Skamil		rv = ptrace(PT_IO, child, &io, sizeof(io));
50361.143Skamil		ATF_REQUIRE(rv != -1 && io.piod_len != 0);
50371.143Skamil
50381.143Skamil		bytes_read += io.piod_len;
50391.143Skamil		io.piod_len = sizeof(tcb) - bytes_read;
50401.143Skamil	} while (bytes_read < sizeof(tcb));
50411.77Skamil
50421.77Skamil	for (n = 0; n <= threads; n++) {
50431.143Skamil		if (strstr(iter, "LWPINFO") != NULL) {
50441.143Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
50451.143Skamil			    "child\n");
50461.143Skamil			SYSCALL_REQUIRE(
50471.143Skamil			    ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
50481.143Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
50491.143Skamil
50501.143Skamil			DPRINTF("Assert that the thread exists\n");
50511.143Skamil			ATF_REQUIRE(lwp.pl_lwpid > 0);
50521.143Skamil
50531.143Skamil			DPRINTF("Assert that lwp thread %d received expected "
50541.143Skamil			    "event\n", lwp.pl_lwpid);
50551.143Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
50561.143Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
50571.143Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
50581.143Skamil
50591.143Skamil			if (strstr(iter, "LWPSTATUS") != NULL) {
50601.143Skamil				DPRINTF("Before calling ptrace(2) with "
50611.143Skamil				    "PT_LWPSTATUS for child\n");
50621.143Skamil				lwpstatus.pl_lwpid = lwp.pl_lwpid;
50631.143Skamil				SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child,
50641.143Skamil				    &lwpstatus, sizeof(lwpstatus)) != -1);
50651.143Skamil
50661.143Skamil				goto check_lwpstatus;
50671.143Skamil			}
50681.143Skamil		} else {
50691.143Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for "
50701.143Skamil			    "child\n");
50711.143Skamil			SYSCALL_REQUIRE(
50721.143Skamil			    ptrace(PT_LWPNEXT, child, &lwpstatus,
50731.143Skamil			    sizeof(lwpstatus)) != -1);
50741.143Skamil			DPRINTF("LWP=%d\n", lwpstatus.pl_lwpid);
50751.143Skamil
50761.143Skamil			DPRINTF("Assert that the thread exists\n");
50771.143Skamil			ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
50781.143Skamil
50791.143Skamil		check_lwpstatus:
50801.143Skamil
50811.143Skamil			if (strstr(iter, "pl_sigmask") != NULL) {
50821.143Skamil				sigmask = lwpstatus.pl_sigmask;
50831.143Skamil
50841.143Skamil				DPRINTF("Retrieved sigmask: "
50851.143Skamil				    "%02x%02x%02x%02x\n",
50861.143Skamil				    sigmask.__bits[0], sigmask.__bits[1],
50871.143Skamil				    sigmask.__bits[2], sigmask.__bits[3]);
50881.143Skamil
50891.143Skamil				found = false;
50901.143Skamil				for (m = 0;
50911.143Skamil				     m < __arraycount(lwpinfo_thread_sigmask);
50921.143Skamil				     m++) {
50931.143Skamil					if (sigismember(&sigmask,
50941.143Skamil					    lwpinfo_thread_sigmask[m])) {
50951.143Skamil						found = true;
50961.143Skamil						lwpinfo_thread_sigmask[m] = 0;
50971.143Skamil						break;
50981.143Skamil					}
50991.143Skamil				}
51001.143Skamil				ATF_REQUIRE(found == true);
51011.143Skamil			} else if (strstr(iter, "pl_name") != NULL) {
51021.143Skamil				name = lwpstatus.pl_name;
51031.143Skamil
51041.143Skamil				DPRINTF("Retrieved thread name: "
51051.143Skamil				    "%s\n", name);
51061.143Skamil
51071.143Skamil				snprintf(namebuf, sizeof namebuf, "thread %d",
51081.143Skamil				    lwpstatus.pl_lwpid);
51091.143Skamil
51101.143Skamil				ATF_REQUIRE(strcmp(name, namebuf) == 0);
51111.143Skamil			} else if (strstr(iter, "pl_private") != NULL) {
51121.143Skamil				private = lwpstatus.pl_private;
51131.143Skamil
51141.143Skamil				DPRINTF("Retrieved thread private pointer: "
51151.143Skamil				    "%p\n", private);
51161.143Skamil
51171.143Skamil				found = false;
51181.143Skamil				for (m = 0; m < __arraycount(tcb); m++) {
51191.143Skamil					DPRINTF("Comparing %p and %p\n",
51201.143Skamil					    private, tcb[m]);
51211.143Skamil					if (private == tcb[m]) {
51221.143Skamil						found = true;
51231.143Skamil						break;
51241.143Skamil					}
51251.143Skamil				}
51261.143Skamil				ATF_REQUIRE(found == true);
51271.143Skamil			}
51281.143Skamil		}
51291.143Skamil	}
51301.143Skamil
51311.143Skamil	if (strstr(iter, "LWPINFO") != NULL) {
51321.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
51331.143Skamil		    "child\n");
51341.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
51351.143Skamil		    != -1);
51361.77Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
51371.77Skamil
51381.143Skamil		DPRINTF("Assert that there are no more threads\n");
51391.143Skamil		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
51401.143Skamil	} else {
51411.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
51421.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
51431.143Skamil		    sizeof(lwpstatus)) != -1);
51441.77Skamil
51451.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
51461.143Skamil		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
51471.143Skamil	}
51481.77Skamil
51491.77Skamil	DPRINTF("Before resuming the child process where it left off and "
51501.77Skamil	    "without signal to be sent\n");
51511.77Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, SIGKILL) != -1);
51521.77Skamil
51531.77Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
51541.77Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
51551.77Skamil
51561.77Skamil	validate_status_signaled(status, SIGKILL, 0);
51571.1Skamil
51581.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
51591.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
51601.1Skamil}
51611.1Skamil
51621.143Skamil#define TRACEME_LWPINFO(test, threads, iter)				\
51631.77SkamilATF_TC(test);								\
51641.77SkamilATF_TC_HEAD(test, tc)							\
51651.77Skamil{									\
51661.77Skamil	atf_tc_set_md_var(tc, "descr",					\
51671.143Skamil	    "Verify " iter " with the child with " #threads		\
51681.77Skamil	    " spawned extra threads");					\
51691.77Skamil}									\
51701.77Skamil									\
51711.77SkamilATF_TC_BODY(test, tc)							\
51721.77Skamil{									\
51731.77Skamil									\
51741.143Skamil	traceme_lwpinfo(threads, iter);					\
51751.1Skamil}
51761.1Skamil
51771.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0, 0, "LWPINFO")
51781.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1, 1, "LWPINFO")
51791.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2, 2, "LWPINFO")
51801.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3, 3, "LWPINFO")
51811.143Skamil
51821.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus, 0, "LWPINFO+LWPSTATUS")
51831.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus, 1, "LWPINFO+LWPSTATUS")
51841.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus, 2, "LWPINFO+LWPSTATUS")
51851.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus, 3, "LWPINFO+LWPSTATUS")
51861.143Skamil
51871.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_sigmask, 0,
51881.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
51891.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_sigmask, 1,
51901.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
51911.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_sigmask, 2,
51921.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
51931.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_sigmask, 3,
51941.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
51951.143Skamil
51961.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_name, 0,
51971.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
51981.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_name, 1,
51991.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
52001.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_name, 2,
52011.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
52021.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_name, 3,
52031.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
52041.143Skamil
52051.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_private, 0,
52061.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
52071.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_private, 1,
52081.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
52091.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_private, 2,
52101.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
52111.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_private, 3,
52121.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
52131.143Skamil
52141.143SkamilTRACEME_LWPINFO(traceme_lwpnext0, 0, "LWPNEXT")
52151.143SkamilTRACEME_LWPINFO(traceme_lwpnext1, 1, "LWPNEXT")
52161.143SkamilTRACEME_LWPINFO(traceme_lwpnext2, 2, "LWPNEXT")
52171.143SkamilTRACEME_LWPINFO(traceme_lwpnext3, 3, "LWPNEXT")
52181.143Skamil
52191.143SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_sigmask, 0, "LWPNEXT+pl_sigmask")
52201.143SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_sigmask, 1, "LWPNEXT+pl_sigmask")
52211.143SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_sigmask, 2, "LWPNEXT+pl_sigmask")
52221.143SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_sigmask, 3, "LWPNEXT+pl_sigmask")
52231.143Skamil
52241.143SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_name, 0, "LWPNEXT+pl_name")
52251.143SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_name, 1, "LWPNEXT+pl_name")
52261.143SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_name, 2, "LWPNEXT+pl_name")
52271.143SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_name, 3, "LWPNEXT+pl_name")
52281.143Skamil
52291.143SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_private, 0, "LWPNEXT+pl_private")
52301.143SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_private, 1, "LWPNEXT+pl_private")
52311.143SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_private, 2, "LWPNEXT+pl_private")
52321.143SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_private, 3, "LWPNEXT+pl_private")
52331.77Skamil
52341.77Skamil/// ----------------------------------------------------------------------------
52351.77Skamil
52361.77Skamil#if defined(TWAIT_HAVE_PID)
52371.77Skamilstatic void
52381.77Skamilattach_lwpinfo(const int threads)
52391.1Skamil{
52401.77Skamil	const int sigval = SIGINT;
52411.1Skamil	struct msg_fds parent_tracee, parent_tracer;
52421.1Skamil	const int exitval_tracer = 10;
52431.1Skamil	pid_t tracee, tracer, wpid;
52441.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
52451.1Skamil#if defined(TWAIT_HAVE_STATUS)
52461.1Skamil	int status;
52471.1Skamil#endif
52481.77Skamil	struct ptrace_lwpinfo lwp = {0, 0};
52491.77Skamil	struct ptrace_siginfo info;
52501.77Skamil
52511.77Skamil	/* Maximum number of supported threads in this test */
52521.77Skamil	pthread_t t[3];
52531.77Skamil	int n, rv;
52541.1Skamil
52551.13Schristos	DPRINTF("Spawn tracee\n");
52561.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
52571.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
52581.1Skamil	tracee = atf_utils_fork();
52591.1Skamil	if (tracee == 0) {
52601.1Skamil		/* Wait for message from the parent */
52611.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
52621.1Skamil
52631.77Skamil		CHILD_FROM_PARENT("spawn threads", parent_tracee, msg);
52641.77Skamil
52651.77Skamil		for (n = 0; n < threads; n++) {
52661.77Skamil			rv = pthread_create(&t[n], NULL, infinite_thread, NULL);
52671.77Skamil			FORKEE_ASSERT(rv == 0);
52681.77Skamil		}
52691.77Skamil
52701.77Skamil		CHILD_TO_PARENT("tracee exit", parent_tracee, msg);
52711.77Skamil
52721.77Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
52731.77Skamil		FORKEE_ASSERT(raise(sigval) == 0);
52741.77Skamil
52751.77Skamil		/* NOTREACHED */
52761.77Skamil		FORKEE_ASSERTX(0 && "Not reached");
52771.1Skamil	}
52781.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
52791.1Skamil
52801.13Schristos	DPRINTF("Spawn debugger\n");
52811.1Skamil	tracer = atf_utils_fork();
52821.1Skamil	if (tracer == 0) {
52831.1Skamil		/* No IPC to communicate with the child */
52841.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
52851.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
52861.1Skamil
52871.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
52881.1Skamil		FORKEE_REQUIRE_SUCCESS(
52891.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
52901.1Skamil
52911.1Skamil		forkee_status_stopped(status, SIGSTOP);
52921.1Skamil
52931.77Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
52941.77Skamil		    "tracee");
52951.77Skamil		FORKEE_ASSERT(
52961.77Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
52971.77Skamil
52981.77Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
52991.77Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
53001.77Skamil		    "si_errno=%#x\n",
53011.77Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
53021.77Skamil		    info.psi_siginfo.si_errno);
53031.77Skamil
53041.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
53051.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
53061.77Skamil
53071.13Schristos		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
53081.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
53091.1Skamil		    != -1);
53101.1Skamil
53111.13Schristos		DPRINTF("Assert that there exists a thread\n");
53121.77Skamil		FORKEE_ASSERTX(lwp.pl_lwpid > 0);
53131.1Skamil
53141.13Schristos		DPRINTF("Assert that lwp thread %d received event "
53151.77Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
53161.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
53171.1Skamil
53181.77Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
53191.77Skamil		    "tracee\n");
53201.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
53211.1Skamil		    != -1);
53221.1Skamil
53231.77Skamil		DPRINTF("Assert that there are no more lwp threads in "
53241.77Skamil		    "tracee\n");
53251.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
53261.1Skamil
53271.1Skamil		/* Resume tracee with PT_CONTINUE */
53281.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
53291.1Skamil
53301.1Skamil		/* Inform parent that tracer has attached to tracee */
53311.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
53321.77Skamil
53331.1Skamil		/* Wait for parent */
53341.1Skamil		CHILD_FROM_PARENT("tracer wait", parent_tracer, msg);
53351.1Skamil
53361.77Skamil		/* Wait for tracee and assert that it raised a signal */
53371.77Skamil		FORKEE_REQUIRE_SUCCESS(
53381.77Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
53391.77Skamil
53401.77Skamil		forkee_status_stopped(status, SIGINT);
53411.77Skamil
53421.77Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
53431.77Skamil		    "child");
53441.77Skamil		FORKEE_ASSERT(
53451.77Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
53461.77Skamil
53471.77Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
53481.77Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
53491.77Skamil		    "si_errno=%#x\n",
53501.77Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
53511.77Skamil		    info.psi_siginfo.si_errno);
53521.77Skamil
53531.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
53541.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
53551.77Skamil
53561.77Skamil		memset(&lwp, 0, sizeof(lwp));
53571.77Skamil
53581.77Skamil		for (n = 0; n <= threads; n++) {
53591.77Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
53601.77Skamil			    "child\n");
53611.77Skamil			FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp,
53621.77Skamil			    sizeof(lwp)) != -1);
53631.77Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
53641.77Skamil
53651.77Skamil			DPRINTF("Assert that the thread exists\n");
53661.77Skamil			FORKEE_ASSERT(lwp.pl_lwpid > 0);
53671.77Skamil
53681.77Skamil			DPRINTF("Assert that lwp thread %d received expected "
53691.77Skamil			    "event\n", lwp.pl_lwpid);
53701.77Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
53711.77Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
53721.77Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
53731.77Skamil		}
53741.77Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
53751.77Skamil		    "tracee\n");
53761.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
53771.77Skamil		    != -1);
53781.77Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
53791.77Skamil
53801.77Skamil		DPRINTF("Assert that there are no more threads\n");
53811.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
53821.77Skamil
53831.77Skamil		DPRINTF("Before resuming the child process where it left off "
53841.77Skamil		    "and without signal to be sent\n");
53851.77Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, SIGKILL)
53861.77Skamil		    != -1);
53871.77Skamil
53881.1Skamil		/* Wait for tracee and assert that it exited */
53891.1Skamil		FORKEE_REQUIRE_SUCCESS(
53901.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
53911.1Skamil
53921.77Skamil		forkee_status_signaled(status, SIGKILL, 0);
53931.1Skamil
53941.13Schristos		DPRINTF("Before exiting of the tracer process\n");
53951.1Skamil		_exit(exitval_tracer);
53961.1Skamil	}
53971.1Skamil
53981.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
53991.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
54001.1Skamil
54011.77Skamil	DPRINTF("Resume the tracee and spawn threads\n");
54021.77Skamil	PARENT_TO_CHILD("spawn threads", parent_tracee, msg);
54031.77Skamil
54041.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
54051.77Skamil	PARENT_FROM_CHILD("tracee exit", parent_tracee, msg);
54061.1Skamil
54071.77Skamil	DPRINTF("Resume the tracer and let it detect multiple threads\n");
54081.1Skamil	PARENT_TO_CHILD("tracer wait", parent_tracer, msg);
54091.1Skamil
54101.13Schristos	DPRINTF("Wait for tracer to finish its job and exit - calling %s()\n",
54111.1Skamil	    TWAIT_FNAME);
54121.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
54131.1Skamil	    tracer);
54141.1Skamil
54151.1Skamil	validate_status_exited(status, exitval_tracer);
54161.1Skamil
54171.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
54181.1Skamil	    TWAIT_FNAME);
54191.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
54201.1Skamil	    tracee);
54211.1Skamil
54221.77Skamil	validate_status_signaled(status, SIGKILL, 0);
54231.1Skamil
54241.1Skamil	msg_close(&parent_tracer);
54251.1Skamil	msg_close(&parent_tracee);
54261.1Skamil}
54271.77Skamil
54281.77Skamil#define ATTACH_LWPINFO(test, threads)					\
54291.77SkamilATF_TC(test);								\
54301.77SkamilATF_TC_HEAD(test, tc)							\
54311.77Skamil{									\
54321.77Skamil	atf_tc_set_md_var(tc, "descr",					\
54331.77Skamil	    "Verify LWPINFO with the child with " #threads		\
54341.77Skamil	    " spawned extra threads (tracer is not the original "	\
54351.77Skamil	    "parent)");							\
54361.77Skamil}									\
54371.77Skamil									\
54381.77SkamilATF_TC_BODY(test, tc)							\
54391.77Skamil{									\
54401.77Skamil									\
54411.77Skamil	attach_lwpinfo(threads);					\
54421.77Skamil}
54431.77Skamil
54441.77SkamilATTACH_LWPINFO(attach_lwpinfo0, 0)
54451.77SkamilATTACH_LWPINFO(attach_lwpinfo1, 1)
54461.77SkamilATTACH_LWPINFO(attach_lwpinfo2, 2)
54471.77SkamilATTACH_LWPINFO(attach_lwpinfo3, 3)
54481.1Skamil#endif
54491.1Skamil
54501.77Skamil/// ----------------------------------------------------------------------------
54511.77Skamil
54521.1Skamilstatic void
54531.79Skamilptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c), int *signal_caught)
54541.1Skamil{
54551.1Skamil	const int exitval = 5;
54561.1Skamil	const int sigval = SIGINT;
54571.1Skamil	const int sigfaked = SIGTRAP;
54581.1Skamil	const int sicodefaked = TRAP_BRKPT;
54591.1Skamil	pid_t child, wpid;
54601.1Skamil	struct sigaction sa;
54611.1Skamil#if defined(TWAIT_HAVE_STATUS)
54621.1Skamil	int status;
54631.1Skamil#endif
54641.1Skamil	struct ptrace_siginfo info;
54651.1Skamil	memset(&info, 0, sizeof(info));
54661.1Skamil
54671.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
54681.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
54691.1Skamil	if (child == 0) {
54701.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
54711.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
54721.1Skamil
54731.79Skamil		sa.sa_sigaction = sah;
54741.1Skamil		sa.sa_flags = SA_SIGINFO;
54751.1Skamil		sigemptyset(&sa.sa_mask);
54761.1Skamil
54771.79Skamil		FORKEE_ASSERT(sigaction(faked ? sigfaked : sigval, &sa, NULL)
54781.79Skamil		    != -1);
54791.1Skamil
54801.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
54811.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
54821.1Skamil
54831.79Skamil		FORKEE_ASSERT_EQ(*signal_caught, 1);
54841.1Skamil
54851.13Schristos		DPRINTF("Before exiting of the child process\n");
54861.1Skamil		_exit(exitval);
54871.1Skamil	}
54881.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
54891.1Skamil
54901.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
54911.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
54921.1Skamil
54931.1Skamil	validate_status_stopped(status, sigval);
54941.1Skamil
54951.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
54961.61Skre	SYSCALL_REQUIRE(
54971.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
54981.1Skamil
54991.13Schristos	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
55001.13Schristos	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
55011.1Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
55021.1Skamil	    info.psi_siginfo.si_errno);
55031.1Skamil
55041.79Skamil	if (faked) {
55051.79Skamil		DPRINTF("Before setting new faked signal to signo=%d "
55061.79Skamil		    "si_code=%d\n", sigfaked, sicodefaked);
55071.79Skamil		info.psi_siginfo.si_signo = sigfaked;
55081.79Skamil		info.psi_siginfo.si_code = sicodefaked;
55091.79Skamil	}
55101.1Skamil
55111.13Schristos	DPRINTF("Before calling ptrace(2) with PT_SET_SIGINFO for child\n");
55121.61Skre	SYSCALL_REQUIRE(
55131.61Skre	    ptrace(PT_SET_SIGINFO, child, &info, sizeof(info)) != -1);
55141.1Skamil
55151.79Skamil	if (faked) {
55161.79Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
55171.79Skamil		    "child\n");
55181.79Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
55191.79Skamil		    sizeof(info)) != -1);
55201.1Skamil
55211.79Skamil		DPRINTF("Before checking siginfo_t\n");
55221.79Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigfaked);
55231.79Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, sicodefaked);
55241.79Skamil	}
55251.1Skamil
55261.13Schristos	DPRINTF("Before resuming the child process where it left off and "
55271.1Skamil	    "without signal to be sent\n");
55281.79Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
55291.79Skamil	    faked ? sigfaked : sigval) != -1);
55301.1Skamil
55311.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
55321.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
55331.1Skamil
55341.1Skamil	validate_status_exited(status, exitval);
55351.1Skamil
55361.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
55371.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
55381.1Skamil}
55391.1Skamil
55401.79Skamil#define PTRACE_SIGINFO(test, faked)					\
55411.79SkamilATF_TC(test);								\
55421.79SkamilATF_TC_HEAD(test, tc)							\
55431.79Skamil{									\
55441.79Skamil	atf_tc_set_md_var(tc, "descr",					\
55451.79Skamil	    "Verify basic PT_GET_SIGINFO and PT_SET_SIGINFO calls"	\
55461.79Skamil	    "with%s setting signal to new value", faked ? "" : "out");	\
55471.79Skamil}									\
55481.79Skamil									\
55491.79Skamilstatic int test##_caught = 0;						\
55501.79Skamil									\
55511.79Skamilstatic void								\
55521.79Skamiltest##_sighandler(int sig, siginfo_t *info, void *ctx)			\
55531.79Skamil{									\
55541.79Skamil	if (faked) {							\
55551.79Skamil		FORKEE_ASSERT_EQ(sig, SIGTRAP);				\
55561.79Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGTRAP);		\
55571.79Skamil		FORKEE_ASSERT_EQ(info->si_code, TRAP_BRKPT);		\
55581.79Skamil	} else {							\
55591.79Skamil		FORKEE_ASSERT_EQ(sig, SIGINT);				\
55601.79Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGINT);		\
55611.79Skamil		FORKEE_ASSERT_EQ(info->si_code, SI_LWP);		\
55621.79Skamil	}								\
55631.79Skamil									\
55641.79Skamil	++ test##_caught;						\
55651.79Skamil}									\
55661.79Skamil									\
55671.79SkamilATF_TC_BODY(test, tc)							\
55681.79Skamil{									\
55691.79Skamil									\
55701.79Skamil	ptrace_siginfo(faked, test##_sighandler, & test##_caught); 	\
55711.79Skamil}
55721.79Skamil
55731.79SkamilPTRACE_SIGINFO(siginfo_set_unmodified, false)
55741.79SkamilPTRACE_SIGINFO(siginfo_set_faked, true)
55751.79Skamil
55761.79Skamil/// ----------------------------------------------------------------------------
55771.79Skamil
55781.97Skamilstatic void
55791.97Skamiltraceme_exec(bool masked, bool ignored)
55801.1Skamil{
55811.1Skamil	const int sigval = SIGTRAP;
55821.1Skamil	pid_t child, wpid;
55831.1Skamil#if defined(TWAIT_HAVE_STATUS)
55841.1Skamil	int status;
55851.1Skamil#endif
55861.97Skamil	struct sigaction sa;
55871.97Skamil	struct ptrace_siginfo info;
55881.97Skamil	sigset_t intmask;
55891.97Skamil	struct kinfo_proc2 kp;
55901.97Skamil	size_t len = sizeof(kp);
55911.97Skamil
55921.97Skamil	int name[6];
55931.97Skamil	const size_t namelen = __arraycount(name);
55941.97Skamil	ki_sigset_t kp_sigmask;
55951.97Skamil	ki_sigset_t kp_sigignore;
55961.1Skamil
55971.1Skamil	memset(&info, 0, sizeof(info));
55981.1Skamil
55991.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
56001.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
56011.1Skamil	if (child == 0) {
56021.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
56031.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
56041.1Skamil
56051.97Skamil		if (masked) {
56061.97Skamil			sigemptyset(&intmask);
56071.97Skamil			sigaddset(&intmask, sigval);
56081.97Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
56091.97Skamil		}
56101.97Skamil
56111.97Skamil		if (ignored) {
56121.97Skamil			memset(&sa, 0, sizeof(sa));
56131.97Skamil			sa.sa_handler = SIG_IGN;
56141.97Skamil			sigemptyset(&sa.sa_mask);
56151.97Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
56161.97Skamil		}
56171.97Skamil
56181.13Schristos		DPRINTF("Before calling execve(2) from child\n");
56191.1Skamil		execlp("/bin/echo", "/bin/echo", NULL);
56201.1Skamil
56211.1Skamil		FORKEE_ASSERT(0 && "Not reached");
56221.1Skamil	}
56231.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
56241.1Skamil
56251.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
56261.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
56271.1Skamil
56281.1Skamil	validate_status_stopped(status, sigval);
56291.1Skamil
56301.97Skamil	name[0] = CTL_KERN,
56311.97Skamil	name[1] = KERN_PROC2,
56321.97Skamil	name[2] = KERN_PROC_PID;
56331.97Skamil	name[3] = getpid();
56341.97Skamil	name[4] = sizeof(kp);
56351.97Skamil	name[5] = 1;
56361.97Skamil
56371.97Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
56381.97Skamil
56391.97Skamil	if (masked)
56401.97Skamil		kp_sigmask = kp.p_sigmask;
56411.97Skamil
56421.97Skamil	if (ignored)
56431.97Skamil		kp_sigignore = kp.p_sigignore;
56441.97Skamil
56451.97Skamil	name[3] = getpid();
56461.97Skamil
56471.97Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
56481.97Skamil
56491.97Skamil	if (masked) {
56501.97Skamil		DPRINTF("kp_sigmask="
56511.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
56521.97Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
56531.97Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
56541.97Skamil
56551.97Skamil		DPRINTF("kp.p_sigmask="
56561.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
56571.97Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
56581.97Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
56591.97Skamil
56601.97Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
56611.97Skamil		    sizeof(kp_sigmask)));
56621.97Skamil	}
56631.97Skamil
56641.97Skamil	if (ignored) {
56651.97Skamil		DPRINTF("kp_sigignore="
56661.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
56671.97Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
56681.97Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
56691.97Skamil
56701.97Skamil		DPRINTF("kp.p_sigignore="
56711.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
56721.97Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
56731.97Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
56741.97Skamil
56751.97Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
56761.97Skamil		    sizeof(kp_sigignore)));
56771.97Skamil	}
56781.97Skamil
56791.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
56801.61Skre	SYSCALL_REQUIRE(
56811.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
56821.1Skamil
56831.13Schristos	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
56841.13Schristos	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
56851.1Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
56861.1Skamil	    info.psi_siginfo.si_errno);
56871.1Skamil
56881.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
56891.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
56901.1Skamil
56911.13Schristos	DPRINTF("Before resuming the child process where it left off and "
56921.1Skamil	    "without signal to be sent\n");
56931.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
56941.1Skamil
56951.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
56961.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
56971.1Skamil
56981.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
56991.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
57001.1Skamil}
57011.1Skamil
57021.97Skamil#define TRACEME_EXEC(test, masked, ignored)				\
57031.97SkamilATF_TC(test);								\
57041.97SkamilATF_TC_HEAD(test, tc)							\
57051.97Skamil{									\
57061.97Skamil       atf_tc_set_md_var(tc, "descr",					\
57071.97Skamil           "Detect SIGTRAP TRAP_EXEC from "				\
57081.97Skamil           "child%s%s", masked ? " with masked signal" : "",		\
57091.97Skamil           masked ? " with ignored signal" : "");			\
57101.97Skamil}									\
57111.97Skamil									\
57121.97SkamilATF_TC_BODY(test, tc)							\
57131.97Skamil{									\
57141.97Skamil									\
57151.97Skamil       traceme_exec(masked, ignored);					\
57161.97Skamil}
57171.97Skamil
57181.97SkamilTRACEME_EXEC(traceme_exec, false, false)
57191.97SkamilTRACEME_EXEC(traceme_signalmasked_exec, true, false)
57201.97SkamilTRACEME_EXEC(traceme_signalignored_exec, false, true)
57211.97Skamil
57221.82Skamil/// ----------------------------------------------------------------------------
57231.82Skamil
57241.135Skamil#define TRACE_THREADS_NUM 100
57251.135Skamil
57261.83Skamilstatic volatile int done;
57271.137Skamilpthread_mutex_t trace_threads_mtx = PTHREAD_MUTEX_INITIALIZER;
57281.1Skamil
57291.83Skamilstatic void *
57301.83Skamiltrace_threads_cb(void *arg __unused)
57311.1Skamil{
57321.1Skamil
57331.137Skamil	pthread_mutex_lock(&trace_threads_mtx);
57341.83Skamil	done++;
57351.137Skamil	pthread_mutex_unlock(&trace_threads_mtx);
57361.83Skamil
57371.135Skamil	while (done < TRACE_THREADS_NUM)
57381.135Skamil		sched_yield();
57391.83Skamil
57401.83Skamil	return NULL;
57411.1Skamil}
57421.1Skamil
57431.83Skamilstatic void
57441.83Skamiltrace_threads(bool trace_create, bool trace_exit)
57451.1Skamil{
57461.1Skamil	const int sigval = SIGSTOP;
57471.1Skamil	pid_t child, wpid;
57481.1Skamil#if defined(TWAIT_HAVE_STATUS)
57491.1Skamil	int status;
57501.1Skamil#endif
57511.1Skamil	ptrace_state_t state;
57521.1Skamil	const int slen = sizeof(state);
57531.1Skamil	ptrace_event_t event;
57541.1Skamil	const int elen = sizeof(event);
57551.83Skamil	struct ptrace_siginfo info;
57561.83Skamil
57571.135Skamil	pthread_t t[TRACE_THREADS_NUM];
57581.83Skamil	int rv;
57591.83Skamil	size_t n;
57601.1Skamil	lwpid_t lid;
57611.83Skamil
57621.83Skamil	/* Track created and exited threads */
57631.141Skamil	struct lwp_event_count traced_lwps[__arraycount(t)] = {{0, 0}};
57641.83Skamil
57651.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
57661.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
57671.1Skamil	if (child == 0) {
57681.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
57691.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
57701.1Skamil
57711.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
57721.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
57731.1Skamil
57741.83Skamil		for (n = 0; n < __arraycount(t); n++) {
57751.83Skamil			rv = pthread_create(&t[n], NULL, trace_threads_cb,
57761.83Skamil			    NULL);
57771.83Skamil			FORKEE_ASSERT(rv == 0);
57781.83Skamil		}
57791.1Skamil
57801.83Skamil		for (n = 0; n < __arraycount(t); n++) {
57811.83Skamil			rv = pthread_join(t[n], NULL);
57821.83Skamil			FORKEE_ASSERT(rv == 0);
57831.83Skamil		}
57841.1Skamil
57851.83Skamil		/*
57861.83Skamil		 * There is race between _exit() and pthread_join() detaching
57871.83Skamil		 * a thread. For simplicity kill the process after detecting
57881.83Skamil		 * LWP events.
57891.83Skamil		 */
57901.83Skamil		while (true)
57911.83Skamil			continue;
57921.1Skamil
57931.83Skamil		FORKEE_ASSERT(0 && "Not reached");
57941.1Skamil	}
57951.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
57961.1Skamil
57971.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
57981.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
57991.1Skamil
58001.1Skamil	validate_status_stopped(status, sigval);
58011.1Skamil
58021.83Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
58031.83Skamil	SYSCALL_REQUIRE(
58041.83Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
58051.1Skamil
58061.83Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
58071.83Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
58081.83Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
58091.83Skamil	    info.psi_siginfo.si_errno);
58101.1Skamil
58111.83Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
58121.83Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
58131.1Skamil
58141.83Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
58151.83Skamil	memset(&event, 0, sizeof(event));
58161.83Skamil	if (trace_create)
58171.83Skamil		event.pe_set_event |= PTRACE_LWP_CREATE;
58181.83Skamil	if (trace_exit)
58191.83Skamil		event.pe_set_event |= PTRACE_LWP_EXIT;
58201.83Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
58211.1Skamil
58221.13Schristos	DPRINTF("Before resuming the child process where it left off and "
58231.1Skamil	    "without signal to be sent\n");
58241.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
58251.1Skamil
58261.83Skamil	for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
58271.83Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
58281.83Skamil		    "SIGTRAP\n", TWAIT_FNAME);
58291.83Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
58301.83Skamil		    child);
58311.1Skamil
58321.83Skamil		validate_status_stopped(status, SIGTRAP);
58331.1Skamil
58341.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
58351.83Skamil		    "child\n");
58361.83Skamil		SYSCALL_REQUIRE(
58371.83Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
58381.1Skamil
58391.83Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
58401.83Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
58411.83Skamil		    "si_errno=%#x\n",
58421.83Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
58431.83Skamil		    info.psi_siginfo.si_errno);
58441.1Skamil
58451.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
58461.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
58471.1Skamil
58481.83Skamil		SYSCALL_REQUIRE(
58491.83Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
58501.1Skamil
58511.83Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
58521.83Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
58531.1Skamil
58541.83Skamil		lid = state.pe_lwp;
58551.83Skamil		DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
58561.1Skamil
58571.141Skamil		*FIND_EVENT_COUNT(traced_lwps, lid) += 1;
58581.1Skamil
58591.83Skamil		DPRINTF("Before resuming the child process where it left off "
58601.83Skamil		    "and without signal to be sent\n");
58611.83Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
58621.83Skamil	}
58631.1Skamil
58641.83Skamil	for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
58651.83Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
58661.83Skamil		    "SIGTRAP\n", TWAIT_FNAME);
58671.83Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
58681.83Skamil		    child);
58691.1Skamil
58701.83Skamil		validate_status_stopped(status, SIGTRAP);
58711.1Skamil
58721.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
58731.83Skamil		    "child\n");
58741.83Skamil		SYSCALL_REQUIRE(
58751.83Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
58761.1Skamil
58771.83Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
58781.83Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
58791.83Skamil		    "si_errno=%#x\n",
58801.83Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
58811.83Skamil		    info.psi_siginfo.si_errno);
58821.1Skamil
58831.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
58841.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
58851.1Skamil
58861.83Skamil		SYSCALL_REQUIRE(
58871.83Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
58881.1Skamil
58891.83Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
58901.83Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
58911.1Skamil
58921.83Skamil		lid = state.pe_lwp;
58931.83Skamil		DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
58941.1Skamil
58951.83Skamil		if (trace_create) {
58961.141Skamil			int *count = FIND_EVENT_COUNT(traced_lwps, lid);
58971.141Skamil			ATF_REQUIRE_EQ(*count, 1);
58981.141Skamil			*count = 0;
58991.83Skamil		}
59001.1Skamil
59011.83Skamil		DPRINTF("Before resuming the child process where it left off "
59021.83Skamil		    "and without signal to be sent\n");
59031.83Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
59041.83Skamil	}
59051.1Skamil
59061.83Skamil	kill(child, SIGKILL);
59071.1Skamil
59081.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
59091.1Skamil	    TWAIT_FNAME);
59101.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
59111.1Skamil
59121.83Skamil	validate_status_signaled(status, SIGKILL, 0);
59131.1Skamil
59141.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
59151.1Skamil	    TWAIT_FNAME);
59161.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
59171.1Skamil}
59181.1Skamil
59191.83Skamil#define TRACE_THREADS(test, trace_create, trace_exit)			\
59201.83SkamilATF_TC(test);								\
59211.83SkamilATF_TC_HEAD(test, tc)							\
59221.83Skamil{									\
59231.83Skamil        atf_tc_set_md_var(tc, "descr",					\
59241.83Skamil            "Verify spawning threads with%s tracing LWP create and"	\
59251.83Skamil	    "with%s tracing LWP exit", trace_create ? "" : "out",	\
59261.83Skamil	    trace_exit ? "" : "out");					\
59271.83Skamil}									\
59281.83Skamil									\
59291.83SkamilATF_TC_BODY(test, tc)							\
59301.83Skamil{									\
59311.83Skamil									\
59321.83Skamil        trace_threads(trace_create, trace_exit);			\
59331.83Skamil}
59341.83Skamil
59351.119SkamilTRACE_THREADS(trace_thread_nolwpevents, false, false)
59361.119SkamilTRACE_THREADS(trace_thread_lwpexit, false, true)
59371.119SkamilTRACE_THREADS(trace_thread_lwpcreate, true, false)
59381.119SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true)
59391.83Skamil
59401.83Skamil/// ----------------------------------------------------------------------------
59411.83Skamil
59421.84SkamilATF_TC(signal_mask_unrelated);
59431.84SkamilATF_TC_HEAD(signal_mask_unrelated, tc)
59441.1Skamil{
59451.1Skamil	atf_tc_set_md_var(tc, "descr",
59461.1Skamil	    "Verify that masking single unrelated signal does not stop tracer "
59471.1Skamil	    "from catching other signals");
59481.1Skamil}
59491.1Skamil
59501.84SkamilATF_TC_BODY(signal_mask_unrelated, tc)
59511.1Skamil{
59521.1Skamil	const int exitval = 5;
59531.1Skamil	const int sigval = SIGSTOP;
59541.1Skamil	const int sigmasked = SIGTRAP;
59551.1Skamil	const int signotmasked = SIGINT;
59561.1Skamil	pid_t child, wpid;
59571.1Skamil#if defined(TWAIT_HAVE_STATUS)
59581.1Skamil	int status;
59591.1Skamil#endif
59601.1Skamil	sigset_t intmask;
59611.1Skamil
59621.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
59631.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
59641.1Skamil	if (child == 0) {
59651.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
59661.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
59671.1Skamil
59681.1Skamil		sigemptyset(&intmask);
59691.1Skamil		sigaddset(&intmask, sigmasked);
59701.1Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
59711.1Skamil
59721.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
59731.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
59741.1Skamil
59751.13Schristos		DPRINTF("Before raising %s from child\n",
59761.1Skamil		    strsignal(signotmasked));
59771.1Skamil		FORKEE_ASSERT(raise(signotmasked) == 0);
59781.1Skamil
59791.13Schristos		DPRINTF("Before exiting of the child process\n");
59801.1Skamil		_exit(exitval);
59811.1Skamil	}
59821.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
59831.1Skamil
59841.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
59851.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
59861.1Skamil
59871.1Skamil	validate_status_stopped(status, sigval);
59881.1Skamil
59891.13Schristos	DPRINTF("Before resuming the child process where it left off and "
59901.1Skamil	    "without signal to be sent\n");
59911.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
59921.1Skamil
59931.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
59941.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
59951.1Skamil
59961.1Skamil	validate_status_stopped(status, signotmasked);
59971.1Skamil
59981.13Schristos	DPRINTF("Before resuming the child process where it left off and "
59991.1Skamil	    "without signal to be sent\n");
60001.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
60011.1Skamil
60021.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
60031.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
60041.1Skamil
60051.1Skamil	validate_status_exited(status, exitval);
60061.1Skamil
60071.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
60081.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
60091.1Skamil}
60101.1Skamil
60111.84Skamil/// ----------------------------------------------------------------------------
60121.84Skamil
60131.1Skamil#if defined(TWAIT_HAVE_PID)
60141.99Skamilstatic void
60151.126Skamilfork2_body(const char *fn, bool masked, bool ignored)
60161.1Skamil{
60171.1Skamil	const int exitval = 5;
60181.126Skamil	const int exitval2 = 0; /* Match exit status from /bin/echo */
60191.1Skamil	const int sigval = SIGSTOP;
60201.99Skamil	pid_t child, child2 = 0, wpid;
60211.1Skamil#if defined(TWAIT_HAVE_STATUS)
60221.1Skamil	int status;
60231.1Skamil#endif
60241.1Skamil	ptrace_state_t state;
60251.1Skamil	const int slen = sizeof(state);
60261.1Skamil	ptrace_event_t event;
60271.1Skamil	const int elen = sizeof(event);
60281.99Skamil	struct sigaction sa;
60291.99Skamil	struct ptrace_siginfo info;
60301.99Skamil	sigset_t intmask;
60311.99Skamil	struct kinfo_proc2 kp;
60321.99Skamil	size_t len = sizeof(kp);
60331.99Skamil
60341.99Skamil	int name[6];
60351.99Skamil	const size_t namelen = __arraycount(name);
60361.99Skamil	ki_sigset_t kp_sigmask;
60371.99Skamil	ki_sigset_t kp_sigignore;
60381.1Skamil
60391.126Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
60401.14Schristos
60411.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
60421.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
60431.1Skamil	if (child == 0) {
60441.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
60451.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
60461.1Skamil
60471.99Skamil		if (masked) {
60481.99Skamil			sigemptyset(&intmask);
60491.99Skamil			sigaddset(&intmask, SIGTRAP);
60501.99Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
60511.99Skamil		}
60521.99Skamil
60531.99Skamil		if (ignored) {
60541.99Skamil			memset(&sa, 0, sizeof(sa));
60551.99Skamil			sa.sa_handler = SIG_IGN;
60561.99Skamil			sigemptyset(&sa.sa_mask);
60571.99Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
60581.99Skamil		}
60591.1Skamil
60601.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
60611.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
60621.1Skamil
60631.126Skamil		if (strcmp(fn, "spawn") == 0) {
60641.126Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
60651.126Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
60661.126Skamil		} else  {
60671.126Skamil			if (strcmp(fn, "fork") == 0) {
60681.126Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
60691.126Skamil			} else {
60701.126Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
60711.126Skamil			}
60721.126Skamil			if (child2 == 0)
60731.126Skamil				_exit(exitval2);
60741.126Skamil		}
60751.1Skamil
60761.1Skamil		FORKEE_REQUIRE_SUCCESS
60771.99Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
60781.1Skamil
60791.1Skamil		forkee_status_exited(status, exitval2);
60801.1Skamil
60811.13Schristos		DPRINTF("Before exiting of the child process\n");
60821.1Skamil		_exit(exitval);
60831.1Skamil	}
60841.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
60851.1Skamil
60861.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
60871.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
60881.1Skamil
60891.1Skamil	validate_status_stopped(status, sigval);
60901.1Skamil
60911.99Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
60921.99Skamil	SYSCALL_REQUIRE(
60931.99Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
60941.99Skamil
60951.99Skamil	DPRINTF("Before checking siginfo_t\n");
60961.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
60971.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
60981.1Skamil
60991.99Skamil	name[0] = CTL_KERN,
61001.99Skamil	name[1] = KERN_PROC2,
61011.99Skamil	name[2] = KERN_PROC_PID;
61021.99Skamil	name[3] = child;
61031.99Skamil	name[4] = sizeof(kp);
61041.99Skamil	name[5] = 1;
61051.1Skamil
61061.99Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
61071.1Skamil
61081.99Skamil	if (masked)
61091.99Skamil		kp_sigmask = kp.p_sigmask;
61101.1Skamil
61111.99Skamil	if (ignored)
61121.99Skamil		kp_sigignore = kp.p_sigignore;
61131.1Skamil
61141.126Skamil	DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
61151.126Skamil	    strcmp(fn, "spawn") == 0 ? "|PTRACE_POSIX_SPAWN" : "",
61161.126Skamil	    strcmp(fn, "fork") == 0 ? "|PTRACE_FORK" : "",
61171.126Skamil	    strcmp(fn, "vfork") == 0 ? "|PTRACE_VFORK" : "",
61181.126Skamil	    strcmp(fn, "vforkdone") == 0 ? "|PTRACE_VFORK_DONE" : "", child);
61191.99Skamil	event.pe_set_event = 0;
61201.126Skamil	if (strcmp(fn, "spawn") == 0)
61211.126Skamil		event.pe_set_event |= PTRACE_POSIX_SPAWN;
61221.126Skamil	if (strcmp(fn, "fork") == 0)
61231.99Skamil		event.pe_set_event |= PTRACE_FORK;
61241.126Skamil	if (strcmp(fn, "vfork") == 0)
61251.99Skamil		event.pe_set_event |= PTRACE_VFORK;
61261.126Skamil	if (strcmp(fn, "vforkdone") == 0)
61271.99Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
61281.99Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
61291.1Skamil
61301.99Skamil	DPRINTF("Before resuming the child process where it left off and "
61311.99Skamil	    "without signal to be sent\n");
61321.99Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
61331.1Skamil
61341.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
61351.126Skamil	    strcmp(fn, "vfork") == 0) {
61361.99Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
61371.99Skamil		    child);
61381.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
61391.99Skamil		    child);
61401.1Skamil
61411.99Skamil		validate_status_stopped(status, SIGTRAP);
61421.1Skamil
61431.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
61441.1Skamil
61451.99Skamil		if (masked) {
61461.99Skamil			DPRINTF("kp_sigmask="
61471.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
61481.99Skamil			    PRIx32 "\n",
61491.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
61501.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
61511.1Skamil
61521.99Skamil			DPRINTF("kp.p_sigmask="
61531.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
61541.99Skamil			    PRIx32 "\n",
61551.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
61561.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
61571.1Skamil
61581.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
61591.99Skamil			    sizeof(kp_sigmask)));
61601.99Skamil		}
61611.1Skamil
61621.99Skamil		if (ignored) {
61631.99Skamil			DPRINTF("kp_sigignore="
61641.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
61651.99Skamil			    PRIx32 "\n",
61661.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
61671.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
61681.1Skamil
61691.99Skamil			DPRINTF("kp.p_sigignore="
61701.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
61711.99Skamil			    PRIx32 "\n",
61721.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
61731.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
61741.1Skamil
61751.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
61761.99Skamil			    sizeof(kp_sigignore)));
61771.99Skamil		}
61781.1Skamil
61791.99Skamil		SYSCALL_REQUIRE(
61801.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
61811.126Skamil		if (strcmp(fn, "spawn") == 0) {
61821.126Skamil			ATF_REQUIRE_EQ(
61831.126Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
61841.126Skamil			       PTRACE_POSIX_SPAWN);
61851.126Skamil		}
61861.126Skamil		if (strcmp(fn, "fork") == 0) {
61871.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
61881.99Skamil			       PTRACE_FORK);
61891.99Skamil		}
61901.126Skamil		if (strcmp(fn, "vfork") == 0) {
61911.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
61921.99Skamil			       PTRACE_VFORK);
61931.99Skamil		}
61941.1Skamil
61951.99Skamil		child2 = state.pe_other_pid;
61961.99Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
61971.1Skamil
61981.99Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
61991.99Skamil		    "%d\n", TWAIT_FNAME, child2, child);
62001.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
62011.99Skamil		    child2);
62021.1Skamil
62031.99Skamil		validate_status_stopped(status, SIGTRAP);
62041.1Skamil
62051.99Skamil		name[3] = child2;
62061.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
62071.1Skamil
62081.99Skamil		if (masked) {
62091.99Skamil			DPRINTF("kp_sigmask="
62101.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
62111.99Skamil			    PRIx32 "\n",
62121.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
62131.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
62141.1Skamil
62151.99Skamil			DPRINTF("kp.p_sigmask="
62161.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
62171.99Skamil			    PRIx32 "\n",
62181.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
62191.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
62201.14Schristos
62211.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
62221.99Skamil			    sizeof(kp_sigmask)));
62231.99Skamil		}
62241.1Skamil
62251.99Skamil		if (ignored) {
62261.99Skamil			DPRINTF("kp_sigignore="
62271.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
62281.99Skamil			    PRIx32 "\n",
62291.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
62301.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
62311.1Skamil
62321.99Skamil			DPRINTF("kp.p_sigignore="
62331.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
62341.99Skamil			    PRIx32 "\n",
62351.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
62361.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
62371.1Skamil
62381.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
62391.99Skamil			    sizeof(kp_sigignore)));
62401.99Skamil		}
62411.1Skamil
62421.99Skamil		SYSCALL_REQUIRE(
62431.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
62441.126Skamil		if (strcmp(fn, "spawn") == 0) {
62451.126Skamil			ATF_REQUIRE_EQ(
62461.126Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
62471.126Skamil			       PTRACE_POSIX_SPAWN);
62481.126Skamil		}
62491.126Skamil		if (strcmp(fn, "fork") == 0) {
62501.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
62511.99Skamil			       PTRACE_FORK);
62521.99Skamil		}
62531.126Skamil		if (strcmp(fn, "vfork") == 0) {
62541.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
62551.99Skamil			       PTRACE_VFORK);
62561.99Skamil		}
62571.1Skamil
62581.99Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
62591.1Skamil
62601.99Skamil		DPRINTF("Before resuming the forkee process where it left off "
62611.99Skamil		    "and without signal to be sent\n");
62621.99Skamil		SYSCALL_REQUIRE(
62631.99Skamil		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
62641.1Skamil
62651.99Skamil		DPRINTF("Before resuming the child process where it left off "
62661.99Skamil		    "and without signal to be sent\n");
62671.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
62681.1Skamil	}
62691.1Skamil
62701.126Skamil	if (strcmp(fn, "vforkdone") == 0) {
62711.99Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
62721.99Skamil		    child);
62731.99Skamil		TWAIT_REQUIRE_SUCCESS(
62741.99Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
62751.1Skamil
62761.99Skamil		validate_status_stopped(status, SIGTRAP);
62771.1Skamil
62781.99Skamil		name[3] = child;
62791.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
62801.1Skamil
62811.102Skamil		/*
62821.102Skamil		 * SIGCHLD is now pending in the signal queue and
62831.102Skamil		 * the kernel presents it to userland as a masked signal.
62841.102Skamil		 */
62851.102Skamil		sigdelset((sigset_t *)&kp.p_sigmask, SIGCHLD);
62861.102Skamil
62871.99Skamil		if (masked) {
62881.99Skamil			DPRINTF("kp_sigmask="
62891.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
62901.99Skamil			    PRIx32 "\n",
62911.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
62921.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
62931.1Skamil
62941.99Skamil			DPRINTF("kp.p_sigmask="
62951.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
62961.99Skamil			    PRIx32 "\n",
62971.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
62981.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
62991.1Skamil
63001.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
63011.99Skamil			    sizeof(kp_sigmask)));
63021.99Skamil		}
63031.1Skamil
63041.99Skamil		if (ignored) {
63051.99Skamil			DPRINTF("kp_sigignore="
63061.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
63071.99Skamil			    PRIx32 "\n",
63081.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
63091.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
63101.1Skamil
63111.99Skamil			DPRINTF("kp.p_sigignore="
63121.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
63131.99Skamil			    PRIx32 "\n",
63141.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
63151.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
63161.1Skamil
63171.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
63181.99Skamil			    sizeof(kp_sigignore)));
63191.99Skamil		}
63201.1Skamil
63211.99Skamil		SYSCALL_REQUIRE(
63221.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
63231.99Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
63241.1Skamil
63251.99Skamil		child2 = state.pe_other_pid;
63261.99Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
63271.99Skamil		    child2);
63281.1Skamil
63291.99Skamil		DPRINTF("Before resuming the child process where it left off "
63301.99Skamil		    "and without signal to be sent\n");
63311.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
63321.99Skamil	}
63331.1Skamil
63341.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
63351.126Skamil	    strcmp(fn, "vfork") == 0) {
63361.99Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
63371.99Skamil		    "\n", TWAIT_FNAME);
63381.99Skamil		TWAIT_REQUIRE_SUCCESS(
63391.99Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
63401.1Skamil
63411.99Skamil		validate_status_exited(status, exitval2);
63421.1Skamil
63431.99Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
63441.99Skamil		    "process\n", TWAIT_FNAME);
63451.99Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
63461.99Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
63471.99Skamil	}
63481.1Skamil
63491.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
63501.1Skamil	    "SIGCHLD\n", TWAIT_FNAME);
63511.57Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
63521.1Skamil
63531.1Skamil	validate_status_stopped(status, SIGCHLD);
63541.1Skamil
63551.57Skamil	DPRINTF("Before resuming the child process where it left off and "
63561.1Skamil	    "without signal to be sent\n");
63571.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
63581.1Skamil
63591.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
63601.1Skamil	    TWAIT_FNAME);
63611.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
63621.1Skamil
63631.1Skamil	validate_status_exited(status, exitval);
63641.1Skamil
63651.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
63661.57Skamil	    TWAIT_FNAME);
63671.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
63681.1Skamil}
63691.1Skamil
63701.126Skamil#define FORK2_TEST(name,fn,masked,ignored)				\
63711.99SkamilATF_TC(name);								\
63721.99SkamilATF_TC_HEAD(name, tc)							\
63731.99Skamil{									\
63741.126Skamil	atf_tc_set_md_var(tc, "descr", "Verify that " fn " is caught "	\
63751.99Skamil	    "regardless of signal %s%s", 				\
63761.99Skamil	    masked ? "masked" : "", ignored ? "ignored" : "");		\
63771.99Skamil}									\
63781.99Skamil									\
63791.99SkamilATF_TC_BODY(name, tc)							\
63801.99Skamil{									\
63811.99Skamil									\
63821.126Skamil	fork2_body(fn, masked, ignored);				\
63831.1Skamil}
63841.1Skamil
63851.126SkamilFORK2_TEST(posix_spawn_singalmasked, "spawn", true, false)
63861.126SkamilFORK2_TEST(posix_spawn_singalignored, "spawn", false, true)
63871.126SkamilFORK2_TEST(fork_singalmasked, "fork", true, false)
63881.126SkamilFORK2_TEST(fork_singalignored, "fork", false, true)
63891.126SkamilFORK2_TEST(vfork_singalmasked, "vfork", true, false)
63901.126SkamilFORK2_TEST(vfork_singalignored, "vfork", false, true)
63911.126SkamilFORK2_TEST(vforkdone_singalmasked, "vforkdone", true, false)
63921.126SkamilFORK2_TEST(vforkdone_singalignored, "vforkdone", false, true)
63931.1Skamil#endif
63941.1Skamil
63951.99Skamil/// ----------------------------------------------------------------------------
63961.1Skamil
63971.83Skamilvolatile lwpid_t the_lwp_id = 0;
63981.83Skamil
63991.83Skamilstatic void
64001.83Skamillwp_main_func(void *arg)
64011.83Skamil{
64021.83Skamil	the_lwp_id = _lwp_self();
64031.83Skamil	_lwp_exit();
64041.83Skamil}
64051.83Skamil
64061.1SkamilATF_TC(signal9);
64071.1SkamilATF_TC_HEAD(signal9, tc)
64081.1Skamil{
64091.1Skamil	atf_tc_set_md_var(tc, "descr",
64101.1Skamil	    "Verify that masking SIGTRAP in tracee does not stop tracer from "
64111.1Skamil	    "catching PTRACE_LWP_CREATE breakpoint");
64121.1Skamil}
64131.1Skamil
64141.1SkamilATF_TC_BODY(signal9, tc)
64151.1Skamil{
64161.1Skamil	const int exitval = 5;
64171.1Skamil	const int sigval = SIGSTOP;
64181.1Skamil	const int sigmasked = SIGTRAP;
64191.1Skamil	pid_t child, wpid;
64201.1Skamil#if defined(TWAIT_HAVE_STATUS)
64211.1Skamil	int status;
64221.1Skamil#endif
64231.1Skamil	sigset_t intmask;
64241.1Skamil	ptrace_state_t state;
64251.1Skamil	const int slen = sizeof(state);
64261.1Skamil	ptrace_event_t event;
64271.1Skamil	const int elen = sizeof(event);
64281.1Skamil	ucontext_t uc;
64291.1Skamil	lwpid_t lid;
64301.1Skamil	static const size_t ssize = 16*1024;
64311.1Skamil	void *stack;
64321.1Skamil
64331.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
64341.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
64351.1Skamil	if (child == 0) {
64361.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
64371.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
64381.1Skamil
64391.1Skamil		sigemptyset(&intmask);
64401.1Skamil		sigaddset(&intmask, sigmasked);
64411.1Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
64421.1Skamil
64431.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
64441.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
64451.1Skamil
64461.13Schristos		DPRINTF("Before allocating memory for stack in child\n");
64471.1Skamil		FORKEE_ASSERT((stack = malloc(ssize)) != NULL);
64481.1Skamil
64491.13Schristos		DPRINTF("Before making context for new lwp in child\n");
64501.1Skamil		_lwp_makecontext(&uc, lwp_main_func, NULL, NULL, stack, ssize);
64511.1Skamil
64521.13Schristos		DPRINTF("Before creating new in child\n");
64531.1Skamil		FORKEE_ASSERT(_lwp_create(&uc, 0, &lid) == 0);
64541.1Skamil
64551.13Schristos		DPRINTF("Before waiting for lwp %d to exit\n", lid);
64561.1Skamil		FORKEE_ASSERT(_lwp_wait(lid, NULL) == 0);
64571.1Skamil
64581.13Schristos		DPRINTF("Before verifying that reported %d and running lid %d "
64591.1Skamil		    "are the same\n", lid, the_lwp_id);
64601.1Skamil		FORKEE_ASSERT_EQ(lid, the_lwp_id);
64611.1Skamil
64621.13Schristos		DPRINTF("Before exiting of the child process\n");
64631.1Skamil		_exit(exitval);
64641.1Skamil	}
64651.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
64661.1Skamil
64671.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
64681.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64691.1Skamil
64701.1Skamil	validate_status_stopped(status, sigval);
64711.1Skamil
64721.13Schristos	DPRINTF("Set empty EVENT_MASK for the child %d\n", child);
64731.1Skamil	event.pe_set_event = PTRACE_LWP_CREATE;
64741.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
64751.1Skamil
64761.13Schristos	DPRINTF("Before resuming the child process where it left off and "
64771.1Skamil	    "without signal to be sent\n");
64781.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
64791.1Skamil
64801.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
64811.1Skamil	    "SIGTRAP\n", TWAIT_FNAME);
64821.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64831.1Skamil
64841.1Skamil	validate_status_stopped(status, sigmasked);
64851.1Skamil
64861.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
64871.1Skamil
64881.1Skamil	ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_LWP_CREATE);
64891.1Skamil
64901.1Skamil	lid = state.pe_lwp;
64911.13Schristos	DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
64921.1Skamil
64931.13Schristos	DPRINTF("Before resuming the child process where it left off and "
64941.1Skamil	    "without signal to be sent\n");
64951.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
64961.1Skamil
64971.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
64981.1Skamil	    TWAIT_FNAME);
64991.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
65001.1Skamil
65011.1Skamil	validate_status_exited(status, exitval);
65021.1Skamil
65031.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
65041.1Skamil	    TWAIT_FNAME);
65051.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
65061.1Skamil}
65071.1Skamil
65081.1SkamilATF_TC(signal10);
65091.1SkamilATF_TC_HEAD(signal10, tc)
65101.1Skamil{
65111.1Skamil	atf_tc_set_md_var(tc, "descr",
65121.1Skamil	    "Verify that masking SIGTRAP in tracee does not stop tracer from "
65131.1Skamil	    "catching PTRACE_LWP_EXIT breakpoint");
65141.1Skamil}
65151.1Skamil
65161.1SkamilATF_TC_BODY(signal10, tc)
65171.1Skamil{
65181.1Skamil	const int exitval = 5;
65191.1Skamil	const int sigval = SIGSTOP;
65201.1Skamil	const int sigmasked = SIGTRAP;
65211.1Skamil	pid_t child, wpid;
65221.1Skamil#if defined(TWAIT_HAVE_STATUS)
65231.1Skamil	int status;
65241.1Skamil#endif
65251.1Skamil	sigset_t intmask;
65261.1Skamil	ptrace_state_t state;
65271.1Skamil	const int slen = sizeof(state);
65281.1Skamil	ptrace_event_t event;
65291.1Skamil	const int elen = sizeof(event);
65301.1Skamil	ucontext_t uc;
65311.1Skamil	lwpid_t lid;
65321.1Skamil	static const size_t ssize = 16*1024;
65331.1Skamil	void *stack;
65341.1Skamil
65351.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
65361.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
65371.1Skamil	if (child == 0) {
65381.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
65391.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
65401.1Skamil
65411.1Skamil		sigemptyset(&intmask);
65421.1Skamil		sigaddset(&intmask, sigmasked);
65431.1Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
65441.1Skamil
65451.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
65461.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
65471.1Skamil
65481.13Schristos		DPRINTF("Before allocating memory for stack in child\n");
65491.1Skamil		FORKEE_ASSERT((stack = malloc(ssize)) != NULL);
65501.1Skamil
65511.13Schristos		DPRINTF("Before making context for new lwp in child\n");
65521.1Skamil		_lwp_makecontext(&uc, lwp_main_func, NULL, NULL, stack, ssize);
65531.1Skamil
65541.13Schristos		DPRINTF("Before creating new in child\n");
65551.1Skamil		FORKEE_ASSERT(_lwp_create(&uc, 0, &lid) == 0);
65561.1Skamil
65571.13Schristos		DPRINTF("Before waiting for lwp %d to exit\n", lid);
65581.1Skamil		FORKEE_ASSERT(_lwp_wait(lid, NULL) == 0);
65591.1Skamil
65601.13Schristos		DPRINTF("Before verifying that reported %d and running lid %d "
65611.1Skamil		    "are the same\n", lid, the_lwp_id);
65621.1Skamil		FORKEE_ASSERT_EQ(lid, the_lwp_id);
65631.1Skamil
65641.13Schristos		DPRINTF("Before exiting of the child process\n");
65651.1Skamil		_exit(exitval);
65661.1Skamil	}
65671.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
65681.1Skamil
65691.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
65701.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
65711.1Skamil
65721.1Skamil	validate_status_stopped(status, sigval);
65731.1Skamil
65741.13Schristos	DPRINTF("Set empty EVENT_MASK for the child %d\n", child);
65751.1Skamil	event.pe_set_event = PTRACE_LWP_EXIT;
65761.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
65771.1Skamil
65781.13Schristos	DPRINTF("Before resuming the child process where it left off and "
65791.1Skamil	    "without signal to be sent\n");
65801.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
65811.1Skamil
65821.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
65831.1Skamil	    "SIGTRAP\n", TWAIT_FNAME);
65841.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
65851.1Skamil
65861.1Skamil	validate_status_stopped(status, sigmasked);
65871.1Skamil
65881.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
65891.1Skamil
65901.1Skamil	ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_LWP_EXIT);
65911.1Skamil
65921.1Skamil	lid = state.pe_lwp;
65931.13Schristos	DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
65941.1Skamil
65951.13Schristos	DPRINTF("Before resuming the child process where it left off and "
65961.1Skamil	    "without signal to be sent\n");
65971.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
65981.1Skamil
65991.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
66001.1Skamil	    TWAIT_FNAME);
66011.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66021.1Skamil
66031.1Skamil	validate_status_exited(status, exitval);
66041.1Skamil
66051.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
66061.1Skamil	    TWAIT_FNAME);
66071.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
66081.1Skamil}
66091.1Skamil
66101.1Skamilstatic void
66111.1Skamillwp_main_stop(void *arg)
66121.1Skamil{
66131.1Skamil	the_lwp_id = _lwp_self();
66141.1Skamil
66151.1Skamil	raise(SIGTRAP);
66161.1Skamil
66171.1Skamil	_lwp_exit();
66181.1Skamil}
66191.1Skamil
66201.1SkamilATF_TC(suspend2);
66211.1SkamilATF_TC_HEAD(suspend2, tc)
66221.1Skamil{
66231.1Skamil	atf_tc_set_md_var(tc, "descr",
66241.1Skamil	    "Verify that the while the only thread within a process is "
66251.1Skamil	    "suspended, the whole process cannot be unstopped");
66261.1Skamil}
66271.1Skamil
66281.1SkamilATF_TC_BODY(suspend2, tc)
66291.1Skamil{
66301.1Skamil	const int exitval = 5;
66311.1Skamil	const int sigval = SIGSTOP;
66321.1Skamil	pid_t child, wpid;
66331.1Skamil#if defined(TWAIT_HAVE_STATUS)
66341.1Skamil	int status;
66351.1Skamil#endif
66361.1Skamil	struct ptrace_siginfo psi;
66371.1Skamil
66381.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
66391.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
66401.1Skamil	if (child == 0) {
66411.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
66421.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
66431.1Skamil
66441.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
66451.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
66461.1Skamil
66471.13Schristos		DPRINTF("Before exiting of the child process\n");
66481.1Skamil		_exit(exitval);
66491.1Skamil	}
66501.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
66511.1Skamil
66521.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
66531.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66541.1Skamil
66551.1Skamil	validate_status_stopped(status, sigval);
66561.1Skamil
66571.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
66581.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
66591.1Skamil
66601.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
66611.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
66621.1Skamil
66631.13Schristos	DPRINTF("Before resuming the child process where it left off and "
66641.1Skamil	    "without signal to be sent\n");
66651.1Skamil	ATF_REQUIRE_ERRNO(EDEADLK,
66661.1Skamil	    ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
66671.1Skamil
66681.13Schristos	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
66691.13Schristos	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
66701.1Skamil
66711.13Schristos	DPRINTF("Before resuming the child process where it left off and "
66721.1Skamil	    "without signal to be sent\n");
66731.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
66741.1Skamil
66751.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
66761.1Skamil	    TWAIT_FNAME);
66771.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66781.1Skamil
66791.1Skamil	validate_status_exited(status, exitval);
66801.1Skamil
66811.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
66821.1Skamil	    TWAIT_FNAME);
66831.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
66841.1Skamil}
66851.1Skamil
66861.1SkamilATF_TC(resume1);
66871.1SkamilATF_TC_HEAD(resume1, tc)
66881.1Skamil{
66891.1Skamil	atf_tc_set_md_var(tc, "descr",
66901.1Skamil	    "Verify that a thread can be suspended by a debugger and later "
66911.1Skamil	    "resumed by the debugger");
66921.1Skamil}
66931.1Skamil
66941.1SkamilATF_TC_BODY(resume1, tc)
66951.1Skamil{
66961.1Skamil	struct msg_fds fds;
66971.1Skamil	const int exitval = 5;
66981.1Skamil	const int sigval = SIGSTOP;
66991.1Skamil	pid_t child, wpid;
67001.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
67011.1Skamil#if defined(TWAIT_HAVE_STATUS)
67021.1Skamil	int status;
67031.1Skamil#endif
67041.1Skamil	ucontext_t uc;
67051.1Skamil	lwpid_t lid;
67061.1Skamil	static const size_t ssize = 16*1024;
67071.1Skamil	void *stack;
67081.1Skamil	struct ptrace_lwpinfo pl;
67091.1Skamil	struct ptrace_siginfo psi;
67101.1Skamil
67111.13Schristos	SYSCALL_REQUIRE(msg_open(&fds) == 0);
67121.1Skamil
67131.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
67141.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
67151.1Skamil	if (child == 0) {
67161.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
67171.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
67181.1Skamil
67191.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
67201.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
67211.1Skamil
67221.13Schristos		DPRINTF("Before allocating memory for stack in child\n");
67231.1Skamil		FORKEE_ASSERT((stack = malloc(ssize)) != NULL);
67241.1Skamil
67251.13Schristos		DPRINTF("Before making context for new lwp in child\n");
67261.1Skamil		_lwp_makecontext(&uc, lwp_main_stop, NULL, NULL, stack, ssize);
67271.1Skamil
67281.13Schristos		DPRINTF("Before creating new in child\n");
67291.1Skamil		FORKEE_ASSERT(_lwp_create(&uc, 0, &lid) == 0);
67301.1Skamil
67311.1Skamil		CHILD_TO_PARENT("Message", fds, msg);
67321.1Skamil
67331.1Skamil		raise(SIGINT);
67341.1Skamil
67351.13Schristos		DPRINTF("Before waiting for lwp %d to exit\n", lid);
67361.1Skamil		FORKEE_ASSERT(_lwp_wait(lid, NULL) == 0);
67371.1Skamil
67381.13Schristos		DPRINTF("Before verifying that reported %d and running lid %d "
67391.1Skamil		    "are the same\n", lid, the_lwp_id);
67401.1Skamil		FORKEE_ASSERT_EQ(lid, the_lwp_id);
67411.1Skamil
67421.13Schristos		DPRINTF("Before exiting of the child process\n");
67431.1Skamil		_exit(exitval);
67441.1Skamil	}
67451.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
67461.1Skamil
67471.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
67481.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
67491.1Skamil
67501.1Skamil	validate_status_stopped(status, sigval);
67511.1Skamil
67521.13Schristos	DPRINTF("Before resuming the child process where it left off and "
67531.1Skamil	    "without signal to be sent\n");
67541.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
67551.1Skamil
67561.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
67571.1Skamil	    "SIGTRAP\n", TWAIT_FNAME);
67581.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
67591.1Skamil
67601.1Skamil	validate_status_stopped(status, SIGTRAP);
67611.1Skamil
67621.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
67631.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
67641.1Skamil
67651.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
67661.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
67671.1Skamil
67681.1Skamil	PARENT_FROM_CHILD("Message", fds, msg);
67691.1Skamil
67701.13Schristos	DPRINTF("Before resuming the child process where it left off and "
67711.1Skamil	    "without signal to be sent\n");
67721.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
67731.1Skamil
67741.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
67751.1Skamil	    "SIGINT\n", TWAIT_FNAME);
67761.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
67771.1Skamil
67781.1Skamil	validate_status_stopped(status, SIGINT);
67791.1Skamil
67801.1Skamil	pl.pl_lwpid = 0;
67811.1Skamil
67821.13Schristos	SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &pl, sizeof(pl)) != -1);
67831.1Skamil	while (pl.pl_lwpid != 0) {
67841.13Schristos		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &pl, sizeof(pl)) != -1);
67851.1Skamil		switch (pl.pl_lwpid) {
67861.1Skamil		case 1:
67871.1Skamil			ATF_REQUIRE_EQ(pl.pl_event, PL_EVENT_SIGNAL);
67881.1Skamil			break;
67891.1Skamil		case 2:
67901.1Skamil			ATF_REQUIRE_EQ(pl.pl_event, PL_EVENT_SUSPENDED);
67911.1Skamil			break;
67921.1Skamil		}
67931.1Skamil	}
67941.1Skamil
67951.13Schristos	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
67961.13Schristos	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
67971.1Skamil
67981.13Schristos	DPRINTF("Before resuming the child process where it left off and "
67991.1Skamil	    "without signal to be sent\n");
68001.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
68011.1Skamil
68021.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
68031.1Skamil	    TWAIT_FNAME);
68041.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68051.1Skamil
68061.1Skamil	validate_status_exited(status, exitval);
68071.1Skamil
68081.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
68091.1Skamil	    TWAIT_FNAME);
68101.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
68111.1Skamil
68121.1Skamil	msg_close(&fds);
68131.1Skamil}
68141.1Skamil
68151.1SkamilATF_TC(syscall1);
68161.1SkamilATF_TC_HEAD(syscall1, tc)
68171.1Skamil{
68181.1Skamil	atf_tc_set_md_var(tc, "descr",
68191.1Skamil	    "Verify that getpid(2) can be traced with PT_SYSCALL");
68201.1Skamil}
68211.1Skamil
68221.1SkamilATF_TC_BODY(syscall1, tc)
68231.1Skamil{
68241.1Skamil	const int exitval = 5;
68251.1Skamil	const int sigval = SIGSTOP;
68261.1Skamil	pid_t child, wpid;
68271.1Skamil#if defined(TWAIT_HAVE_STATUS)
68281.1Skamil	int status;
68291.1Skamil#endif
68301.1Skamil	struct ptrace_siginfo info;
68311.1Skamil	memset(&info, 0, sizeof(info));
68321.1Skamil
68331.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
68341.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
68351.1Skamil	if (child == 0) {
68361.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
68371.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
68381.1Skamil
68391.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
68401.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
68411.1Skamil
68421.1Skamil		syscall(SYS_getpid);
68431.1Skamil
68441.13Schristos		DPRINTF("Before exiting of the child process\n");
68451.1Skamil		_exit(exitval);
68461.1Skamil	}
68471.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
68481.1Skamil
68491.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68501.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68511.1Skamil
68521.1Skamil	validate_status_stopped(status, sigval);
68531.1Skamil
68541.13Schristos	DPRINTF("Before resuming the child process where it left off and "
68551.1Skamil	    "without signal to be sent\n");
68561.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
68571.1Skamil
68581.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68591.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68601.1Skamil
68611.1Skamil	validate_status_stopped(status, SIGTRAP);
68621.1Skamil
68631.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
68641.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
68651.1Skamil
68661.38Skamil	DPRINTF("Before checking siginfo_t and lwpid\n");
68671.38Skamil	ATF_REQUIRE_EQ(info.psi_lwpid, 1);
68681.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
68691.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_SCE);
68701.1Skamil
68711.13Schristos	DPRINTF("Before resuming the child process where it left off and "
68721.1Skamil	    "without signal to be sent\n");
68731.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
68741.1Skamil
68751.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68761.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68771.1Skamil
68781.1Skamil	validate_status_stopped(status, SIGTRAP);
68791.1Skamil
68801.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
68811.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
68821.1Skamil
68831.38Skamil	DPRINTF("Before checking siginfo_t and lwpid\n");
68841.38Skamil	ATF_REQUIRE_EQ(info.psi_lwpid, 1);
68851.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
68861.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_SCX);
68871.1Skamil
68881.13Schristos	DPRINTF("Before resuming the child process where it left off and "
68891.1Skamil	    "without signal to be sent\n");
68901.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
68911.1Skamil
68921.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68931.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68941.1Skamil
68951.1Skamil	validate_status_exited(status, exitval);
68961.1Skamil
68971.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68981.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
68991.1Skamil}
69001.1Skamil
69011.1SkamilATF_TC(syscallemu1);
69021.1SkamilATF_TC_HEAD(syscallemu1, tc)
69031.1Skamil{
69041.1Skamil	atf_tc_set_md_var(tc, "descr",
69051.1Skamil	    "Verify that exit(2) can be intercepted with PT_SYSCALLEMU");
69061.1Skamil}
69071.1Skamil
69081.1SkamilATF_TC_BODY(syscallemu1, tc)
69091.1Skamil{
69101.1Skamil	const int exitval = 5;
69111.1Skamil	const int sigval = SIGSTOP;
69121.1Skamil	pid_t child, wpid;
69131.1Skamil#if defined(TWAIT_HAVE_STATUS)
69141.1Skamil	int status;
69151.1Skamil#endif
69161.1Skamil
69171.6Skamil#if defined(__sparc__) && !defined(__sparc64__)
69181.6Skamil	/* syscallemu does not work on sparc (32-bit) */
69191.6Skamil	atf_tc_expect_fail("PR kern/52166");
69201.6Skamil#endif
69211.6Skamil
69221.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
69231.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
69241.1Skamil	if (child == 0) {
69251.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
69261.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
69271.1Skamil
69281.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
69291.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
69301.1Skamil
69311.1Skamil		syscall(SYS_exit, 100);
69321.1Skamil
69331.13Schristos		DPRINTF("Before exiting of the child process\n");
69341.1Skamil		_exit(exitval);
69351.1Skamil	}
69361.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
69371.1Skamil
69381.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
69391.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
69401.1Skamil
69411.1Skamil	validate_status_stopped(status, sigval);
69421.1Skamil
69431.13Schristos	DPRINTF("Before resuming the child process where it left off and "
69441.1Skamil	    "without signal to be sent\n");
69451.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
69461.1Skamil
69471.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
69481.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
69491.1Skamil
69501.1Skamil	validate_status_stopped(status, SIGTRAP);
69511.1Skamil
69521.13Schristos	DPRINTF("Set SYSCALLEMU for intercepted syscall\n");
69531.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALLEMU, child, (void *)1, 0) != -1);
69541.1Skamil
69551.13Schristos	DPRINTF("Before resuming the child process where it left off and "
69561.1Skamil	    "without signal to be sent\n");
69571.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
69581.1Skamil
69591.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
69601.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
69611.1Skamil
69621.1Skamil	validate_status_stopped(status, SIGTRAP);
69631.1Skamil
69641.13Schristos	DPRINTF("Before resuming the child process where it left off and "
69651.1Skamil	    "without signal to be sent\n");
69661.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
69671.1Skamil
69681.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
69691.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
69701.1Skamil
69711.1Skamil	validate_status_exited(status, exitval);
69721.1Skamil
69731.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
69741.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
69751.1Skamil}
69761.1Skamil
69771.103Skamil/// ----------------------------------------------------------------------------
69781.103Skamil
69791.106Skamilstatic void
69801.106Skamilclone_body(int flags, bool trackfork, bool trackvfork,
69811.106Skamil    bool trackvforkdone)
69821.106Skamil{
69831.106Skamil	const int exitval = 5;
69841.106Skamil	const int exitval2 = 15;
69851.106Skamil	const int sigval = SIGSTOP;
69861.106Skamil	pid_t child, child2 = 0, wpid;
69871.106Skamil#if defined(TWAIT_HAVE_STATUS)
69881.106Skamil	int status;
69891.106Skamil#endif
69901.106Skamil	ptrace_state_t state;
69911.106Skamil	const int slen = sizeof(state);
69921.106Skamil	ptrace_event_t event;
69931.106Skamil	const int elen = sizeof(event);
69941.106Skamil
69951.106Skamil	const size_t stack_size = 1024 * 1024;
69961.106Skamil	void *stack, *stack_base;
69971.106Skamil
69981.106Skamil	stack = malloc(stack_size);
69991.106Skamil	ATF_REQUIRE(stack != NULL);
70001.106Skamil
70011.106Skamil#ifdef __MACHINE_STACK_GROWS_UP
70021.106Skamil	stack_base = stack;
70031.106Skamil#else
70041.106Skamil	stack_base = (char *)stack + stack_size;
70051.106Skamil#endif
70061.106Skamil
70071.106Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
70081.106Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
70091.106Skamil	if (child == 0) {
70101.106Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
70111.106Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
70121.106Skamil
70131.106Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
70141.106Skamil		FORKEE_ASSERT(raise(sigval) == 0);
70151.106Skamil
70161.106Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
70171.106Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
70181.106Skamil
70191.106Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
70201.106Skamil		    child2);
70211.106Skamil
70221.106Skamil		// XXX WALLSIG?
70231.106Skamil		FORKEE_REQUIRE_SUCCESS
70241.106Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
70251.106Skamil
70261.106Skamil		forkee_status_exited(status, exitval2);
70271.106Skamil
70281.106Skamil		DPRINTF("Before exiting of the child process\n");
70291.106Skamil		_exit(exitval);
70301.106Skamil	}
70311.106Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
70321.106Skamil
70331.106Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
70341.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
70351.106Skamil
70361.106Skamil	validate_status_stopped(status, sigval);
70371.106Skamil
70381.106Skamil	DPRINTF("Set 0%s%s%s in EVENT_MASK for the child %d\n",
70391.106Skamil	    trackfork ? "|PTRACE_FORK" : "",
70401.106Skamil	    trackvfork ? "|PTRACE_VFORK" : "",
70411.106Skamil	    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", child);
70421.106Skamil	event.pe_set_event = 0;
70431.106Skamil	if (trackfork)
70441.106Skamil		event.pe_set_event |= PTRACE_FORK;
70451.106Skamil	if (trackvfork)
70461.106Skamil		event.pe_set_event |= PTRACE_VFORK;
70471.106Skamil	if (trackvforkdone)
70481.106Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
70491.106Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
70501.106Skamil
70511.106Skamil	DPRINTF("Before resuming the child process where it left off and "
70521.106Skamil	    "without signal to be sent\n");
70531.106Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
70541.106Skamil
70551.106Skamil#if defined(TWAIT_HAVE_PID)
70561.106Skamil	if ((trackfork && !(flags & CLONE_VFORK)) ||
70571.106Skamil	    (trackvfork && (flags & CLONE_VFORK))) {
70581.106Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
70591.106Skamil		    child);
70601.106Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
70611.106Skamil		    child);
70621.106Skamil
70631.106Skamil		validate_status_stopped(status, SIGTRAP);
70641.106Skamil
70651.106Skamil		SYSCALL_REQUIRE(
70661.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
70671.106Skamil		if (trackfork && !(flags & CLONE_VFORK)) {
70681.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
70691.106Skamil			       PTRACE_FORK);
70701.106Skamil		}
70711.106Skamil		if (trackvfork && (flags & CLONE_VFORK)) {
70721.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
70731.106Skamil			       PTRACE_VFORK);
70741.106Skamil		}
70751.106Skamil
70761.106Skamil		child2 = state.pe_other_pid;
70771.106Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
70781.106Skamil
70791.106Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
70801.106Skamil		    "%d\n", TWAIT_FNAME, child2, child);
70811.106Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
70821.106Skamil		    child2);
70831.106Skamil
70841.106Skamil		validate_status_stopped(status, SIGTRAP);
70851.106Skamil
70861.106Skamil		SYSCALL_REQUIRE(
70871.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
70881.106Skamil		if (trackfork && !(flags & CLONE_VFORK)) {
70891.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
70901.106Skamil			       PTRACE_FORK);
70911.106Skamil		}
70921.106Skamil		if (trackvfork && (flags & CLONE_VFORK)) {
70931.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
70941.106Skamil			       PTRACE_VFORK);
70951.106Skamil		}
70961.106Skamil
70971.106Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
70981.106Skamil
70991.106Skamil		DPRINTF("Before resuming the forkee process where it left off "
71001.106Skamil		    "and without signal to be sent\n");
71011.106Skamil		SYSCALL_REQUIRE(
71021.106Skamil		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
71031.106Skamil
71041.106Skamil		DPRINTF("Before resuming the child process where it left off "
71051.106Skamil		    "and without signal to be sent\n");
71061.106Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
71071.106Skamil	}
71081.106Skamil#endif
71091.106Skamil
71101.106Skamil	if (trackvforkdone && (flags & CLONE_VFORK)) {
71111.106Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
71121.106Skamil		    child);
71131.106Skamil		TWAIT_REQUIRE_SUCCESS(
71141.106Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
71151.106Skamil
71161.106Skamil		validate_status_stopped(status, SIGTRAP);
71171.106Skamil
71181.106Skamil		SYSCALL_REQUIRE(
71191.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
71201.106Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
71211.106Skamil
71221.106Skamil		child2 = state.pe_other_pid;
71231.106Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
71241.106Skamil		    child2);
71251.106Skamil
71261.106Skamil		DPRINTF("Before resuming the child process where it left off "
71271.106Skamil		    "and without signal to be sent\n");
71281.106Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
71291.106Skamil	}
71301.106Skamil
71311.103Skamil#if defined(TWAIT_HAVE_PID)
71321.106Skamil	if ((trackfork && !(flags & CLONE_VFORK)) ||
71331.106Skamil	    (trackvfork && (flags & CLONE_VFORK))) {
71341.106Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
71351.106Skamil		    "\n", TWAIT_FNAME);
71361.106Skamil		TWAIT_REQUIRE_SUCCESS(
71371.106Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
71381.106Skamil
71391.106Skamil		validate_status_exited(status, exitval2);
71401.106Skamil
71411.106Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
71421.106Skamil		    "process\n", TWAIT_FNAME);
71431.106Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
71441.106Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
71451.106Skamil	}
71461.106Skamil#endif
71471.106Skamil
71481.106Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
71491.106Skamil	    "SIGCHLD\n", TWAIT_FNAME);
71501.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
71511.106Skamil
71521.106Skamil	validate_status_stopped(status, SIGCHLD);
71531.106Skamil
71541.106Skamil	DPRINTF("Before resuming the child process where it left off and "
71551.106Skamil	    "without signal to be sent\n");
71561.106Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
71571.106Skamil
71581.106Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
71591.106Skamil	    TWAIT_FNAME);
71601.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
71611.106Skamil
71621.106Skamil	validate_status_exited(status, exitval);
71631.103Skamil
71641.106Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
71651.106Skamil	    TWAIT_FNAME);
71661.106Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
71671.106Skamil}
71681.103Skamil
71691.106Skamil#define CLONE_TEST(name,flags,tfork,tvfork,tvforkdone)			\
71701.106SkamilATF_TC(name);								\
71711.106SkamilATF_TC_HEAD(name, tc)							\
71721.106Skamil{									\
71731.106Skamil	atf_tc_set_md_var(tc, "descr", "Verify clone(%s) "		\
71741.106Skamil	    "called with 0%s%s%s in EVENT_MASK",			\
71751.106Skamil	    #flags,							\
71761.106Skamil	    tfork ? "|PTRACE_FORK" : "",				\
71771.106Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
71781.106Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
71791.106Skamil}									\
71801.106Skamil									\
71811.106SkamilATF_TC_BODY(name, tc)							\
71821.106Skamil{									\
71831.106Skamil									\
71841.106Skamil	clone_body(flags, tfork, tvfork, tvforkdone);			\
71851.103Skamil}
71861.103Skamil
71871.106SkamilCLONE_TEST(clone1, 0, false, false, false)
71881.106Skamil#if defined(TWAIT_HAVE_PID)
71891.106SkamilCLONE_TEST(clone2, 0, true, false, false)
71901.106SkamilCLONE_TEST(clone3, 0, false, true, false)
71911.106SkamilCLONE_TEST(clone4, 0, true, true, false)
71921.106Skamil#endif
71931.106SkamilCLONE_TEST(clone5, 0, false, false, true)
71941.106Skamil#if defined(TWAIT_HAVE_PID)
71951.106SkamilCLONE_TEST(clone6, 0, true, false, true)
71961.106SkamilCLONE_TEST(clone7, 0, false, true, true)
71971.106SkamilCLONE_TEST(clone8, 0, true, true, true)
71981.106Skamil#endif
71991.106Skamil
72001.106SkamilCLONE_TEST(clone_vm1, CLONE_VM, false, false, false)
72011.106Skamil#if defined(TWAIT_HAVE_PID)
72021.106SkamilCLONE_TEST(clone_vm2, CLONE_VM, true, false, false)
72031.106SkamilCLONE_TEST(clone_vm3, CLONE_VM, false, true, false)
72041.106SkamilCLONE_TEST(clone_vm4, CLONE_VM, true, true, false)
72051.106Skamil#endif
72061.106SkamilCLONE_TEST(clone_vm5, CLONE_VM, false, false, true)
72071.106Skamil#if defined(TWAIT_HAVE_PID)
72081.106SkamilCLONE_TEST(clone_vm6, CLONE_VM, true, false, true)
72091.106SkamilCLONE_TEST(clone_vm7, CLONE_VM, false, true, true)
72101.106SkamilCLONE_TEST(clone_vm8, CLONE_VM, true, true, true)
72111.106Skamil#endif
72121.106Skamil
72131.106SkamilCLONE_TEST(clone_fs1, CLONE_FS, false, false, false)
72141.106Skamil#if defined(TWAIT_HAVE_PID)
72151.106SkamilCLONE_TEST(clone_fs2, CLONE_FS, true, false, false)
72161.106SkamilCLONE_TEST(clone_fs3, CLONE_FS, false, true, false)
72171.106SkamilCLONE_TEST(clone_fs4, CLONE_FS, true, true, false)
72181.106Skamil#endif
72191.106SkamilCLONE_TEST(clone_fs5, CLONE_FS, false, false, true)
72201.106Skamil#if defined(TWAIT_HAVE_PID)
72211.106SkamilCLONE_TEST(clone_fs6, CLONE_FS, true, false, true)
72221.106SkamilCLONE_TEST(clone_fs7, CLONE_FS, false, true, true)
72231.106SkamilCLONE_TEST(clone_fs8, CLONE_FS, true, true, true)
72241.106Skamil#endif
72251.106Skamil
72261.106SkamilCLONE_TEST(clone_files1, CLONE_FILES, false, false, false)
72271.106Skamil#if defined(TWAIT_HAVE_PID)
72281.106SkamilCLONE_TEST(clone_files2, CLONE_FILES, true, false, false)
72291.106SkamilCLONE_TEST(clone_files3, CLONE_FILES, false, true, false)
72301.106SkamilCLONE_TEST(clone_files4, CLONE_FILES, true, true, false)
72311.106Skamil#endif
72321.106SkamilCLONE_TEST(clone_files5, CLONE_FILES, false, false, true)
72331.106Skamil#if defined(TWAIT_HAVE_PID)
72341.106SkamilCLONE_TEST(clone_files6, CLONE_FILES, true, false, true)
72351.106SkamilCLONE_TEST(clone_files7, CLONE_FILES, false, true, true)
72361.106SkamilCLONE_TEST(clone_files8, CLONE_FILES, true, true, true)
72371.106Skamil#endif
72381.106Skamil
72391.106Skamil//CLONE_TEST(clone_sighand1, CLONE_SIGHAND, false, false, false)
72401.106Skamil#if defined(TWAIT_HAVE_PID)
72411.106Skamil//CLONE_TEST(clone_sighand2, CLONE_SIGHAND, true, false, false)
72421.106Skamil//CLONE_TEST(clone_sighand3, CLONE_SIGHAND, false, true, false)
72431.106Skamil//CLONE_TEST(clone_sighand4, CLONE_SIGHAND, true, true, false)
72441.106Skamil#endif
72451.106Skamil//CLONE_TEST(clone_sighand5, CLONE_SIGHAND, false, false, true)
72461.106Skamil#if defined(TWAIT_HAVE_PID)
72471.106Skamil//CLONE_TEST(clone_sighand6, CLONE_SIGHAND, true, false, true)
72481.106Skamil//CLONE_TEST(clone_sighand7, CLONE_SIGHAND, false, true, true)
72491.106Skamil//CLONE_TEST(clone_sighand8, CLONE_SIGHAND, true, true, true)
72501.106Skamil#endif
72511.106Skamil
72521.106SkamilCLONE_TEST(clone_vfork1, CLONE_VFORK, false, false, false)
72531.106Skamil#if defined(TWAIT_HAVE_PID)
72541.106SkamilCLONE_TEST(clone_vfork2, CLONE_VFORK, true, false, false)
72551.106SkamilCLONE_TEST(clone_vfork3, CLONE_VFORK, false, true, false)
72561.106SkamilCLONE_TEST(clone_vfork4, CLONE_VFORK, true, true, false)
72571.106Skamil#endif
72581.106SkamilCLONE_TEST(clone_vfork5, CLONE_VFORK, false, false, true)
72591.106Skamil#if defined(TWAIT_HAVE_PID)
72601.106SkamilCLONE_TEST(clone_vfork6, CLONE_VFORK, true, false, true)
72611.106SkamilCLONE_TEST(clone_vfork7, CLONE_VFORK, false, true, true)
72621.106SkamilCLONE_TEST(clone_vfork8, CLONE_VFORK, true, true, true)
72631.106Skamil#endif
72641.106Skamil
72651.106Skamil/// ----------------------------------------------------------------------------
72661.106Skamil
72671.106Skamil#if defined(TWAIT_HAVE_PID)
72681.103Skamilstatic void
72691.106Skamilclone_body2(int flags, bool masked, bool ignored)
72701.103Skamil{
72711.103Skamil	const int exitval = 5;
72721.103Skamil	const int exitval2 = 15;
72731.103Skamil	const int sigval = SIGSTOP;
72741.103Skamil	pid_t child, child2 = 0, wpid;
72751.103Skamil#if defined(TWAIT_HAVE_STATUS)
72761.103Skamil	int status;
72771.103Skamil#endif
72781.103Skamil	ptrace_state_t state;
72791.103Skamil	const int slen = sizeof(state);
72801.103Skamil	ptrace_event_t event;
72811.103Skamil	const int elen = sizeof(event);
72821.103Skamil	struct sigaction sa;
72831.103Skamil	struct ptrace_siginfo info;
72841.103Skamil	sigset_t intmask;
72851.103Skamil	struct kinfo_proc2 kp;
72861.103Skamil	size_t len = sizeof(kp);
72871.103Skamil
72881.103Skamil	int name[6];
72891.103Skamil	const size_t namelen = __arraycount(name);
72901.103Skamil	ki_sigset_t kp_sigmask;
72911.103Skamil	ki_sigset_t kp_sigignore;
72921.103Skamil
72931.103Skamil	const size_t stack_size = 1024 * 1024;
72941.103Skamil	void *stack, *stack_base;
72951.103Skamil
72961.103Skamil	stack = malloc(stack_size);
72971.103Skamil	ATF_REQUIRE(stack != NULL);
72981.103Skamil
72991.103Skamil#ifdef __MACHINE_STACK_GROWS_UP
73001.103Skamil	stack_base = stack;
73011.103Skamil#else
73021.103Skamil	stack_base = (char *)stack + stack_size;
73031.103Skamil#endif
73041.103Skamil
73051.103Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
73061.103Skamil	if (child == 0) {
73071.103Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
73081.103Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
73091.103Skamil
73101.103Skamil		if (masked) {
73111.103Skamil			sigemptyset(&intmask);
73121.103Skamil			sigaddset(&intmask, SIGTRAP);
73131.103Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
73141.103Skamil		}
73151.103Skamil
73161.103Skamil		if (ignored) {
73171.103Skamil			memset(&sa, 0, sizeof(sa));
73181.103Skamil			sa.sa_handler = SIG_IGN;
73191.103Skamil			sigemptyset(&sa.sa_mask);
73201.103Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
73211.103Skamil		}
73221.103Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
73231.103Skamil		FORKEE_ASSERT(raise(sigval) == 0);
73241.103Skamil
73251.103Skamil		DPRINTF("Before forking process PID=%d flags=%#x\n", getpid(),
73261.103Skamil		    flags);
73271.103Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
73281.103Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
73291.103Skamil
73301.103Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
73311.103Skamil		    child2);
73321.103Skamil
73331.103Skamil		// XXX WALLSIG?
73341.103Skamil		FORKEE_REQUIRE_SUCCESS
73351.103Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
73361.103Skamil
73371.103Skamil		forkee_status_exited(status, exitval2);
73381.103Skamil
73391.103Skamil		DPRINTF("Before exiting of the child process\n");
73401.103Skamil		_exit(exitval);
73411.103Skamil	}
73421.103Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
73431.103Skamil
73441.103Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
73451.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
73461.103Skamil
73471.103Skamil	validate_status_stopped(status, sigval);
73481.103Skamil
73491.103Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
73501.103Skamil	SYSCALL_REQUIRE(
73511.103Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
73521.103Skamil
73531.103Skamil	DPRINTF("Before checking siginfo_t\n");
73541.103Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
73551.103Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
73561.103Skamil
73571.103Skamil	name[0] = CTL_KERN,
73581.103Skamil	name[1] = KERN_PROC2,
73591.103Skamil	name[2] = KERN_PROC_PID;
73601.103Skamil	name[3] = child;
73611.103Skamil	name[4] = sizeof(kp);
73621.103Skamil	name[5] = 1;
73631.103Skamil
73641.103Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
73651.103Skamil
73661.103Skamil	if (masked)
73671.103Skamil		kp_sigmask = kp.p_sigmask;
73681.103Skamil
73691.103Skamil	if (ignored)
73701.103Skamil		kp_sigignore = kp.p_sigignore;
73711.103Skamil
73721.103Skamil	DPRINTF("Set PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE in "
73731.103Skamil	    "EVENT_MASK for the child %d\n", child);
73741.103Skamil	event.pe_set_event = PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE;
73751.103Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
73761.103Skamil
73771.103Skamil	DPRINTF("Before resuming the child process where it left off and "
73781.103Skamil	    "without signal to be sent\n");
73791.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
73801.103Skamil
73811.103Skamil	DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
73821.103Skamil	    child);
73831.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
73841.103Skamil	    child);
73851.103Skamil
73861.103Skamil	validate_status_stopped(status, SIGTRAP);
73871.103Skamil
73881.103Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
73891.103Skamil
73901.103Skamil	if (masked) {
73911.103Skamil		DPRINTF("kp_sigmask="
73921.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73931.103Skamil		    PRIx32 "\n",
73941.103Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
73951.103Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
73961.103Skamil
73971.103Skamil		DPRINTF("kp.p_sigmask="
73981.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73991.103Skamil		    PRIx32 "\n",
74001.103Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
74011.103Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
74021.103Skamil
74031.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
74041.103Skamil		    sizeof(kp_sigmask)));
74051.103Skamil	}
74061.103Skamil
74071.103Skamil	if (ignored) {
74081.103Skamil		DPRINTF("kp_sigignore="
74091.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
74101.103Skamil		    PRIx32 "\n",
74111.103Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
74121.103Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
74131.103Skamil
74141.103Skamil		DPRINTF("kp.p_sigignore="
74151.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
74161.103Skamil		    PRIx32 "\n",
74171.103Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
74181.103Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
74191.103Skamil
74201.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
74211.103Skamil		    sizeof(kp_sigignore)));
74221.103Skamil	}
74231.103Skamil
74241.103Skamil	SYSCALL_REQUIRE(
74251.103Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
74261.103Skamil	DPRINTF("state.pe_report_event=%#x pid=%d\n", state.pe_report_event,
74271.103Skamil	    child2);
74281.103Skamil	if (!(flags & CLONE_VFORK)) {
74291.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
74301.103Skamil		       PTRACE_FORK);
74311.103Skamil	} else {
74321.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
74331.103Skamil		       PTRACE_VFORK);
74341.103Skamil	}
74351.103Skamil
74361.103Skamil	child2 = state.pe_other_pid;
74371.103Skamil	DPRINTF("Reported ptrace event with forkee %d\n", child2);
74381.103Skamil
74391.103Skamil	DPRINTF("Before calling %s() for the forkee %d of the child "
74401.103Skamil	    "%d\n", TWAIT_FNAME, child2, child);
74411.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
74421.103Skamil	    child2);
74431.103Skamil
74441.103Skamil	validate_status_stopped(status, SIGTRAP);
74451.103Skamil
74461.103Skamil	name[3] = child2;
74471.103Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
74481.103Skamil
74491.103Skamil	if (masked) {
74501.103Skamil		DPRINTF("kp_sigmask="
74511.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
74521.103Skamil		    PRIx32 "\n",
74531.103Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
74541.103Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
74551.103Skamil
74561.103Skamil		DPRINTF("kp.p_sigmask="
74571.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
74581.103Skamil		    PRIx32 "\n",
74591.103Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
74601.103Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
74611.103Skamil
74621.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
74631.103Skamil		    sizeof(kp_sigmask)));
74641.103Skamil	}
74651.103Skamil
74661.103Skamil	if (ignored) {
74671.103Skamil		DPRINTF("kp_sigignore="
74681.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
74691.103Skamil		    PRIx32 "\n",
74701.103Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
74711.103Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
74721.103Skamil
74731.103Skamil		DPRINTF("kp.p_sigignore="
74741.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
74751.103Skamil		    PRIx32 "\n",
74761.103Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
74771.103Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
74781.103Skamil
74791.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
74801.103Skamil		    sizeof(kp_sigignore)));
74811.103Skamil	}
74821.103Skamil
74831.103Skamil	SYSCALL_REQUIRE(
74841.103Skamil	    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
74851.103Skamil	if (!(flags & CLONE_VFORK)) {
74861.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
74871.103Skamil		       PTRACE_FORK);
74881.103Skamil	} else {
74891.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
74901.103Skamil		       PTRACE_VFORK);
74911.103Skamil	}
74921.103Skamil
74931.103Skamil	ATF_REQUIRE_EQ(state.pe_other_pid, child);
74941.103Skamil
74951.103Skamil	DPRINTF("Before resuming the forkee process where it left off "
74961.103Skamil	    "and without signal to be sent\n");
74971.103Skamil	SYSCALL_REQUIRE(
74981.103Skamil	    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
74991.103Skamil
75001.103Skamil	DPRINTF("Before resuming the child process where it left off "
75011.103Skamil	    "and without signal to be sent\n");
75021.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
75031.103Skamil
75041.103Skamil	if (flags & CLONE_VFORK) {
75051.103Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
75061.103Skamil		    child);
75071.103Skamil		TWAIT_REQUIRE_SUCCESS(
75081.103Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
75091.103Skamil
75101.103Skamil		validate_status_stopped(status, SIGTRAP);
75111.103Skamil
75121.103Skamil		name[3] = child;
75131.103Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
75141.103Skamil
75151.103Skamil		/*
75161.103Skamil		 * SIGCHLD is now pending in the signal queue and
75171.103Skamil		 * the kernel presents it to userland as a masked signal.
75181.103Skamil		 */
75191.103Skamil		sigdelset((sigset_t *)&kp.p_sigmask, SIGCHLD);
75201.103Skamil
75211.103Skamil		if (masked) {
75221.103Skamil			DPRINTF("kp_sigmask="
75231.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
75241.103Skamil			    PRIx32 "\n",
75251.103Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
75261.103Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
75271.103Skamil
75281.103Skamil			DPRINTF("kp.p_sigmask="
75291.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
75301.103Skamil			    PRIx32 "\n",
75311.103Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
75321.103Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
75331.103Skamil
75341.103Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
75351.103Skamil			    sizeof(kp_sigmask)));
75361.103Skamil		}
75371.103Skamil
75381.103Skamil		if (ignored) {
75391.103Skamil			DPRINTF("kp_sigignore="
75401.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
75411.103Skamil			    PRIx32 "\n",
75421.103Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
75431.103Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
75441.103Skamil
75451.103Skamil			DPRINTF("kp.p_sigignore="
75461.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
75471.103Skamil			    PRIx32 "\n",
75481.103Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
75491.103Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
75501.103Skamil
75511.103Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
75521.103Skamil			    sizeof(kp_sigignore)));
75531.103Skamil		}
75541.103Skamil
75551.103Skamil		SYSCALL_REQUIRE(
75561.103Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
75571.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
75581.103Skamil
75591.103Skamil		child2 = state.pe_other_pid;
75601.103Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
75611.103Skamil		    child2);
75621.103Skamil
75631.103Skamil		DPRINTF("Before resuming the child process where it left off "
75641.103Skamil		    "and without signal to be sent\n");
75651.103Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
75661.103Skamil	}
75671.103Skamil
75681.103Skamil	DPRINTF("Before calling %s() for the forkee - expected exited"
75691.103Skamil	    "\n", TWAIT_FNAME);
75701.103Skamil	TWAIT_REQUIRE_SUCCESS(
75711.103Skamil	    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
75721.103Skamil
75731.103Skamil	validate_status_exited(status, exitval2);
75741.103Skamil
75751.103Skamil	DPRINTF("Before calling %s() for the forkee - expected no "
75761.103Skamil	    "process\n", TWAIT_FNAME);
75771.103Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
75781.103Skamil	    wpid = TWAIT_GENERIC(child2, &status, 0));
75791.103Skamil
75801.103Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
75811.103Skamil	    "SIGCHLD\n", TWAIT_FNAME);
75821.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
75831.103Skamil
75841.103Skamil	validate_status_stopped(status, SIGCHLD);
75851.103Skamil
75861.103Skamil	DPRINTF("Before resuming the child process where it left off and "
75871.103Skamil	    "without signal to be sent\n");
75881.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
75891.103Skamil
75901.103Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
75911.103Skamil	    TWAIT_FNAME);
75921.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
75931.103Skamil
75941.103Skamil	validate_status_exited(status, exitval);
75951.103Skamil
75961.103Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
75971.103Skamil	    TWAIT_FNAME);
75981.103Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
75991.103Skamil}
76001.103Skamil
76011.106Skamil#define CLONE_TEST2(name,flags,masked,ignored)				\
76021.103SkamilATF_TC(name);								\
76031.103SkamilATF_TC_HEAD(name, tc)							\
76041.103Skamil{									\
76051.103Skamil	atf_tc_set_md_var(tc, "descr", "Verify that clone(%s) is caught"\
76061.103Skamil	    " regardless of signal %s%s", 				\
76071.103Skamil	    #flags, masked ? "masked" : "", ignored ? "ignored" : "");	\
76081.103Skamil}									\
76091.103Skamil									\
76101.103SkamilATF_TC_BODY(name, tc)							\
76111.103Skamil{									\
76121.103Skamil									\
76131.106Skamil	clone_body2(flags, masked, ignored);				\
76141.103Skamil}
76151.103Skamil
76161.106SkamilCLONE_TEST2(clone_signalignored, 0, true, false)
76171.106SkamilCLONE_TEST2(clone_signalmasked, 0, false, true)
76181.106SkamilCLONE_TEST2(clone_vm_signalignored, CLONE_VM, true, false)
76191.106SkamilCLONE_TEST2(clone_vm_signalmasked, CLONE_VM, false, true)
76201.106SkamilCLONE_TEST2(clone_fs_signalignored, CLONE_FS, true, false)
76211.106SkamilCLONE_TEST2(clone_fs_signalmasked, CLONE_FS, false, true)
76221.106SkamilCLONE_TEST2(clone_files_signalignored, CLONE_FILES, true, false)
76231.106SkamilCLONE_TEST2(clone_files_signalmasked, CLONE_FILES, false, true)
76241.106Skamil//CLONE_TEST2(clone_sighand_signalignored, CLONE_SIGHAND, true, false) // XXX
76251.106Skamil//CLONE_TEST2(clone_sighand_signalmasked, CLONE_SIGHAND, false, true)  // XXX
76261.106SkamilCLONE_TEST2(clone_vfork_signalignored, CLONE_VFORK, true, false)
76271.106SkamilCLONE_TEST2(clone_vfork_signalmasked, CLONE_VFORK, false, true)
76281.103Skamil#endif
76291.103Skamil
76301.103Skamil/// ----------------------------------------------------------------------------
76311.103Skamil
76321.107Skamil#if defined(TWAIT_HAVE_PID)
76331.107Skamilstatic void
76341.107Skamiltraceme_vfork_clone_body(int flags)
76351.107Skamil{
76361.107Skamil	const int exitval = 5;
76371.107Skamil	const int exitval2 = 15;
76381.107Skamil	pid_t child, child2 = 0, wpid;
76391.107Skamil#if defined(TWAIT_HAVE_STATUS)
76401.107Skamil	int status;
76411.107Skamil#endif
76421.107Skamil
76431.107Skamil	const size_t stack_size = 1024 * 1024;
76441.107Skamil	void *stack, *stack_base;
76451.107Skamil
76461.107Skamil	stack = malloc(stack_size);
76471.107Skamil	ATF_REQUIRE(stack != NULL);
76481.107Skamil
76491.107Skamil#ifdef __MACHINE_STACK_GROWS_UP
76501.107Skamil	stack_base = stack;
76511.107Skamil#else
76521.107Skamil	stack_base = (char *)stack + stack_size;
76531.107Skamil#endif
76541.107Skamil
76551.107Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
76561.107Skamil	if (child == 0) {
76571.107Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
76581.107Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
76591.107Skamil
76601.107Skamil		DPRINTF("Before forking process PID=%d flags=%#x\n", getpid(),
76611.107Skamil		    flags);
76621.107Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
76631.107Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
76641.107Skamil
76651.107Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
76661.107Skamil		    child2);
76671.107Skamil
76681.107Skamil		// XXX WALLSIG?
76691.107Skamil		FORKEE_REQUIRE_SUCCESS
76701.107Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
76711.107Skamil
76721.107Skamil		forkee_status_exited(status, exitval2);
76731.107Skamil
76741.107Skamil		DPRINTF("Before exiting of the child process\n");
76751.107Skamil		_exit(exitval);
76761.107Skamil	}
76771.107Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
76781.107Skamil
76791.107Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
76801.107Skamil	    TWAIT_FNAME);
76811.107Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
76821.107Skamil
76831.107Skamil	validate_status_exited(status, exitval);
76841.107Skamil
76851.107Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
76861.107Skamil	    TWAIT_FNAME);
76871.107Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
76881.107Skamil}
76891.107Skamil
76901.107Skamil#define TRACEME_VFORK_CLONE_TEST(name,flags)				\
76911.107SkamilATF_TC(name);								\
76921.107SkamilATF_TC_HEAD(name, tc)							\
76931.107Skamil{									\
76941.107Skamil	atf_tc_set_md_var(tc, "descr", "Verify that clone(%s) is "	\
76951.107Skamil	    "handled correctly with vfork(2)ed tracer", 		\
76961.107Skamil	    #flags);							\
76971.107Skamil}									\
76981.107Skamil									\
76991.107SkamilATF_TC_BODY(name, tc)							\
77001.107Skamil{									\
77011.107Skamil									\
77021.107Skamil	traceme_vfork_clone_body(flags);				\
77031.107Skamil}
77041.107Skamil
77051.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone, 0)
77061.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_vm, CLONE_VM)
77071.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_fs, CLONE_FS)
77081.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_files, CLONE_FILES)
77091.107Skamil//TRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_sighand, CLONE_SIGHAND)  // XXX
77101.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_vfork, CLONE_VFORK)
77111.107Skamil#endif
77121.107Skamil
77131.107Skamil/// ----------------------------------------------------------------------------
77141.107Skamil
77151.122Skamilstatic void
77161.122Skamiluser_va0_disable(int operation)
77171.122Skamil{
77181.122Skamil	pid_t child, wpid;
77191.122Skamil#if defined(TWAIT_HAVE_STATUS)
77201.122Skamil	int status;
77211.122Skamil#endif
77221.122Skamil	const int sigval = SIGSTOP;
77231.122Skamil	int rv;
77241.122Skamil
77251.122Skamil	struct ptrace_siginfo info;
77261.122Skamil
77271.122Skamil	if (get_user_va0_disable() == 0)
77281.122Skamil		atf_tc_skip("vm.user_va0_disable is set to 0");
77291.122Skamil
77301.122Skamil	memset(&info, 0, sizeof(info));
77311.122Skamil
77321.122Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
77331.122Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
77341.122Skamil	if (child == 0) {
77351.122Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
77361.122Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
77371.122Skamil
77381.122Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
77391.122Skamil		FORKEE_ASSERT(raise(sigval) == 0);
77401.122Skamil
77411.122Skamil		/* NOTREACHED */
77421.122Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
77431.122Skamil		__unreachable();
77441.122Skamil	}
77451.122Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
77461.122Skamil
77471.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
77481.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
77491.122Skamil
77501.122Skamil	validate_status_stopped(status, sigval);
77511.122Skamil
77521.122Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
77531.122Skamil		"child\n");
77541.122Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
77551.122Skamil		sizeof(info)) != -1);
77561.122Skamil
77571.122Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
77581.122Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
77591.122Skamil		"si_errno=%#x\n",
77601.122Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
77611.122Skamil		info.psi_siginfo.si_errno);
77621.122Skamil
77631.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
77641.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
77651.122Skamil
77661.122Skamil	DPRINTF("Before resuming the child process in PC=0x0 "
77671.122Skamil	    "and without signal to be sent\n");
77681.122Skamil	errno = 0;
77691.122Skamil	rv = ptrace(operation, child, (void *)0, 0);
77701.122Skamil	ATF_REQUIRE_EQ(errno, EINVAL);
77711.122Skamil	ATF_REQUIRE_EQ(rv, -1);
77721.122Skamil
77731.122Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
77741.122Skamil
77751.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
77761.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
77771.122Skamil	validate_status_signaled(status, SIGKILL, 0);
77781.122Skamil
77791.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
77801.122Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
77811.122Skamil}
77821.122Skamil
77831.122Skamil#define USER_VA0_DISABLE(test, operation)				\
77841.122SkamilATF_TC(test);								\
77851.122SkamilATF_TC_HEAD(test, tc)							\
77861.122Skamil{									\
77871.122Skamil	atf_tc_set_md_var(tc, "descr",					\
77881.122Skamil	    "Verify behavior of " #operation " with PC set to 0x0");	\
77891.122Skamil}									\
77901.122Skamil									\
77911.122SkamilATF_TC_BODY(test, tc)							\
77921.122Skamil{									\
77931.122Skamil									\
77941.122Skamil	user_va0_disable(operation);					\
77951.122Skamil}
77961.122Skamil
77971.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_continue, PT_CONTINUE)
77981.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_syscall, PT_SYSCALL)
77991.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_detach, PT_DETACH)
78001.122Skamil
78011.122Skamil/// ----------------------------------------------------------------------------
78021.122Skamil
78031.130Smgorny/*
78041.130Smgorny * Parse the core file and find the requested note.  If the reading or parsing
78051.130Smgorny * fails, the test is failed.  If the note is found, it is read onto buf, up to
78061.130Smgorny * buf_len.  The actual length of the note is returned (which can be greater
78071.130Smgorny * than buf_len, indicating that it has been truncated).  If the note is not
78081.130Smgorny * found, -1 is returned.
78091.130Smgorny */
78101.130Smgornystatic ssize_t core_find_note(const char *core_path,
78111.130Smgorny    const char *note_name, uint64_t note_type, void *buf, size_t buf_len)
78121.130Smgorny{
78131.130Smgorny	int core_fd;
78141.130Smgorny	Elf *core_elf;
78151.130Smgorny	size_t core_numhdr, i;
78161.130Smgorny	ssize_t ret = -1;
78171.130Smgorny	/* note: we assume note name will be null-terminated */
78181.130Smgorny	size_t name_len = strlen(note_name) + 1;
78191.130Smgorny
78201.130Smgorny	SYSCALL_REQUIRE((core_fd = open(core_path, O_RDONLY)) != -1);
78211.130Smgorny	SYSCALL_REQUIRE(elf_version(EV_CURRENT) != EV_NONE);
78221.130Smgorny	SYSCALL_REQUIRE((core_elf = elf_begin(core_fd, ELF_C_READ, NULL)));
78231.130Smgorny
78241.130Smgorny	SYSCALL_REQUIRE(elf_getphnum(core_elf, &core_numhdr) != 0);
78251.130Smgorny	for (i = 0; i < core_numhdr && ret == -1; i++) {
78261.130Smgorny		GElf_Phdr core_hdr;
78271.130Smgorny		size_t offset;
78281.130Smgorny		SYSCALL_REQUIRE(gelf_getphdr(core_elf, i, &core_hdr));
78291.130Smgorny		if (core_hdr.p_type != PT_NOTE)
78301.130Smgorny		    continue;
78311.130Smgorny
78321.130Smgorny		for (offset = core_hdr.p_offset;
78331.130Smgorny		    offset < core_hdr.p_offset + core_hdr.p_filesz;) {
78341.130Smgorny			Elf64_Nhdr note_hdr;
78351.130Smgorny			char name_buf[64];
78361.130Smgorny
78371.130Smgorny			switch (gelf_getclass(core_elf)) {
78381.130Smgorny			case ELFCLASS64:
78391.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &note_hdr,
78401.130Smgorny				    sizeof(note_hdr), offset)
78411.130Smgorny				    == sizeof(note_hdr));
78421.130Smgorny				offset += sizeof(note_hdr);
78431.130Smgorny				break;
78441.130Smgorny			case ELFCLASS32:
78451.130Smgorny				{
78461.130Smgorny				Elf32_Nhdr tmp_hdr;
78471.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &tmp_hdr,
78481.130Smgorny				    sizeof(tmp_hdr), offset)
78491.130Smgorny				    == sizeof(tmp_hdr));
78501.130Smgorny				offset += sizeof(tmp_hdr);
78511.130Smgorny				note_hdr.n_namesz = tmp_hdr.n_namesz;
78521.130Smgorny				note_hdr.n_descsz = tmp_hdr.n_descsz;
78531.130Smgorny				note_hdr.n_type = tmp_hdr.n_type;
78541.130Smgorny				}
78551.130Smgorny				break;
78561.130Smgorny			}
78571.130Smgorny
78581.130Smgorny			/* indicates end of notes */
78591.130Smgorny			if (note_hdr.n_namesz == 0 || note_hdr.n_descsz == 0)
78601.130Smgorny				break;
78611.130Smgorny			if (note_hdr.n_namesz == name_len &&
78621.130Smgorny			    note_hdr.n_namesz <= sizeof(name_buf)) {
78631.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, name_buf,
78641.130Smgorny				    note_hdr.n_namesz, offset)
78651.131Skamil				    == (ssize_t)(size_t)note_hdr.n_namesz);
78661.130Smgorny
78671.130Smgorny				if (!strncmp(note_name, name_buf, name_len) &&
78681.130Smgorny				    note_hdr.n_type == note_type)
78691.130Smgorny					ret = note_hdr.n_descsz;
78701.130Smgorny			}
78711.130Smgorny
78721.130Smgorny			offset += note_hdr.n_namesz;
78731.130Smgorny			/* fix to alignment */
78741.146Smgorny			offset = roundup(offset, core_hdr.p_align);
78751.130Smgorny
78761.130Smgorny			/* if name & type matched above */
78771.130Smgorny			if (ret != -1) {
78781.130Smgorny				ssize_t read_len = MIN(buf_len,
78791.130Smgorny				    note_hdr.n_descsz);
78801.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, buf,
78811.130Smgorny				    read_len, offset) == read_len);
78821.130Smgorny				break;
78831.130Smgorny			}
78841.130Smgorny
78851.130Smgorny			offset += note_hdr.n_descsz;
78861.146Smgorny			/* fix to alignment */
78871.146Smgorny			offset = roundup(offset, core_hdr.p_align);
78881.130Smgorny		}
78891.130Smgorny	}
78901.130Smgorny
78911.130Smgorny	elf_end(core_elf);
78921.130Smgorny	close(core_fd);
78931.130Smgorny
78941.130Smgorny	return ret;
78951.130Smgorny}
78961.130Smgorny
78971.130SmgornyATF_TC(core_dump_procinfo);
78981.130SmgornyATF_TC_HEAD(core_dump_procinfo, tc)
78991.130Smgorny{
79001.130Smgorny	atf_tc_set_md_var(tc, "descr",
79011.130Smgorny		"Trigger a core dump and verify its contents.");
79021.130Smgorny}
79031.130Smgorny
79041.130SmgornyATF_TC_BODY(core_dump_procinfo, tc)
79051.130Smgorny{
79061.130Smgorny	const int exitval = 5;
79071.130Smgorny	pid_t child, wpid;
79081.130Smgorny#if defined(TWAIT_HAVE_STATUS)
79091.130Smgorny	const int sigval = SIGTRAP;
79101.130Smgorny	int status;
79111.130Smgorny#endif
79121.130Smgorny	char core_path[] = "/tmp/core.XXXXXX";
79131.130Smgorny	int core_fd;
79141.130Smgorny	struct netbsd_elfcore_procinfo procinfo;
79151.130Smgorny
79161.130Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
79171.130Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
79181.130Smgorny	if (child == 0) {
79191.130Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
79201.130Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
79211.130Smgorny
79221.130Smgorny		DPRINTF("Before triggering SIGTRAP\n");
79231.130Smgorny		trigger_trap();
79241.130Smgorny
79251.130Smgorny		DPRINTF("Before exiting of the child process\n");
79261.130Smgorny		_exit(exitval);
79271.130Smgorny	}
79281.130Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
79291.130Smgorny
79301.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
79311.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
79321.130Smgorny
79331.130Smgorny	validate_status_stopped(status, sigval);
79341.130Smgorny
79351.130Smgorny	SYSCALL_REQUIRE((core_fd = mkstemp(core_path)) != -1);
79361.130Smgorny	close(core_fd);
79371.130Smgorny
79381.130Smgorny	DPRINTF("Call DUMPCORE for the child process\n");
79391.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_DUMPCORE, child, core_path, strlen(core_path))
79401.130Smgorny	    != -1);
79411.130Smgorny
79421.130Smgorny	DPRINTF("Read core file\n");
79431.130Smgorny	ATF_REQUIRE_EQ(core_find_note(core_path, "NetBSD-CORE",
79441.130Smgorny	    ELF_NOTE_NETBSD_CORE_PROCINFO, &procinfo, sizeof(procinfo)),
79451.130Smgorny	    sizeof(procinfo));
79461.130Smgorny
79471.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_version, 1);
79481.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_cpisize, sizeof(procinfo));
79491.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_signo, SIGTRAP);
79501.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pid, child);
79511.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ppid, getpid());
79521.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pgrp, getpgid(child));
79531.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_sid, getsid(child));
79541.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ruid, getuid());
79551.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_euid, geteuid());
79561.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_rgid, getgid());
79571.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_egid, getegid());
79581.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_nlwps, 1);
79591.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_siglwp, 1);
79601.130Smgorny
79611.130Smgorny	unlink(core_path);
79621.130Smgorny
79631.130Smgorny	DPRINTF("Before resuming the child process where it left off and "
79641.130Smgorny	    "without signal to be sent\n");
79651.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
79661.130Smgorny
79671.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
79681.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
79691.130Smgorny
79701.130Smgorny	validate_status_exited(status, exitval);
79711.130Smgorny
79721.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
79731.130Smgorny	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
79741.130Smgorny}
79751.130Smgorny
79761.130Smgorny/// ----------------------------------------------------------------------------
79771.130Smgorny
79781.138Smgorny#if defined(TWAIT_HAVE_STATUS)
79791.138Smgorny
79801.138SmgornyATF_TC(thread_concurrent_signals);
79811.138SmgornyATF_TC_HEAD(thread_concurrent_signals, tc)
79821.138Smgorny{
79831.138Smgorny	atf_tc_set_md_var(tc, "descr",
79841.138Smgorny	    "Verify that concurrent signals issued to a single thread "
79851.138Smgorny	    "are reported correctly");
79861.138Smgorny}
79871.138Smgorny
79881.138Smgorny/* List of signals to use for the test */
79891.138Smgornyconst int thread_concurrent_signals_list[] = {
79901.138Smgorny	SIGIO,
79911.138Smgorny	SIGXCPU,
79921.138Smgorny	SIGXFSZ,
79931.138Smgorny	SIGVTALRM,
79941.138Smgorny	SIGPROF,
79951.138Smgorny	SIGWINCH,
79961.138Smgorny	SIGINFO,
79971.138Smgorny	SIGUSR1,
79981.138Smgorny	SIGUSR2
79991.138Smgorny};
80001.138Smgorny
80011.138Smgornypthread_barrier_t thread_concurrent_signals_barrier;
80021.138Smgorny
80031.138Smgornystatic void *
80041.138Smgornythread_concurrent_signals_thread(void *arg)
80051.138Smgorny{
80061.138Smgorny	int sigval = thread_concurrent_signals_list[
80071.138Smgorny	    _lwp_self() % __arraycount(thread_concurrent_signals_list)];
80081.138Smgorny	pthread_barrier_wait(&thread_concurrent_signals_barrier);
80091.138Smgorny	DPRINTF("Before raising %s from LWP %d\n", strsignal(sigval),
80101.138Smgorny		_lwp_self());
80111.138Smgorny	pthread_kill(pthread_self(), sigval);
80121.138Smgorny	return NULL;
80131.138Smgorny}
80141.138Smgorny
80151.138Smgorny#define THREAD_CONCURRENT_SIGNALS_NUM 50
80161.138Smgorny
80171.138SmgornyATF_TC_BODY(thread_concurrent_signals, tc)
80181.138Smgorny{
80191.138Smgorny	const int exitval = 5;
80201.138Smgorny	const int sigval = SIGSTOP;
80211.138Smgorny	pid_t child, wpid;
80221.138Smgorny	int status;
80231.141Skamil	struct lwp_event_count signal_counts[THREAD_CONCURRENT_SIGNALS_NUM]
80241.141Skamil	    = {{0, 0}};
80251.138Smgorny	unsigned int i;
80261.138Smgorny
80271.138Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
80281.138Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
80291.138Smgorny	if (child == 0) {
80301.138Smgorny		pthread_t threads[THREAD_CONCURRENT_SIGNALS_NUM];
80311.138Smgorny
80321.138Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
80331.138Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
80341.138Smgorny
80351.138Smgorny		DPRINTF("Before raising %s from child\n", strsignal(sigval));
80361.138Smgorny		FORKEE_ASSERT(raise(sigval) == 0);
80371.138Smgorny
80381.138Smgorny		DPRINTF("Before starting threads from the child\n");
80391.138Smgorny		FORKEE_ASSERT(pthread_barrier_init(
80401.138Smgorny		    &thread_concurrent_signals_barrier, NULL,
80411.138Smgorny		    __arraycount(threads)) == 0);
80421.138Smgorny
80431.138Smgorny		for (i = 0; i < __arraycount(threads); i++) {
80441.138Smgorny			FORKEE_ASSERT(pthread_create(&threads[i], NULL,
80451.138Smgorny			    thread_concurrent_signals_thread, NULL) == 0);
80461.138Smgorny		}
80471.138Smgorny
80481.138Smgorny		DPRINTF("Before joining threads from the child\n");
80491.138Smgorny		for (i = 0; i < __arraycount(threads); i++) {
80501.138Smgorny			FORKEE_ASSERT(pthread_join(threads[i], NULL) == 0);
80511.138Smgorny		}
80521.138Smgorny
80531.138Smgorny		FORKEE_ASSERT(pthread_barrier_destroy(
80541.138Smgorny		    &thread_concurrent_signals_barrier) == 0);
80551.138Smgorny
80561.138Smgorny		DPRINTF("Before exiting of the child process\n");
80571.138Smgorny		_exit(exitval);
80581.138Smgorny	}
80591.138Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
80601.138Smgorny
80611.138Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
80621.138Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
80631.138Smgorny
80641.138Smgorny	validate_status_stopped(status, sigval);
80651.138Smgorny
80661.138Smgorny	DPRINTF("Before resuming the child process where it left off\n");
80671.138Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
80681.138Smgorny
80691.138Smgorny	DPRINTF("Before entering signal collection loop\n");
80701.138Smgorny	while (1) {
80711.138Smgorny		ptrace_siginfo_t info;
80721.138Smgorny		int expected_sig;
80731.138Smgorny
80741.138Smgorny		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
80751.138Smgorny		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
80761.138Smgorny		    child);
80771.138Smgorny		if (WIFEXITED(status))
80781.138Smgorny			break;
80791.138Smgorny		/* Note: we use validate_status_stopped() to get nice error
80801.138Smgorny		 * message.  Signal is irrelevant since it won't be reached.
80811.138Smgorny		 */
80821.138Smgorny		else if (!WIFSTOPPED(status))
80831.138Smgorny			validate_status_stopped(status, 0);
80841.138Smgorny
80851.138Smgorny		DPRINTF("Before calling PT_GET_SIGINFO\n");
80861.138Smgorny		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
80871.138Smgorny		    sizeof(info)) != -1);
80881.138Smgorny
80891.138Smgorny		DPRINTF("Received signal %d from LWP %d (wait: %d)\n",
80901.138Smgorny		    info.psi_siginfo.si_signo, info.psi_lwpid,
80911.138Smgorny		    WSTOPSIG(status));
80921.138Smgorny
80931.138Smgorny		expected_sig = thread_concurrent_signals_list[info.psi_lwpid %
80941.138Smgorny		    __arraycount(thread_concurrent_signals_list)];
80951.138Smgorny		ATF_CHECK_EQ_MSG(info.psi_siginfo.si_signo, expected_sig,
80961.138Smgorny		    "lwp=%d, expected %d, got %d", info.psi_lwpid,
80971.138Smgorny		    expected_sig, info.psi_siginfo.si_signo);
80981.138Smgorny		ATF_CHECK_EQ_MSG(WSTOPSIG(status), expected_sig,
80991.138Smgorny		    "lwp=%d, expected %d, got %d", info.psi_lwpid,
81001.138Smgorny		    expected_sig, WSTOPSIG(status));
81011.138Smgorny
81021.141Skamil		*FIND_EVENT_COUNT(signal_counts, info.psi_lwpid) += 1;
81031.138Smgorny
81041.138Smgorny		DPRINTF("Before resuming the child process\n");
81051.138Smgorny		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
81061.138Smgorny	}
81071.138Smgorny
81081.138Smgorny	for (i = 0; i < __arraycount(signal_counts); i++)
81091.141Skamil		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 1,
81101.141Skamil		    "signal_counts[%d].lec_count=%d; lec_lwp=%d",
81111.141Skamil		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
81121.138Smgorny
81131.138Smgorny	validate_status_exited(status, exitval);
81141.138Smgorny}
81151.138Smgorny
81161.138Smgorny#endif /*defined(TWAIT_HAVE_STATUS)*/
81171.138Smgorny
81181.138Smgorny/// ----------------------------------------------------------------------------
81191.138Smgorny
81201.1Skamil#include "t_ptrace_amd64_wait.h"
81211.1Skamil#include "t_ptrace_i386_wait.h"
81221.1Skamil#include "t_ptrace_x86_wait.h"
81231.1Skamil
81241.1SkamilATF_TP_ADD_TCS(tp)
81251.1Skamil{
81261.1Skamil	setvbuf(stdout, NULL, _IONBF, 0);
81271.1Skamil	setvbuf(stderr, NULL, _IONBF, 0);
81281.33Skamil
81291.36Skamil	ATF_TP_ADD_TC(tp, traceme_raise1);
81301.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise2);
81311.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise3);
81321.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise4);
81331.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise5);
81341.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise6);
81351.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise7);
81361.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise8);
81371.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise9);
81381.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise10);
81391.33Skamil
81401.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored1);
81411.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored2);
81421.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored3);
81431.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored4);
81441.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored5);
81451.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored6);
81461.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored7);
81471.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored8);
81481.87Skamil
81491.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked1);
81501.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked2);
81511.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked3);
81521.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked4);
81531.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked5);
81541.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked6);
81551.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked7);
81561.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked8);
81571.86Skamil
81581.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_trap);
81591.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_segv);
81601.71Skamil	ATF_TP_ADD_TC(tp, traceme_crash_ill);
81611.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_fpe);
81621.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_bus);
81631.59Skamil
81641.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_trap);
81651.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_segv);
81661.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_ill);
81671.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_fpe);
81681.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_bus);
81691.88Skamil
81701.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_trap);
81711.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_segv);
81721.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_ill);
81731.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_fpe);
81741.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_bus);
81751.88Skamil
81761.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle1);
81771.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle2);
81781.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle3);
81791.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle4);
81801.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle5);
81811.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle6);
81821.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle7);
81831.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle8);
81841.50Skamil
81851.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked1);
81861.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked2);
81871.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked3);
81881.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked4);
81891.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked5);
81901.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked6);
81911.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked7);
81921.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked8);
81931.50Skamil
81941.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored1);
81951.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored2);
81961.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored3);
81971.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored4);
81981.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored5);
81991.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored6);
82001.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored7);
82011.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored8);
82021.50Skamil
82031.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple1);
82041.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple2);
82051.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple3);
82061.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple4);
82071.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple5);
82081.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple6);
82091.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple7);
82101.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple8);
82111.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple9);
82121.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple10);
82131.1Skamil
82141.37Skamil	ATF_TP_ADD_TC(tp, traceme_pid1_parent);
82151.37Skamil
82161.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise1);
82171.46Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise2);
82181.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise3);
82191.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise4);
82201.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise5);
82211.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise6);
82221.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise7);
82231.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise8);
82241.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise9);
82251.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise10);
82261.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise11);
82271.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise12);
82281.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise13);
82291.40Skamil
82301.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_trap);
82311.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_segv);
82321.71Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_ill);
82331.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_fpe);
82341.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_bus);
82351.41Skamil
82361.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_trap);
82371.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_segv);
82381.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_ill);
82391.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_fpe);
82401.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_bus);
82411.92Skamil
82421.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_trap);
82431.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_segv);
82441.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_ill);
82451.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_fpe);
82461.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_bus);
82471.92Skamil
82481.43Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_exec);
82491.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_exec);
82501.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_exec);
82511.43Skamil
82521.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_trap);
82531.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_segv);
82541.71Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_ill);
82551.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_fpe);
82561.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_bus);
82571.59Skamil
82581.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
82591.94Skamil	    unrelated_tracer_sees_signalmasked_crash_trap);
82601.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
82611.94Skamil	    unrelated_tracer_sees_signalmasked_crash_segv);
82621.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
82631.94Skamil	    unrelated_tracer_sees_signalmasked_crash_ill);
82641.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
82651.94Skamil	    unrelated_tracer_sees_signalmasked_crash_fpe);
82661.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
82671.94Skamil	    unrelated_tracer_sees_signalmasked_crash_bus);
82681.94Skamil
82691.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
82701.94Skamil	    unrelated_tracer_sees_signalignored_crash_trap);
82711.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
82721.94Skamil	    unrelated_tracer_sees_signalignored_crash_segv);
82731.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
82741.94Skamil	    unrelated_tracer_sees_signalignored_crash_ill);
82751.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
82761.94Skamil	    unrelated_tracer_sees_signalignored_crash_fpe);
82771.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
82781.94Skamil	    unrelated_tracer_sees_signalignored_crash_bus);
82791.94Skamil
82801.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sees_terminaton_before_the_parent);
82811.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sysctl_lookup_without_duplicates);
82821.61Skre	ATF_TP_ADD_TC_HAVE_PID(tp,
82831.61Skre		unrelated_tracer_sees_terminaton_before_the_parent);
82841.67Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_attach_to_unrelated_stopped_process);
82851.51Skamil
82861.51Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_child);
82871.66Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_stopped_child);
82881.51Skamil
82891.51Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_parent);
82901.65Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_stopped_parent);
82911.51Skamil
82921.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
82931.51Skamil		tracee_sees_its_original_parent_getppid);
82941.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
82951.51Skamil		tracee_sees_its_original_parent_sysctl_kinfo_proc2);
82961.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
82971.51Skamil		tracee_sees_its_original_parent_procfs_status);
82981.1Skamil
82991.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_empty);
83001.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_fork);
83011.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork);
83021.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork_done);
83031.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_create);
83041.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_exit);
83051.125Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_posix_spawn);
83061.1Skamil
83071.31Skamil	ATF_TP_ADD_TC(tp, fork1);
83081.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork2);
83091.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork3);
83101.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork4);
83111.31Skamil	ATF_TP_ADD_TC(tp, fork5);
83121.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork6);
83131.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork7);
83141.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork8);
83151.125Skamil	ATF_TP_ADD_TC(tp, fork9);
83161.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork10);
83171.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork11);
83181.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork12);
83191.125Skamil	ATF_TP_ADD_TC(tp, fork13);
83201.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork14);
83211.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork15);
83221.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork16);
83231.31Skamil
83241.31Skamil	ATF_TP_ADD_TC(tp, vfork1);
83251.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork2);
83261.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork3);
83271.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork4);
83281.31Skamil	ATF_TP_ADD_TC(tp, vfork5);
83291.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork6);
83301.104Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork7);
83311.104Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork8);
83321.125Skamil	ATF_TP_ADD_TC(tp, vfork9);
83331.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork10);
83341.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork11);
83351.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork12);
83361.125Skamil	ATF_TP_ADD_TC(tp, vfork13);
83371.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork14);
83381.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork15);
83391.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork16);
83401.1Skamil
83411.124Skamil	ATF_TP_ADD_TC(tp, posix_spawn1);
83421.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn2);
83431.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn3);
83441.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn4);
83451.124Skamil	ATF_TP_ADD_TC(tp, posix_spawn5);
83461.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn6);
83471.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn7);
83481.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn8);
83491.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn9);
83501.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn10);
83511.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn11);
83521.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn12);
83531.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn13);
83541.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn14);
83551.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn15);
83561.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn16);
83571.124Skamil
83581.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_detach_spawner);
83591.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_detach_forker);
83601.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_detach_vforker);
83611.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_detach_vforkerdone);
83621.126Skamil
83631.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_kill_spawner);
83641.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_kill_forker);
83651.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_kill_vforker);
83661.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_kill_vforkerdone);
83671.116Skamil
83681.108Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_fork);
83691.108Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_vfork);
83701.108Skamil
83711.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8);
83721.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16);
83731.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32);
83741.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64);
83751.54Skamil
83761.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8);
83771.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16);
83781.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32);
83791.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64);
83801.54Skamil
83811.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8);
83821.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16);
83831.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32);
83841.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64);
83851.54Skamil
83861.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8);
83871.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16);
83881.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32);
83891.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64);
83901.54Skamil
83911.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d);
83921.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i);
83931.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d);
83941.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i);
83951.54Skamil
83961.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8_text);
83971.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16_text);
83981.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32_text);
83991.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64_text);
84001.54Skamil
84011.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8_text);
84021.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16_text);
84031.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32_text);
84041.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64_text);
84051.54Skamil
84061.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8_text);
84071.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16_text);
84081.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32_text);
84091.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64_text);
84101.54Skamil
84111.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8_text);
84121.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16_text);
84131.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32_text);
84141.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64_text);
84151.54Skamil
84161.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d_text);
84171.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i_text);
84181.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d_text);
84191.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i_text);
84201.1Skamil
84211.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_auxv);
84221.1Skamil
84231.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_i);
84241.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_d);
84251.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_i);
84261.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_d);
84271.101Skamil
84281.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_i);
84291.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_d);
84301.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_i);
84311.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_d);
84321.101Skamil
84331.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_auxv);
84341.101Skamil
84351.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_i);
84361.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_d);
84371.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_i);
84381.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_d);
84391.115Skamil
84401.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_i);
84411.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_d);
84421.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_i);
84431.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_d);
84441.115Skamil
84451.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs1);
84461.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs2);
84471.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs3);
84481.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs4);
84491.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs5);
84501.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs6);
84511.1Skamil
84521.147Skamil	ATF_TP_ADD_TC(tp, access_regs_set_unaligned_pc_0x1);
84531.147Skamil	ATF_TP_ADD_TC(tp, access_regs_set_unaligned_pc_0x3);
84541.147Skamil	ATF_TP_ADD_TC(tp, access_regs_set_unaligned_pc_0x7);
84551.147Skamil
84561.72Skamil	ATF_TP_ADD_TC_HAVE_FPREGS(tp, access_fpregs1);
84571.72Skamil	ATF_TP_ADD_TC_HAVE_FPREGS(tp, access_fpregs2);
84581.1Skamil
84591.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step1);
84601.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step2);
84611.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step3);
84621.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step4);
84631.1Skamil
84641.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep1);
84651.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep2);
84661.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep3);
84671.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep4);
84681.2Skamil
84691.95Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step_signalmasked);
84701.95Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step_signalignored);
84711.95Skamil
84721.1Skamil	ATF_TP_ADD_TC(tp, kill1);
84731.1Skamil	ATF_TP_ADD_TC(tp, kill2);
84741.75Skamil	ATF_TP_ADD_TC(tp, kill3);
84751.1Skamil
84761.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0);
84771.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1);
84781.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2);
84791.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3);
84801.77Skamil
84811.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus);
84821.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus);
84831.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus);
84841.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus);
84851.143Skamil
84861.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_sigmask);
84871.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_sigmask);
84881.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_sigmask);
84891.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_sigmask);
84901.143Skamil
84911.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_name);
84921.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_name);
84931.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_name);
84941.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_name);
84951.143Skamil
84961.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_private);
84971.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_private);
84981.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_private);
84991.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_private);
85001.143Skamil
85011.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0);
85021.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1);
85031.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2);
85041.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3);
85051.143Skamil
85061.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_sigmask);
85071.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_sigmask);
85081.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_sigmask);
85091.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_sigmask);
85101.143Skamil
85111.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_name);
85121.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_name);
85131.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_name);
85141.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_name);
85151.143Skamil
85161.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_private);
85171.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_private);
85181.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_private);
85191.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_private);
85201.143Skamil
85211.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo0);
85221.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo1);
85231.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo2);
85241.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo3);
85251.1Skamil
85261.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_unmodified);
85271.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_faked);
85281.79Skamil
85291.82Skamil	ATF_TP_ADD_TC(tp, traceme_exec);
85301.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_exec);
85311.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_exec);
85321.1Skamil
85331.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_nolwpevents);
85341.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit);
85351.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate);
85361.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit);
85371.1Skamil
85381.84Skamil	ATF_TP_ADD_TC(tp, signal_mask_unrelated);
85391.84Skamil
85401.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_singalmasked);
85411.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_singalignored);
85421.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_singalmasked);
85431.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_singalignored);
85441.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_singalmasked);
85451.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_singalignored);
85461.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vforkdone_singalmasked);
85471.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vforkdone_singalignored);
85481.99Skamil
85491.1Skamil	ATF_TP_ADD_TC(tp, signal9);
85501.1Skamil	ATF_TP_ADD_TC(tp, signal10);
85511.1Skamil
85521.1Skamil	ATF_TP_ADD_TC(tp, suspend2);
85531.1Skamil
85541.1Skamil	ATF_TP_ADD_TC(tp, resume1);
85551.1Skamil
85561.1Skamil	ATF_TP_ADD_TC(tp, syscall1);
85571.1Skamil
85581.1Skamil	ATF_TP_ADD_TC(tp, syscallemu1);
85591.1Skamil
85601.106Skamil	ATF_TP_ADD_TC(tp, clone1);
85611.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone2);
85621.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone3);
85631.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone4);
85641.106Skamil	ATF_TP_ADD_TC(tp, clone5);
85651.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone6);
85661.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone7);
85671.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone8);
85681.106Skamil
85691.106Skamil	ATF_TP_ADD_TC(tp, clone_vm1);
85701.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm2);
85711.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm3);
85721.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm4);
85731.106Skamil	ATF_TP_ADD_TC(tp, clone_vm5);
85741.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm6);
85751.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm7);
85761.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm8);
85771.106Skamil
85781.106Skamil	ATF_TP_ADD_TC(tp, clone_fs1);
85791.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs2);
85801.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs3);
85811.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs4);
85821.106Skamil	ATF_TP_ADD_TC(tp, clone_fs5);
85831.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs6);
85841.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs7);
85851.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs8);
85861.106Skamil
85871.106Skamil	ATF_TP_ADD_TC(tp, clone_files1);
85881.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files2);
85891.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files3);
85901.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files4);
85911.106Skamil	ATF_TP_ADD_TC(tp, clone_files5);
85921.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files6);
85931.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files7);
85941.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files8);
85951.106Skamil
85961.106Skamil//	ATF_TP_ADD_TC(tp, clone_sighand1); // XXX
85971.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand2); // XXX
85981.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand3); // XXX
85991.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand4); // XXX
86001.106Skamil//	ATF_TP_ADD_TC(tp, clone_sighand5); // XXX
86011.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand6); // XXX
86021.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand7); // XXX
86031.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand8); // XXX
86041.106Skamil
86051.106Skamil	ATF_TP_ADD_TC(tp, clone_vfork1);
86061.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork2);
86071.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork3);
86081.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork4);
86091.106Skamil	ATF_TP_ADD_TC(tp, clone_vfork5);
86101.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork6);
86111.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork7);
86121.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork8);
86131.106Skamil
86141.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_signalignored);
86151.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_signalmasked);
86161.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm_signalignored);
86171.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm_signalmasked);
86181.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs_signalignored);
86191.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs_signalmasked);
86201.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files_signalignored);
86211.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files_signalmasked);
86221.103Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand_signalignored); // XXX
86231.103Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand_signalmasked); // XXX
86241.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork_signalignored);
86251.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork_signalmasked);
86261.103Skamil
86271.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone);
86281.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_vm);
86291.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_fs);
86301.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_files);
86311.107Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_sighand); // XXX
86321.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_vfork);
86331.107Skamil
86341.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_continue);
86351.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall);
86361.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach);
86371.122Skamil
86381.130Smgorny	ATF_TP_ADD_TC(tp, core_dump_procinfo);
86391.130Smgorny
86401.138Smgorny#if defined(TWAIT_HAVE_STATUS)
86411.138Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals);
86421.138Smgorny#endif
86431.138Smgorny
86441.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
86451.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_I386();
86461.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_X86();
86471.1Skamil
86481.1Skamil	return atf_no_error();
86491.1Skamil}
8650