t_ptrace_wait.c revision 1.133
11.133Skamil/*	$NetBSD: t_ptrace_wait.c,v 1.133 2019/10/01 22:26:38 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.133Skamil__RCSID("$NetBSD: t_ptrace_wait.c,v 1.133 2019/10/01 22:26:38 kamil Exp $");
311.1Skamil
321.1Skamil#include <sys/param.h>
331.1Skamil#include <sys/types.h>
341.130Smgorny#include <sys/exec_elf.h>
351.39Skamil#include <sys/mman.h>
361.1Skamil#include <sys/ptrace.h>
371.1Skamil#include <sys/resource.h>
381.1Skamil#include <sys/stat.h>
391.1Skamil#include <sys/syscall.h>
401.1Skamil#include <sys/sysctl.h>
411.129Smgorny#include <sys/uio.h>
421.1Skamil#include <sys/wait.h>
431.1Skamil#include <machine/reg.h>
441.132Skamil#include <assert.h>
451.1Skamil#include <elf.h>
461.1Skamil#include <err.h>
471.1Skamil#include <errno.h>
481.130Smgorny#include <fcntl.h>
491.1Skamil#include <lwp.h>
501.77Skamil#include <pthread.h>
511.1Skamil#include <sched.h>
521.1Skamil#include <signal.h>
531.124Skamil#include <spawn.h>
541.1Skamil#include <stdint.h>
551.1Skamil#include <stdio.h>
561.1Skamil#include <stdlib.h>
571.1Skamil#include <strings.h>
581.26Skamil#include <time.h>
591.1Skamil#include <unistd.h>
601.1Skamil
611.114Skamil#include <fenv.h>
621.114Skamil#if (__arm__ && !__SOFTFP__) || __aarch64__
631.114Skamil#include <ieeefp.h> /* only need for ARM Cortex/Neon hack */
641.114Skamil#endif
651.114Skamil
661.121Smgorny#if defined(__i386__) || defined(__x86_64__)
671.121Smgorny#include <cpuid.h>
681.121Smgorny#include <x86/cpu_extended_state.h>
691.129Smgorny#include <x86/specialreg.h>
701.121Smgorny#endif
711.121Smgorny
721.130Smgorny#include <libelf.h>
731.130Smgorny#include <gelf.h>
741.130Smgorny
751.1Skamil#include <atf-c.h>
761.1Skamil
771.132Skamil/* Assumptions in the kernel code that must be kept. */
781.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_report_event) ==
791.132Skamil    sizeof(((siginfo_t *)0)->si_pe_report_event),
801.132Skamil    "pe_report_event and si_pe_report_event must be of the same size");
811.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_other_pid) ==
821.132Skamil    sizeof(((siginfo_t *)0)->si_pe_other_pid),
831.132Skamil    "pe_other_pid and si_pe_other_pid must be of the same size");
841.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_lwp) ==
851.132Skamil    sizeof(((siginfo_t *)0)->si_pe_lwp),
861.132Skamil    "pe_lwp and si_pe_lwp must be of the same size");
871.132Skamilstatic_assert(sizeof(((struct ptrace_state *)0)->pe_other_pid) ==
881.132Skamil    sizeof(((struct ptrace_state *)0)->pe_lwp),
891.132Skamil    "pe_other_pid and pe_lwp must be of the same size");
901.132Skamil
911.1Skamil#include "h_macros.h"
921.1Skamil
931.1Skamil#include "t_ptrace_wait.h"
941.1Skamil#include "msg.h"
951.1Skamil
961.1Skamil#define PARENT_TO_CHILD(info, fds, msg) \
971.61Skre    SYSCALL_REQUIRE(msg_write_child(info " to child " # fds, &fds, &msg, \
981.61Skre	sizeof(msg)) == 0)
991.1Skamil
1001.1Skamil#define CHILD_FROM_PARENT(info, fds, msg) \
1011.61Skre    FORKEE_ASSERT(msg_read_parent(info " from parent " # fds, &fds, &msg, \
1021.61Skre	sizeof(msg)) == 0)
1031.1Skamil
1041.1Skamil#define CHILD_TO_PARENT(info, fds, msg) \
1051.61Skre    FORKEE_ASSERT(msg_write_parent(info " to parent " # fds, &fds, &msg, \
1061.61Skre	sizeof(msg)) == 0)
1071.1Skamil
1081.1Skamil#define PARENT_FROM_CHILD(info, fds, msg) \
1091.61Skre    SYSCALL_REQUIRE(msg_read_child(info " from parent " # fds, &fds, &msg, \
1101.61Skre	sizeof(msg)) == 0)
1111.13Schristos
1121.13Schristos#define SYSCALL_REQUIRE(expr) ATF_REQUIRE_MSG(expr, "%s: %s", # expr, \
1131.13Schristos    strerror(errno))
1141.18Schristos#define SYSCALL_REQUIRE_ERRNO(res, exp) ATF_REQUIRE_MSG(res == exp, \
1151.18Schristos    "%d(%s) != %d", res, strerror(res), exp)
1161.13Schristos
1171.13Schristosstatic int debug = 0;
1181.13Schristos
1191.13Schristos#define DPRINTF(a, ...)	do  \
1201.123Skamil	if (debug) \
1211.123Skamil	printf("%s() %s:%d " a, __func__, __FILE__, __LINE__,  ##__VA_ARGS__); \
1221.13Schristos    while (/*CONSTCOND*/0)
1231.1Skamil
1241.110Skamil#ifndef TEST_VFORK_ENABLED
1251.127Skamil#define TEST_VFORK_ENABLED 1
1261.110Skamil#endif
1271.109Skamil
1281.128Skamil#ifndef TEST_LWP_ENABLED
1291.128Skamil#define TEST_LWP_ENABLED 0
1301.128Skamil#endif
1311.128Skamil
1321.34Skamil/// ----------------------------------------------------------------------------
1331.34Skamil
1341.33Skamilstatic void
1351.33Skamiltraceme_raise(int sigval)
1361.1Skamil{
1371.1Skamil	const int exitval = 5;
1381.1Skamil	pid_t child, wpid;
1391.1Skamil#if defined(TWAIT_HAVE_STATUS)
1401.1Skamil	int status;
1411.1Skamil#endif
1421.1Skamil
1431.133Skamil	ptrace_state_t state, zero_state;
1441.133Skamil	const int slen = sizeof(state);
1451.45Skamil	struct ptrace_siginfo info;
1461.133Skamil	memset(&zero_state, 0, sizeof(zero_state));
1471.45Skamil	memset(&info, 0, sizeof(info));
1481.45Skamil
1491.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
1501.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
1511.1Skamil	if (child == 0) {
1521.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1531.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
1541.1Skamil
1551.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
1561.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
1571.1Skamil
1581.36Skamil		switch (sigval) {
1591.36Skamil		case SIGKILL:
1601.36Skamil			/* NOTREACHED */
1611.36Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
1621.70Smrg			__unreachable();
1631.36Skamil		default:
1641.36Skamil			DPRINTF("Before exiting of the child process\n");
1651.36Skamil			_exit(exitval);
1661.36Skamil		}
1671.1Skamil	}
1681.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
1691.1Skamil
1701.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1711.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
1721.1Skamil
1731.36Skamil	switch (sigval) {
1741.36Skamil	case SIGKILL:
1751.36Skamil		validate_status_signaled(status, sigval, 0);
1761.133Skamil		SYSCALL_REQUIRE(
1771.133Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) == -1);
1781.133Skamil
1791.36Skamil		break;
1801.36Skamil	default:
1811.36Skamil		validate_status_stopped(status, sigval);
1821.1Skamil
1831.45Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
1841.61Skre			"child\n");
1851.45Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
1861.61Skre			sizeof(info)) != -1);
1871.45Skamil
1881.45Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
1891.45Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
1901.61Skre			"si_errno=%#x\n",
1911.61Skre			info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
1921.61Skre			info.psi_siginfo.si_errno);
1931.45Skamil
1941.45Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
1951.45Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
1961.45Skamil
1971.133Skamil		DPRINTF("Assert that PT_GET_PROCESS_STATE returns non-error");
1981.133Skamil		SYSCALL_REQUIRE(
1991.133Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
2001.133Skamil		ATF_REQUIRE(memcmp(&state, &zero_state, slen) == 0);
2011.133Skamil
2021.36Skamil		DPRINTF("Before resuming the child process where it left off "
2031.36Skamil		    "and without signal to be sent\n");
2041.36Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
2051.1Skamil
2061.36Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2071.36Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
2081.61Skre		    child);
2091.36Skamil		break;
2101.36Skamil	}
2111.1Skamil
2121.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2131.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
2141.1Skamil}
2151.1Skamil
2161.61Skre#define TRACEME_RAISE(test, sig)					\
2171.61SkreATF_TC(test);								\
2181.61SkreATF_TC_HEAD(test, tc)							\
2191.61Skre{									\
2201.61Skre	atf_tc_set_md_var(tc, "descr",					\
2211.61Skre	    "Verify " #sig " followed by _exit(2) in a child");		\
2221.61Skre}									\
2231.61Skre									\
2241.61SkreATF_TC_BODY(test, tc)							\
2251.61Skre{									\
2261.61Skre									\
2271.61Skre	traceme_raise(sig);						\
2281.33Skamil}
2291.33Skamil
2301.36SkamilTRACEME_RAISE(traceme_raise1, SIGKILL) /* non-maskable */
2311.33SkamilTRACEME_RAISE(traceme_raise2, SIGSTOP) /* non-maskable */
2321.33SkamilTRACEME_RAISE(traceme_raise3, SIGABRT) /* regular abort trap */
2331.33SkamilTRACEME_RAISE(traceme_raise4, SIGHUP)  /* hangup */
2341.33SkamilTRACEME_RAISE(traceme_raise5, SIGCONT) /* continued? */
2351.85SkamilTRACEME_RAISE(traceme_raise6, SIGTRAP) /* crash signal */
2361.85SkamilTRACEME_RAISE(traceme_raise7, SIGBUS) /* crash signal */
2371.85SkamilTRACEME_RAISE(traceme_raise8, SIGILL) /* crash signal */
2381.85SkamilTRACEME_RAISE(traceme_raise9, SIGFPE) /* crash signal */
2391.85SkamilTRACEME_RAISE(traceme_raise10, SIGSEGV) /* crash signal */
2401.33Skamil
2411.34Skamil/// ----------------------------------------------------------------------------
2421.1Skamil
2431.1Skamilstatic void
2441.87Skamiltraceme_raisesignal_ignored(int sigignored)
2451.87Skamil{
2461.87Skamil	const int exitval = 5;
2471.87Skamil	const int sigval = SIGSTOP;
2481.87Skamil	pid_t child, wpid;
2491.87Skamil	struct sigaction sa;
2501.87Skamil#if defined(TWAIT_HAVE_STATUS)
2511.87Skamil	int status;
2521.87Skamil#endif
2531.87Skamil	struct ptrace_siginfo info;
2541.87Skamil
2551.87Skamil	memset(&info, 0, sizeof(info));
2561.87Skamil
2571.87Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
2581.87Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
2591.87Skamil	if (child == 0) {
2601.87Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
2611.87Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
2621.87Skamil
2631.87Skamil		memset(&sa, 0, sizeof(sa));
2641.87Skamil		sa.sa_handler = SIG_IGN;
2651.87Skamil		sigemptyset(&sa.sa_mask);
2661.87Skamil		FORKEE_ASSERT(sigaction(sigignored, &sa, NULL) != -1);
2671.87Skamil
2681.87Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
2691.87Skamil		FORKEE_ASSERT(raise(sigval) == 0);
2701.87Skamil
2711.87Skamil		DPRINTF("Before raising %s from child\n",
2721.87Skamil		    strsignal(sigignored));
2731.87Skamil		FORKEE_ASSERT(raise(sigignored) == 0);
2741.87Skamil
2751.87Skamil		DPRINTF("Before exiting of the child process\n");
2761.87Skamil		_exit(exitval);
2771.87Skamil	}
2781.87Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
2791.87Skamil
2801.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2811.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2821.87Skamil
2831.87Skamil	validate_status_stopped(status, sigval);
2841.87Skamil
2851.87Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
2861.87Skamil	SYSCALL_REQUIRE(
2871.87Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
2881.87Skamil
2891.87Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
2901.87Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
2911.87Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
2921.87Skamil	    info.psi_siginfo.si_errno);
2931.87Skamil
2941.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
2951.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
2961.87Skamil
2971.87Skamil	DPRINTF("Before resuming the child process where it left off and "
2981.87Skamil	    "without signal to be sent\n");
2991.87Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
3001.87Skamil
3011.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3021.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
3031.87Skamil
3041.87Skamil	validate_status_stopped(status, sigignored);
3051.87Skamil
3061.87Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
3071.87Skamil	SYSCALL_REQUIRE(
3081.87Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
3091.87Skamil
3101.87Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
3111.87Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
3121.87Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
3131.87Skamil	    info.psi_siginfo.si_errno);
3141.87Skamil
3151.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigignored);
3161.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
3171.87Skamil
3181.87Skamil	DPRINTF("Before resuming the child process where it left off and "
3191.87Skamil	    "without signal to be sent\n");
3201.87Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
3211.87Skamil
3221.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3231.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
3241.87Skamil
3251.87Skamil	validate_status_exited(status, exitval);
3261.87Skamil
3271.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3281.87Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
3291.87Skamil}
3301.87Skamil
3311.87Skamil#define TRACEME_RAISESIGNAL_IGNORED(test, sig)				\
3321.87SkamilATF_TC(test);								\
3331.87SkamilATF_TC_HEAD(test, tc)							\
3341.87Skamil{									\
3351.87Skamil	atf_tc_set_md_var(tc, "descr",					\
3361.87Skamil	    "Verify that ignoring (with SIG_IGN) " #sig " in tracee "	\
3371.87Skamil	    "does not stop tracer from catching this raised signal");	\
3381.87Skamil}									\
3391.87Skamil									\
3401.87SkamilATF_TC_BODY(test, tc)							\
3411.87Skamil{									\
3421.87Skamil									\
3431.87Skamil	traceme_raisesignal_ignored(sig);				\
3441.87Skamil}
3451.87Skamil
3461.87Skamil// A signal handler for SIGKILL and SIGSTOP cannot be ignored.
3471.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored1, SIGABRT) /* abort */
3481.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored2, SIGHUP)  /* hangup */
3491.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored3, SIGCONT) /* cont. */
3501.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored4, SIGTRAP) /* crash */
3511.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored5, SIGBUS) /* crash */
3521.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored6, SIGILL) /* crash */
3531.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored7, SIGFPE) /* crash */
3541.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored8, SIGSEGV) /* crash */
3551.87Skamil
3561.87Skamil/// ----------------------------------------------------------------------------
3571.87Skamil
3581.87Skamilstatic void
3591.86Skamiltraceme_raisesignal_masked(int sigmasked)
3601.86Skamil{
3611.86Skamil	const int exitval = 5;
3621.86Skamil	const int sigval = SIGSTOP;
3631.86Skamil	pid_t child, wpid;
3641.86Skamil#if defined(TWAIT_HAVE_STATUS)
3651.86Skamil	int status;
3661.86Skamil#endif
3671.86Skamil	sigset_t intmask;
3681.86Skamil	struct ptrace_siginfo info;
3691.86Skamil
3701.86Skamil	memset(&info, 0, sizeof(info));
3711.86Skamil
3721.86Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
3731.86Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
3741.86Skamil	if (child == 0) {
3751.86Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
3761.86Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
3771.86Skamil
3781.86Skamil		sigemptyset(&intmask);
3791.86Skamil		sigaddset(&intmask, sigmasked);
3801.86Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
3811.86Skamil
3821.86Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
3831.86Skamil		FORKEE_ASSERT(raise(sigval) == 0);
3841.86Skamil
3851.86Skamil		DPRINTF("Before raising %s breakpoint from child\n",
3861.86Skamil		    strsignal(sigmasked));
3871.86Skamil		FORKEE_ASSERT(raise(sigmasked) == 0);
3881.86Skamil
3891.86Skamil		DPRINTF("Before exiting of the child process\n");
3901.86Skamil		_exit(exitval);
3911.86Skamil	}
3921.86Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
3931.86Skamil
3941.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3951.86Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
3961.86Skamil
3971.86Skamil	validate_status_stopped(status, sigval);
3981.86Skamil
3991.86Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
4001.86Skamil	SYSCALL_REQUIRE(
4011.86Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
4021.86Skamil
4031.86Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
4041.86Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
4051.86Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
4061.86Skamil	    info.psi_siginfo.si_errno);
4071.86Skamil
4081.86Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
4091.86Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
4101.86Skamil
4111.86Skamil	DPRINTF("Before resuming the child process where it left off and "
4121.86Skamil	    "without signal to be sent\n");
4131.86Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
4141.86Skamil
4151.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
4161.86Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
4171.86Skamil
4181.86Skamil	validate_status_exited(status, exitval);
4191.86Skamil
4201.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
4211.86Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
4221.86Skamil}
4231.86Skamil
4241.86Skamil#define TRACEME_RAISESIGNAL_MASKED(test, sig)				\
4251.86SkamilATF_TC(test);								\
4261.86SkamilATF_TC_HEAD(test, tc)							\
4271.86Skamil{									\
4281.86Skamil	atf_tc_set_md_var(tc, "descr",					\
4291.86Skamil	    "Verify that masking (with SIG_BLOCK) " #sig " in tracee "	\
4301.86Skamil	    "stops tracer from catching this raised signal");		\
4311.86Skamil}									\
4321.86Skamil									\
4331.86SkamilATF_TC_BODY(test, tc)							\
4341.86Skamil{									\
4351.86Skamil									\
4361.86Skamil	traceme_raisesignal_masked(sig);				\
4371.86Skamil}
4381.86Skamil
4391.86Skamil// A signal handler for SIGKILL and SIGSTOP cannot be masked.
4401.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked1, SIGABRT) /* abort trap */
4411.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked2, SIGHUP)  /* hangup */
4421.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked3, SIGCONT) /* continued? */
4431.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked4, SIGTRAP) /* crash sig. */
4441.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked5, SIGBUS) /* crash sig. */
4451.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked6, SIGILL) /* crash sig. */
4461.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked7, SIGFPE) /* crash sig. */
4471.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked8, SIGSEGV) /* crash sig. */
4481.86Skamil
4491.86Skamil/// ----------------------------------------------------------------------------
4501.86Skamil
4511.86Skamilstatic void
4521.59Skamiltraceme_crash(int sig)
4531.59Skamil{
4541.59Skamil	pid_t child, wpid;
4551.59Skamil#if defined(TWAIT_HAVE_STATUS)
4561.59Skamil	int status;
4571.59Skamil#endif
4581.59Skamil	struct ptrace_siginfo info;
4591.61Skre
4601.71Skamil#ifndef PTRACE_ILLEGAL_ASM
4611.71Skamil	if (sig == SIGILL)
4621.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
4631.71Skamil#endif
4641.71Skamil
4651.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
4661.114Skamil		atf_tc_skip("FP exceptions are not supported");
4671.114Skamil
4681.59Skamil	memset(&info, 0, sizeof(info));
4691.59Skamil
4701.59Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
4711.59Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
4721.59Skamil	if (child == 0) {
4731.59Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
4741.59Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
4751.59Skamil
4761.59Skamil		DPRINTF("Before executing a trap\n");
4771.59Skamil		switch (sig) {
4781.59Skamil		case SIGTRAP:
4791.59Skamil			trigger_trap();
4801.59Skamil			break;
4811.59Skamil		case SIGSEGV:
4821.59Skamil			trigger_segv();
4831.59Skamil			break;
4841.59Skamil		case SIGILL:
4851.59Skamil			trigger_ill();
4861.59Skamil			break;
4871.59Skamil		case SIGFPE:
4881.59Skamil			trigger_fpe();
4891.59Skamil			break;
4901.59Skamil		case SIGBUS:
4911.59Skamil			trigger_bus();
4921.59Skamil			break;
4931.59Skamil		default:
4941.59Skamil			/* NOTREACHED */
4951.59Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
4961.59Skamil		}
4971.59Skamil
4981.59Skamil		/* NOTREACHED */
4991.59Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
5001.59Skamil	}
5011.59Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
5021.59Skamil
5031.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5041.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
5051.59Skamil
5061.59Skamil	validate_status_stopped(status, sig);
5071.59Skamil
5081.59Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
5091.61Skre	SYSCALL_REQUIRE(
5101.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
5111.59Skamil
5121.59Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
5131.59Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
5141.61Skre	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
5151.61Skre	    info.psi_siginfo.si_errno);
5161.59Skamil
5171.59Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
5181.59Skamil	switch (sig) {
5191.59Skamil	case SIGTRAP:
5201.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
5211.59Skamil		break;
5221.59Skamil	case SIGSEGV:
5231.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
5241.59Skamil		break;
5251.71Skamil	case SIGILL:
5261.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
5271.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
5281.71Skamil		break;
5291.59Skamil	case SIGFPE:
5301.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
5311.59Skamil		break;
5321.59Skamil	case SIGBUS:
5331.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
5341.59Skamil		break;
5351.59Skamil	}
5361.59Skamil
5371.59Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
5381.59Skamil
5391.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5401.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
5411.59Skamil
5421.59Skamil	validate_status_signaled(status, SIGKILL, 0);
5431.59Skamil
5441.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5451.59Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
5461.59Skamil}
5471.59Skamil
5481.61Skre#define TRACEME_CRASH(test, sig)					\
5491.61SkreATF_TC(test);								\
5501.61SkreATF_TC_HEAD(test, tc)							\
5511.61Skre{									\
5521.61Skre	atf_tc_set_md_var(tc, "descr",					\
5531.61Skre	    "Verify crash signal " #sig " in a child after PT_TRACE_ME"); \
5541.61Skre}									\
5551.61Skre									\
5561.61SkreATF_TC_BODY(test, tc)							\
5571.61Skre{									\
5581.61Skre									\
5591.61Skre	traceme_crash(sig);						\
5601.59Skamil}
5611.59Skamil
5621.59SkamilTRACEME_CRASH(traceme_crash_trap, SIGTRAP)
5631.59SkamilTRACEME_CRASH(traceme_crash_segv, SIGSEGV)
5641.71SkamilTRACEME_CRASH(traceme_crash_ill, SIGILL)
5651.59SkamilTRACEME_CRASH(traceme_crash_fpe, SIGFPE)
5661.59SkamilTRACEME_CRASH(traceme_crash_bus, SIGBUS)
5671.59Skamil
5681.59Skamil/// ----------------------------------------------------------------------------
5691.59Skamil
5701.59Skamilstatic void
5711.88Skamiltraceme_signalmasked_crash(int sig)
5721.88Skamil{
5731.89Skamil	const int sigval = SIGSTOP;
5741.88Skamil	pid_t child, wpid;
5751.88Skamil#if defined(TWAIT_HAVE_STATUS)
5761.88Skamil	int status;
5771.88Skamil#endif
5781.88Skamil	struct ptrace_siginfo info;
5791.88Skamil	sigset_t intmask;
5801.89Skamil	struct kinfo_proc2 kp;
5811.89Skamil	size_t len = sizeof(kp);
5821.89Skamil
5831.89Skamil	int name[6];
5841.89Skamil	const size_t namelen = __arraycount(name);
5851.89Skamil	ki_sigset_t kp_sigmask;
5861.88Skamil
5871.88Skamil#ifndef PTRACE_ILLEGAL_ASM
5881.88Skamil	if (sig == SIGILL)
5891.88Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
5901.88Skamil#endif
5911.88Skamil
5921.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
5931.114Skamil		atf_tc_skip("FP exceptions are not supported");
5941.114Skamil
5951.88Skamil	memset(&info, 0, sizeof(info));
5961.88Skamil
5971.88Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
5981.88Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
5991.88Skamil	if (child == 0) {
6001.88Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
6011.88Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
6021.88Skamil
6031.88Skamil		sigemptyset(&intmask);
6041.88Skamil		sigaddset(&intmask, sig);
6051.88Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
6061.88Skamil
6071.89Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
6081.89Skamil		FORKEE_ASSERT(raise(sigval) == 0);
6091.89Skamil
6101.88Skamil		DPRINTF("Before executing a trap\n");
6111.88Skamil		switch (sig) {
6121.88Skamil		case SIGTRAP:
6131.88Skamil			trigger_trap();
6141.88Skamil			break;
6151.88Skamil		case SIGSEGV:
6161.88Skamil			trigger_segv();
6171.88Skamil			break;
6181.88Skamil		case SIGILL:
6191.88Skamil			trigger_ill();
6201.88Skamil			break;
6211.88Skamil		case SIGFPE:
6221.88Skamil			trigger_fpe();
6231.88Skamil			break;
6241.88Skamil		case SIGBUS:
6251.88Skamil			trigger_bus();
6261.88Skamil			break;
6271.88Skamil		default:
6281.88Skamil			/* NOTREACHED */
6291.88Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
6301.88Skamil		}
6311.88Skamil
6321.88Skamil		/* NOTREACHED */
6331.88Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
6341.88Skamil	}
6351.88Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
6361.88Skamil
6371.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6381.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
6391.88Skamil
6401.89Skamil	validate_status_stopped(status, sigval);
6411.89Skamil
6421.89Skamil	name[0] = CTL_KERN,
6431.89Skamil	name[1] = KERN_PROC2,
6441.89Skamil	name[2] = KERN_PROC_PID;
6451.89Skamil	name[3] = child;
6461.89Skamil	name[4] = sizeof(kp);
6471.89Skamil	name[5] = 1;
6481.89Skamil
6491.89Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
6501.89Skamil
6511.89Skamil	kp_sigmask = kp.p_sigmask;
6521.89Skamil
6531.89Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
6541.89Skamil	SYSCALL_REQUIRE(
6551.89Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
6561.89Skamil
6571.89Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
6581.89Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
6591.89Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
6601.89Skamil	    info.psi_siginfo.si_errno);
6611.89Skamil
6621.89Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
6631.89Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
6641.89Skamil
6651.89Skamil	DPRINTF("Before resuming the child process where it left off and "
6661.89Skamil	    "without signal to be sent\n");
6671.89Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
6681.89Skamil
6691.89Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6701.89Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
6711.89Skamil
6721.88Skamil	validate_status_stopped(status, sig);
6731.88Skamil
6741.88Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
6751.88Skamil	SYSCALL_REQUIRE(
6761.88Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
6771.88Skamil
6781.88Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
6791.88Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
6801.88Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
6811.88Skamil	    info.psi_siginfo.si_errno);
6821.88Skamil
6831.89Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
6841.89Skamil
6851.89Skamil	DPRINTF("kp_sigmask="
6861.89Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
6871.89Skamil	    kp_sigmask.__bits[0], kp_sigmask.__bits[1], kp_sigmask.__bits[2],
6881.89Skamil	    kp_sigmask.__bits[3]);
6891.89Skamil
6901.89Skamil	DPRINTF("kp.p_sigmask="
6911.89Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
6921.89Skamil	    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
6931.89Skamil	    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
6941.89Skamil
6951.89Skamil	ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask, sizeof(kp_sigmask)));
6961.89Skamil
6971.88Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
6981.88Skamil	switch (sig) {
6991.88Skamil	case SIGTRAP:
7001.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
7011.88Skamil		break;
7021.88Skamil	case SIGSEGV:
7031.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
7041.88Skamil		break;
7051.88Skamil	case SIGILL:
7061.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
7071.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
7081.88Skamil		break;
7091.88Skamil	case SIGFPE:
7101.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
7111.88Skamil		break;
7121.88Skamil	case SIGBUS:
7131.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
7141.88Skamil		break;
7151.88Skamil	}
7161.88Skamil
7171.88Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
7181.88Skamil
7191.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
7201.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
7211.88Skamil
7221.88Skamil	validate_status_signaled(status, SIGKILL, 0);
7231.88Skamil
7241.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
7251.88Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
7261.88Skamil}
7271.88Skamil
7281.88Skamil#define TRACEME_SIGNALMASKED_CRASH(test, sig)				\
7291.88SkamilATF_TC(test);								\
7301.88SkamilATF_TC_HEAD(test, tc)							\
7311.88Skamil{									\
7321.88Skamil	atf_tc_set_md_var(tc, "descr",					\
7331.88Skamil	    "Verify masked crash signal " #sig " in a child after "	\
7341.88Skamil	    "PT_TRACE_ME is delivered to its tracer");			\
7351.88Skamil}									\
7361.88Skamil									\
7371.88SkamilATF_TC_BODY(test, tc)							\
7381.88Skamil{									\
7391.88Skamil									\
7401.88Skamil	traceme_signalmasked_crash(sig);				\
7411.88Skamil}
7421.88Skamil
7431.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_trap, SIGTRAP)
7441.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_segv, SIGSEGV)
7451.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_ill, SIGILL)
7461.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_fpe, SIGFPE)
7471.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_bus, SIGBUS)
7481.88Skamil
7491.88Skamil/// ----------------------------------------------------------------------------
7501.88Skamil
7511.88Skamilstatic void
7521.88Skamiltraceme_signalignored_crash(int sig)
7531.88Skamil{
7541.90Skamil	const int sigval = SIGSTOP;
7551.88Skamil	pid_t child, wpid;
7561.88Skamil#if defined(TWAIT_HAVE_STATUS)
7571.88Skamil	int status;
7581.88Skamil#endif
7591.88Skamil	struct sigaction sa;
7601.88Skamil	struct ptrace_siginfo info;
7611.90Skamil	struct kinfo_proc2 kp;
7621.90Skamil	size_t len = sizeof(kp);
7631.90Skamil
7641.90Skamil	int name[6];
7651.90Skamil	const size_t namelen = __arraycount(name);
7661.90Skamil	ki_sigset_t kp_sigignore;
7671.88Skamil
7681.88Skamil#ifndef PTRACE_ILLEGAL_ASM
7691.88Skamil	if (sig == SIGILL)
7701.88Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
7711.88Skamil#endif
7721.88Skamil
7731.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
7741.114Skamil		atf_tc_skip("FP exceptions are not supported");
7751.114Skamil
7761.88Skamil	memset(&info, 0, sizeof(info));
7771.88Skamil
7781.88Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
7791.88Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
7801.88Skamil	if (child == 0) {
7811.88Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
7821.88Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
7831.88Skamil
7841.88Skamil		memset(&sa, 0, sizeof(sa));
7851.88Skamil		sa.sa_handler = SIG_IGN;
7861.88Skamil		sigemptyset(&sa.sa_mask);
7871.88Skamil
7881.88Skamil		FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
7891.88Skamil
7901.90Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
7911.90Skamil		FORKEE_ASSERT(raise(sigval) == 0);
7921.90Skamil
7931.88Skamil		DPRINTF("Before executing a trap\n");
7941.88Skamil		switch (sig) {
7951.88Skamil		case SIGTRAP:
7961.88Skamil			trigger_trap();
7971.88Skamil			break;
7981.88Skamil		case SIGSEGV:
7991.88Skamil			trigger_segv();
8001.88Skamil			break;
8011.88Skamil		case SIGILL:
8021.88Skamil			trigger_ill();
8031.88Skamil			break;
8041.88Skamil		case SIGFPE:
8051.88Skamil			trigger_fpe();
8061.88Skamil			break;
8071.88Skamil		case SIGBUS:
8081.88Skamil			trigger_bus();
8091.88Skamil			break;
8101.88Skamil		default:
8111.88Skamil			/* NOTREACHED */
8121.88Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
8131.88Skamil		}
8141.88Skamil
8151.88Skamil		/* NOTREACHED */
8161.88Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
8171.88Skamil	}
8181.88Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
8191.88Skamil
8201.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8211.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8221.88Skamil
8231.90Skamil	validate_status_stopped(status, sigval);
8241.90Skamil
8251.90Skamil	name[0] = CTL_KERN,
8261.90Skamil	name[1] = KERN_PROC2,
8271.90Skamil	name[2] = KERN_PROC_PID;
8281.90Skamil	name[3] = child;
8291.90Skamil	name[4] = sizeof(kp);
8301.90Skamil	name[5] = 1;
8311.90Skamil
8321.90Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
8331.90Skamil
8341.90Skamil	kp_sigignore = kp.p_sigignore;
8351.90Skamil
8361.90Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
8371.90Skamil	SYSCALL_REQUIRE(
8381.90Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
8391.90Skamil
8401.90Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
8411.90Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
8421.90Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
8431.90Skamil	    info.psi_siginfo.si_errno);
8441.90Skamil
8451.90Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
8461.90Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
8471.90Skamil
8481.90Skamil	DPRINTF("Before resuming the child process where it left off and "
8491.90Skamil	    "without signal to be sent\n");
8501.90Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
8511.90Skamil
8521.90Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8531.90Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8541.90Skamil
8551.88Skamil	validate_status_stopped(status, sig);
8561.88Skamil
8571.88Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
8581.88Skamil	SYSCALL_REQUIRE(
8591.88Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
8601.88Skamil
8611.88Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
8621.88Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
8631.88Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
8641.88Skamil	    info.psi_siginfo.si_errno);
8651.88Skamil
8661.90Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
8671.90Skamil
8681.90Skamil	DPRINTF("kp_sigignore="
8691.90Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
8701.90Skamil	    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
8711.90Skamil	    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
8721.90Skamil
8731.90Skamil	DPRINTF("kp.p_sigignore="
8741.90Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
8751.90Skamil	    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
8761.90Skamil	    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
8771.90Skamil
8781.90Skamil	ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore, sizeof(kp_sigignore)));
8791.90Skamil
8801.88Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
8811.88Skamil	switch (sig) {
8821.88Skamil	case SIGTRAP:
8831.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
8841.88Skamil		break;
8851.88Skamil	case SIGSEGV:
8861.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
8871.88Skamil		break;
8881.88Skamil	case SIGILL:
8891.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
8901.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
8911.88Skamil		break;
8921.88Skamil	case SIGFPE:
8931.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
8941.88Skamil		break;
8951.88Skamil	case SIGBUS:
8961.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
8971.88Skamil		break;
8981.88Skamil	}
8991.88Skamil
9001.88Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
9011.88Skamil
9021.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9031.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9041.88Skamil
9051.88Skamil	validate_status_signaled(status, SIGKILL, 0);
9061.88Skamil
9071.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9081.88Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
9091.88Skamil}
9101.88Skamil
9111.88Skamil#define TRACEME_SIGNALIGNORED_CRASH(test, sig)				\
9121.88SkamilATF_TC(test);								\
9131.88SkamilATF_TC_HEAD(test, tc)							\
9141.88Skamil{									\
9151.88Skamil	atf_tc_set_md_var(tc, "descr",					\
9161.88Skamil	    "Verify ignored crash signal " #sig " in a child after "	\
9171.88Skamil	    "PT_TRACE_ME is delivered to its tracer"); 			\
9181.88Skamil}									\
9191.88Skamil									\
9201.88SkamilATF_TC_BODY(test, tc)							\
9211.88Skamil{									\
9221.88Skamil									\
9231.88Skamil	traceme_signalignored_crash(sig);				\
9241.88Skamil}
9251.88Skamil
9261.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_trap, SIGTRAP)
9271.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_segv, SIGSEGV)
9281.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_ill, SIGILL)
9291.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_fpe, SIGFPE)
9301.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_bus, SIGBUS)
9311.88Skamil
9321.88Skamil/// ----------------------------------------------------------------------------
9331.88Skamil
9341.88Skamilstatic void
9351.50Skamiltraceme_sendsignal_handle(int sigsent, void (*sah)(int a), int *traceme_caught)
9361.1Skamil{
9371.1Skamil	const int exitval = 5;
9381.34Skamil	const int sigval = SIGSTOP;
9391.1Skamil	pid_t child, wpid;
9401.1Skamil	struct sigaction sa;
9411.1Skamil#if defined(TWAIT_HAVE_STATUS)
9421.1Skamil	int status;
9431.1Skamil#endif
9441.61Skre	struct ptrace_siginfo info;
9451.1Skamil
9461.45Skamil	memset(&info, 0, sizeof(info));
9471.45Skamil
9481.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
9491.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
9501.1Skamil	if (child == 0) {
9511.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
9521.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
9531.1Skamil
9541.34Skamil		sa.sa_handler = sah;
9551.1Skamil		sa.sa_flags = SA_SIGINFO;
9561.1Skamil		sigemptyset(&sa.sa_mask);
9571.1Skamil
9581.1Skamil		FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
9591.1Skamil
9601.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
9611.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
9621.1Skamil
9631.34Skamil		FORKEE_ASSERT_EQ(*traceme_caught, 1);
9641.1Skamil
9651.13Schristos		DPRINTF("Before exiting of the child process\n");
9661.1Skamil		_exit(exitval);
9671.1Skamil	}
9681.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
9691.1Skamil
9701.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9711.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9721.1Skamil
9731.1Skamil	validate_status_stopped(status, sigval);
9741.1Skamil
9751.45Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
9761.61Skre	SYSCALL_REQUIRE(
9771.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
9781.45Skamil
9791.45Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
9801.45Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
9811.45Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
9821.45Skamil	    info.psi_siginfo.si_errno);
9831.45Skamil
9841.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
9851.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
9861.45Skamil
9871.13Schristos	DPRINTF("Before resuming the child process where it left off and with "
9881.1Skamil	    "signal %s to be sent\n", strsignal(sigsent));
9891.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
9901.1Skamil
9911.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9921.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9931.1Skamil
9941.1Skamil	validate_status_exited(status, exitval);
9951.1Skamil
9961.13Schristos	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
9971.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
9981.1Skamil}
9991.1Skamil
10001.61Skre#define TRACEME_SENDSIGNAL_HANDLE(test, sig)				\
10011.61SkreATF_TC(test);								\
10021.61SkreATF_TC_HEAD(test, tc)							\
10031.61Skre{									\
10041.61Skre	atf_tc_set_md_var(tc, "descr",					\
10051.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
10061.61Skre	    "handled correctly and caught by a signal handler");	\
10071.61Skre}									\
10081.61Skre									\
10091.61Skrestatic int test##_caught = 0;						\
10101.61Skre									\
10111.61Skrestatic void								\
10121.61Skretest##_sighandler(int arg)						\
10131.61Skre{									\
10141.61Skre	FORKEE_ASSERT_EQ(arg, sig);					\
10151.61Skre									\
10161.61Skre	++ test##_caught;						\
10171.61Skre}									\
10181.61Skre									\
10191.61SkreATF_TC_BODY(test, tc)							\
10201.61Skre{									\
10211.61Skre									\
10221.61Skre	traceme_sendsignal_handle(sig, test##_sighandler, & test##_caught); \
10231.34Skamil}
10241.34Skamil
10251.34Skamil// A signal handler for SIGKILL and SIGSTOP cannot be registered.
10261.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle1, SIGABRT) /* abort trap */
10271.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle2, SIGHUP)  /* hangup */
10281.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle3, SIGCONT) /* continued? */
10291.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle4, SIGTRAP) /* crash sig. */
10301.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle5, SIGBUS) /* crash sig. */
10311.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle6, SIGILL) /* crash sig. */
10321.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle7, SIGFPE) /* crash sig. */
10331.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle8, SIGSEGV) /* crash sig. */
10341.34Skamil
10351.34Skamil/// ----------------------------------------------------------------------------
10361.34Skamil
10371.35Skamilstatic void
10381.50Skamiltraceme_sendsignal_masked(int sigsent)
10391.50Skamil{
10401.50Skamil	const int exitval = 5;
10411.50Skamil	const int sigval = SIGSTOP;
10421.50Skamil	pid_t child, wpid;
10431.50Skamil	sigset_t set;
10441.50Skamil#if defined(TWAIT_HAVE_STATUS)
10451.50Skamil	int status;
10461.50Skamil#endif
10471.61Skre	struct ptrace_siginfo info;
10481.50Skamil
10491.50Skamil	memset(&info, 0, sizeof(info));
10501.50Skamil
10511.50Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
10521.50Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
10531.50Skamil	if (child == 0) {
10541.50Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
10551.50Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
10561.50Skamil
10571.50Skamil		sigemptyset(&set);
10581.50Skamil		sigaddset(&set, sigsent);
10591.50Skamil		FORKEE_ASSERT(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
10601.50Skamil
10611.50Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
10621.50Skamil		FORKEE_ASSERT(raise(sigval) == 0);
10631.50Skamil
10641.50Skamil		_exit(exitval);
10651.50Skamil	}
10661.50Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
10671.50Skamil
10681.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10691.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
10701.50Skamil
10711.50Skamil	validate_status_stopped(status, sigval);
10721.50Skamil
10731.50Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
10741.61Skre	SYSCALL_REQUIRE(
10751.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
10761.50Skamil
10771.50Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
10781.50Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
10791.50Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
10801.50Skamil	    info.psi_siginfo.si_errno);
10811.50Skamil
10821.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
10831.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
10841.50Skamil
10851.50Skamil	DPRINTF("Before resuming the child process where it left off and with "
10861.50Skamil	    "signal %s to be sent\n", strsignal(sigsent));
10871.50Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
10881.50Skamil
10891.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10901.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
10911.50Skamil
10921.50Skamil	validate_status_exited(status, exitval);
10931.50Skamil
10941.50Skamil	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
10951.50Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
10961.50Skamil}
10971.50Skamil
10981.61Skre#define TRACEME_SENDSIGNAL_MASKED(test, sig)				\
10991.61SkreATF_TC(test);								\
11001.61SkreATF_TC_HEAD(test, tc)							\
11011.61Skre{									\
11021.61Skre	atf_tc_set_md_var(tc, "descr",					\
11031.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
11041.61Skre	    "handled correctly and the signal is masked by SIG_BLOCK");	\
11051.61Skre}									\
11061.61Skre									\
11071.61SkreATF_TC_BODY(test, tc)							\
11081.61Skre{									\
11091.61Skre									\
11101.61Skre	traceme_sendsignal_masked(sig);					\
11111.50Skamil}
11121.50Skamil
11131.50Skamil// A signal handler for SIGKILL and SIGSTOP cannot be masked.
11141.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked1, SIGABRT) /* abort trap */
11151.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked2, SIGHUP)  /* hangup */
11161.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked3, SIGCONT) /* continued? */
11171.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked4, SIGTRAP) /* crash sig. */
11181.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked5, SIGBUS) /* crash sig. */
11191.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked6, SIGILL) /* crash sig. */
11201.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked7, SIGFPE) /* crash sig. */
11211.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked8, SIGSEGV) /* crash sig. */
11221.50Skamil
11231.50Skamil/// ----------------------------------------------------------------------------
11241.50Skamil
11251.50Skamilstatic void
11261.50Skamiltraceme_sendsignal_ignored(int sigsent)
11271.50Skamil{
11281.50Skamil	const int exitval = 5;
11291.50Skamil	const int sigval = SIGSTOP;
11301.50Skamil	pid_t child, wpid;
11311.50Skamil	struct sigaction sa;
11321.50Skamil#if defined(TWAIT_HAVE_STATUS)
11331.50Skamil	int status;
11341.50Skamil#endif
11351.61Skre	struct ptrace_siginfo info;
11361.50Skamil
11371.50Skamil	memset(&info, 0, sizeof(info));
11381.50Skamil
11391.50Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
11401.50Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
11411.50Skamil	if (child == 0) {
11421.50Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
11431.61Skre
11441.50Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
11451.50Skamil
11461.50Skamil		memset(&sa, 0, sizeof(sa));
11471.50Skamil		sa.sa_handler = SIG_IGN;
11481.50Skamil		sigemptyset(&sa.sa_mask);
11491.50Skamil		FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
11501.50Skamil
11511.50Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
11521.50Skamil		FORKEE_ASSERT(raise(sigval) == 0);
11531.50Skamil
11541.50Skamil		_exit(exitval);
11551.50Skamil	}
11561.50Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
11571.50Skamil
11581.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11591.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11601.50Skamil
11611.50Skamil	validate_status_stopped(status, sigval);
11621.50Skamil
11631.50Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
11641.61Skre	SYSCALL_REQUIRE(
11651.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
11661.50Skamil
11671.50Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
11681.50Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
11691.50Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
11701.50Skamil	    info.psi_siginfo.si_errno);
11711.50Skamil
11721.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
11731.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
11741.50Skamil
11751.50Skamil	DPRINTF("Before resuming the child process where it left off and with "
11761.50Skamil	    "signal %s to be sent\n", strsignal(sigsent));
11771.50Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
11781.50Skamil
11791.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11801.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11811.50Skamil
11821.50Skamil	validate_status_exited(status, exitval);
11831.50Skamil
11841.50Skamil	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
11851.50Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
11861.50Skamil}
11871.50Skamil
11881.61Skre#define TRACEME_SENDSIGNAL_IGNORED(test, sig)				\
11891.61SkreATF_TC(test);								\
11901.61SkreATF_TC_HEAD(test, tc)							\
11911.61Skre{									\
11921.61Skre	atf_tc_set_md_var(tc, "descr",					\
11931.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
11941.61Skre	    "handled correctly and the signal is masked by SIG_IGN");	\
11951.61Skre}									\
11961.61Skre									\
11971.61SkreATF_TC_BODY(test, tc)							\
11981.61Skre{									\
11991.61Skre									\
12001.61Skre	traceme_sendsignal_ignored(sig);				\
12011.50Skamil}
12021.50Skamil
12031.50Skamil// A signal handler for SIGKILL and SIGSTOP cannot be ignored.
12041.61SkreTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored1, SIGABRT) /* abort */
12051.50SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored2, SIGHUP)  /* hangup */
12061.61SkreTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored3, SIGCONT) /* continued */
12071.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored4, SIGTRAP) /* crash s. */
12081.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored5, SIGBUS) /* crash s. */
12091.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored6, SIGILL) /* crash s. */
12101.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored7, SIGFPE) /* crash s. */
12111.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored8, SIGSEGV) /* crash s. */
12121.50Skamil
12131.50Skamil/// ----------------------------------------------------------------------------
12141.50Skamil
12151.50Skamilstatic void
12161.50Skamiltraceme_sendsignal_simple(int sigsent)
12171.1Skamil{
12181.35Skamil	const int sigval = SIGSTOP;
12191.35Skamil	int exitval = 0;
12201.1Skamil	pid_t child, wpid;
12211.1Skamil#if defined(TWAIT_HAVE_STATUS)
12221.1Skamil	int status;
12231.85Skamil	int expect_core;
12241.85Skamil
12251.85Skamil	switch (sigsent) {
12261.85Skamil	case SIGABRT:
12271.85Skamil	case SIGTRAP:
12281.85Skamil	case SIGBUS:
12291.85Skamil	case SIGILL:
12301.85Skamil	case SIGFPE:
12311.85Skamil	case SIGSEGV:
12321.85Skamil		expect_core = 1;
12331.85Skamil		break;
12341.85Skamil	default:
12351.85Skamil		expect_core = 0;
12361.85Skamil		break;
12371.85Skamil	}
12381.1Skamil#endif
12391.61Skre	struct ptrace_siginfo info;
12401.1Skamil
12411.45Skamil	memset(&info, 0, sizeof(info));
12421.45Skamil
12431.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
12441.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
12451.1Skamil	if (child == 0) {
12461.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
12471.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
12481.1Skamil
12491.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
12501.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
12511.1Skamil
12521.35Skamil		switch (sigsent) {
12531.35Skamil		case SIGCONT:
12541.48Skamil		case SIGSTOP:
12551.35Skamil			_exit(exitval);
12561.35Skamil		default:
12571.35Skamil			/* NOTREACHED */
12581.35Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
12591.35Skamil		}
12601.1Skamil	}
12611.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
12621.1Skamil
12631.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12641.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
12651.1Skamil
12661.1Skamil	validate_status_stopped(status, sigval);
12671.1Skamil
12681.45Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
12691.61Skre	SYSCALL_REQUIRE(
12701.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
12711.45Skamil
12721.45Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12731.45Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
12741.45Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12751.45Skamil	    info.psi_siginfo.si_errno);
12761.45Skamil
12771.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
12781.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
12791.45Skamil
12801.13Schristos	DPRINTF("Before resuming the child process where it left off and with "
12811.1Skamil	    "signal %s to be sent\n", strsignal(sigsent));
12821.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
12831.1Skamil
12841.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12851.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
12861.1Skamil
12871.35Skamil	switch (sigsent) {
12881.48Skamil	case SIGSTOP:
12891.48Skamil		validate_status_stopped(status, sigsent);
12901.48Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
12911.61Skre		    "child\n");
12921.48Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
12931.61Skre		    sizeof(info)) != -1);
12941.48Skamil
12951.48Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12961.48Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
12971.61Skre		    "si_errno=%#x\n",
12981.61Skre		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12991.61Skre		    info.psi_siginfo.si_errno);
13001.48Skamil
13011.48Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
13021.48Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
13031.48Skamil
13041.48Skamil		DPRINTF("Before resuming the child process where it left off "
13051.61Skre		    "and with signal %s to be sent\n", strsignal(sigsent));
13061.48Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
13071.48Skamil
13081.48Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
13091.48Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
13101.61Skre		    child);
13111.48Skamil		/* FALLTHROUGH */
13121.35Skamil	case SIGCONT:
13131.35Skamil		validate_status_exited(status, exitval);
13141.35Skamil		break;
13151.35Skamil	default:
13161.35Skamil		validate_status_signaled(status, sigsent, expect_core);
13171.35Skamil		break;
13181.35Skamil	}
13191.1Skamil
13201.13Schristos	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
13211.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
13221.1Skamil}
13231.1Skamil
13241.61Skre#define TRACEME_SENDSIGNAL_SIMPLE(test, sig)				\
13251.61SkreATF_TC(test);								\
13261.61SkreATF_TC_HEAD(test, tc)							\
13271.61Skre{									\
13281.61Skre	atf_tc_set_md_var(tc, "descr",					\
13291.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
13301.61Skre	    "handled correctly in a child without a signal handler");	\
13311.61Skre}									\
13321.61Skre									\
13331.61SkreATF_TC_BODY(test, tc)							\
13341.61Skre{									\
13351.61Skre									\
13361.61Skre	traceme_sendsignal_simple(sig);					\
13371.35Skamil}
13381.35Skamil
13391.61SkreTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple1, SIGKILL) /* non-maskable*/
13401.61SkreTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple2, SIGSTOP) /* non-maskable*/
13411.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple3, SIGABRT) /* abort trap */
13421.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple4, SIGHUP)  /* hangup */
13431.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple5, SIGCONT) /* continued? */
13441.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple6, SIGTRAP) /* crash sig. */
13451.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple7, SIGBUS) /* crash sig. */
13461.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple8, SIGILL) /* crash sig. */
13471.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple9, SIGFPE) /* crash sig. */
13481.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple10, SIGSEGV) /* crash sig. */
13491.35Skamil
13501.35Skamil/// ----------------------------------------------------------------------------
13511.35Skamil
13521.37SkamilATF_TC(traceme_pid1_parent);
13531.37SkamilATF_TC_HEAD(traceme_pid1_parent, tc)
13541.37Skamil{
13551.37Skamil	atf_tc_set_md_var(tc, "descr",
13561.37Skamil	    "Verify that PT_TRACE_ME is not allowed when our parent is PID1");
13571.37Skamil}
13581.37Skamil
13591.37SkamilATF_TC_BODY(traceme_pid1_parent, tc)
13601.37Skamil{
13611.37Skamil	struct msg_fds parent_child;
13621.37Skamil	int exitval_child1 = 1, exitval_child2 = 2;
13631.37Skamil	pid_t child1, child2, wpid;
13641.37Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
13651.37Skamil#if defined(TWAIT_HAVE_STATUS)
13661.37Skamil	int status;
13671.37Skamil#endif
13681.37Skamil
13691.37Skamil	SYSCALL_REQUIRE(msg_open(&parent_child) == 0);
13701.37Skamil
13711.37Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
13721.37Skamil	SYSCALL_REQUIRE((child1 = fork()) != -1);
13731.37Skamil	if (child1 == 0) {
13741.37Skamil		DPRINTF("Before forking process PID=%d\n", getpid());
13751.37Skamil		SYSCALL_REQUIRE((child2 = fork()) != -1);
13761.37Skamil		if (child2 != 0) {
13771.37Skamil			DPRINTF("Parent process PID=%d, child2's PID=%d\n",
13781.61Skre			    getpid(), child2);
13791.37Skamil			_exit(exitval_child1);
13801.37Skamil		}
13811.37Skamil		CHILD_FROM_PARENT("exit child1", parent_child, msg);
13821.37Skamil
13831.37Skamil		DPRINTF("Assert that our parent is PID1 (initproc)\n");
13841.37Skamil		FORKEE_ASSERT_EQ(getppid(), 1);
13851.37Skamil
13861.37Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
13871.37Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) == -1);
13881.37Skamil		SYSCALL_REQUIRE_ERRNO(errno, EPERM);
13891.37Skamil
13901.37Skamil		CHILD_TO_PARENT("child2 exiting", parent_child, msg);
13911.37Skamil
13921.37Skamil		_exit(exitval_child2);
13931.37Skamil	}
13941.37Skamil	DPRINTF("Parent process PID=%d, child1's PID=%d\n", getpid(), child1);
13951.37Skamil
13961.37Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
13971.61Skre	TWAIT_REQUIRE_SUCCESS(
13981.61Skre	    wpid = TWAIT_GENERIC(child1, &status, WEXITED), child1);
13991.37Skamil
14001.37Skamil	validate_status_exited(status, exitval_child1);
14011.37Skamil
14021.37Skamil	DPRINTF("Notify that child1 is dead\n");
14031.37Skamil	PARENT_TO_CHILD("exit child1", parent_child, msg);
14041.37Skamil
14051.37Skamil	DPRINTF("Wait for exiting of child2\n");
14061.37Skamil	PARENT_FROM_CHILD("child2 exiting", parent_child, msg);
14071.37Skamil}
14081.37Skamil
14091.37Skamil/// ----------------------------------------------------------------------------
14101.37Skamil
14111.40Skamilstatic void
14121.40Skamiltraceme_vfork_raise(int sigval)
14131.40Skamil{
14141.46Skamil	const int exitval = 5, exitval_watcher = 10;
14151.46Skamil	pid_t child, parent, watcher, wpid;
14161.46Skamil	int rv;
14171.40Skamil#if defined(TWAIT_HAVE_STATUS)
14181.40Skamil	int status;
14191.85Skamil
14201.85Skamil	/* volatile workarounds GCC -Werror=clobbered */
14211.85Skamil	volatile int expect_core;
14221.85Skamil
14231.85Skamil	switch (sigval) {
14241.85Skamil	case SIGABRT:
14251.85Skamil	case SIGTRAP:
14261.85Skamil	case SIGBUS:
14271.85Skamil	case SIGILL:
14281.85Skamil	case SIGFPE:
14291.85Skamil	case SIGSEGV:
14301.85Skamil		expect_core = 1;
14311.85Skamil		break;
14321.85Skamil	default:
14331.85Skamil		expect_core = 0;
14341.85Skamil		break;
14351.85Skamil	}
14361.40Skamil#endif
14371.40Skamil
14381.46Skamil	/*
14391.46Skamil	 * Spawn a dedicated thread to watch for a stopped child and emit
14401.46Skamil	 * the SIGKILL signal to it.
14411.46Skamil	 *
14421.46Skamil	 * vfork(2) might clobber watcher, this means that it's safer and
14431.46Skamil	 * simpler to reparent this process to initproc and forget about it.
14441.46Skamil	 */
14451.46Skamil	if (sigval == SIGSTOP) {
14461.46Skamil		parent = getpid();
14471.46Skamil
14481.46Skamil		watcher = fork();
14491.46Skamil		ATF_REQUIRE(watcher != 1);
14501.46Skamil		if (watcher == 0) {
14511.46Skamil			/* Double fork(2) trick to reparent to initproc */
14521.46Skamil			watcher = fork();
14531.46Skamil			FORKEE_ASSERT_NEQ(watcher, -1);
14541.46Skamil			if (watcher != 0)
14551.46Skamil				_exit(exitval_watcher);
14561.46Skamil
14571.46Skamil			child = await_stopped_child(parent);
14581.46Skamil
14591.46Skamil			errno = 0;
14601.46Skamil			rv = kill(child, SIGKILL);
14611.46Skamil			FORKEE_ASSERT_EQ(rv, 0);
14621.46Skamil			FORKEE_ASSERT_EQ(errno, 0);
14631.46Skamil
14641.46Skamil			/* This exit value will be collected by initproc */
14651.46Skamil			_exit(0);
14661.46Skamil		}
14671.46Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14681.46Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(watcher, &status, 0),
14691.61Skre		    watcher);
14701.46Skamil
14711.46Skamil		validate_status_exited(status, exitval_watcher);
14721.46Skamil
14731.46Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14741.61Skre		TWAIT_REQUIRE_FAILURE(ECHILD,
14751.61Skre		    wpid = TWAIT_GENERIC(watcher, &status, 0));
14761.46Skamil	}
14771.46Skamil
14781.40Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
14791.40Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
14801.40Skamil	if (child == 0) {
14811.40Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
14821.40Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
14831.40Skamil
14841.40Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
14851.40Skamil		FORKEE_ASSERT(raise(sigval) == 0);
14861.40Skamil
14871.40Skamil		switch (sigval) {
14881.46Skamil		case SIGSTOP:
14891.40Skamil		case SIGKILL:
14901.40Skamil		case SIGABRT:
14911.40Skamil		case SIGHUP:
14921.85Skamil		case SIGTRAP:
14931.85Skamil		case SIGBUS:
14941.85Skamil		case SIGILL:
14951.85Skamil		case SIGFPE:
14961.85Skamil		case SIGSEGV:
14971.40Skamil			/* NOTREACHED */
14981.40Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
14991.70Smrg			__unreachable();
15001.40Skamil		default:
15011.40Skamil			DPRINTF("Before exiting of the child process\n");
15021.40Skamil			_exit(exitval);
15031.40Skamil		}
15041.40Skamil	}
15051.40Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
15061.40Skamil
15071.40Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15081.40Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
15091.40Skamil
15101.40Skamil	switch (sigval) {
15111.40Skamil	case SIGKILL:
15121.40Skamil	case SIGABRT:
15131.40Skamil	case SIGHUP:
15141.85Skamil	case SIGTRAP:
15151.85Skamil	case SIGBUS:
15161.85Skamil	case SIGILL:
15171.85Skamil	case SIGFPE:
15181.85Skamil	case SIGSEGV:
15191.40Skamil		validate_status_signaled(status, sigval, expect_core);
15201.40Skamil		break;
15211.40Skamil	case SIGSTOP:
15221.46Skamil		validate_status_signaled(status, SIGKILL, 0);
15231.46Skamil		break;
15241.40Skamil	case SIGCONT:
15251.47Skamil	case SIGTSTP:
15261.47Skamil	case SIGTTIN:
15271.47Skamil	case SIGTTOU:
15281.40Skamil		validate_status_exited(status, exitval);
15291.40Skamil		break;
15301.40Skamil	default:
15311.40Skamil		/* NOTREACHED */
15321.40Skamil		ATF_REQUIRE(0 && "NOT IMPLEMENTED");
15331.40Skamil		break;
15341.40Skamil	}
15351.40Skamil
15361.40Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15371.40Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
15381.40Skamil}
15391.40Skamil
15401.61Skre#define TRACEME_VFORK_RAISE(test, sig)					\
15411.61SkreATF_TC(test);								\
15421.61SkreATF_TC_HEAD(test, tc)							\
15431.61Skre{									\
15441.61Skre	atf_tc_set_md_var(tc, "descr",					\
15451.61Skre	    "Verify PT_TRACE_ME followed by raise of " #sig " in a "	\
15461.61Skre	    "vfork(2)ed child");					\
15471.61Skre}									\
15481.61Skre									\
15491.61SkreATF_TC_BODY(test, tc)							\
15501.61Skre{									\
15511.61Skre									\
15521.61Skre	traceme_vfork_raise(sig);					\
15531.40Skamil}
15541.40Skamil
15551.40SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise1, SIGKILL) /* non-maskable */
15561.46SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise2, SIGSTOP) /* non-maskable */
15571.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise3, SIGTSTP) /* ignored in vfork(2) */
15581.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise4, SIGTTIN) /* ignored in vfork(2) */
15591.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise5, SIGTTOU) /* ignored in vfork(2) */
15601.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise6, SIGABRT) /* regular abort trap */
15611.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise7, SIGHUP)  /* hangup */
15621.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise8, SIGCONT) /* continued? */
15631.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise9, SIGTRAP) /* crash signal */
15641.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise10, SIGBUS) /* crash signal */
15651.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise11, SIGILL) /* crash signal */
15661.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise12, SIGFPE) /* crash signal */
15671.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise13, SIGSEGV) /* crash signal */
15681.40Skamil
15691.40Skamil/// ----------------------------------------------------------------------------
15701.40Skamil
15711.52Skamilstatic void
15721.52Skamiltraceme_vfork_crash(int sig)
15731.41Skamil{
15741.41Skamil	pid_t child, wpid;
15751.41Skamil#if defined(TWAIT_HAVE_STATUS)
15761.41Skamil	int status;
15771.41Skamil#endif
15781.41Skamil
15791.71Skamil#ifndef PTRACE_ILLEGAL_ASM
15801.71Skamil	if (sig == SIGILL)
15811.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
15821.71Skamil#endif
15831.71Skamil
15841.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
15851.114Skamil		atf_tc_skip("FP exceptions are not supported");
15861.114Skamil
15871.41Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
15881.41Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
15891.41Skamil	if (child == 0) {
15901.41Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
15911.41Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
15921.41Skamil
15931.52Skamil		DPRINTF("Before executing a trap\n");
15941.52Skamil		switch (sig) {
15951.52Skamil		case SIGTRAP:
15961.52Skamil			trigger_trap();
15971.52Skamil			break;
15981.52Skamil		case SIGSEGV:
15991.52Skamil			trigger_segv();
16001.52Skamil			break;
16011.52Skamil		case SIGILL:
16021.52Skamil			trigger_ill();
16031.52Skamil			break;
16041.52Skamil		case SIGFPE:
16051.52Skamil			trigger_fpe();
16061.52Skamil			break;
16071.52Skamil		case SIGBUS:
16081.52Skamil			trigger_bus();
16091.52Skamil			break;
16101.52Skamil		default:
16111.52Skamil			/* NOTREACHED */
16121.52Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
16131.52Skamil		}
16141.41Skamil
16151.41Skamil		/* NOTREACHED */
16161.41Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
16171.41Skamil	}
16181.41Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
16191.41Skamil
16201.41Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16211.41Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
16221.41Skamil
16231.52Skamil	validate_status_signaled(status, sig, 1);
16241.41Skamil
16251.41Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16261.41Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
16271.41Skamil}
16281.41Skamil
16291.61Skre#define TRACEME_VFORK_CRASH(test, sig)					\
16301.61SkreATF_TC(test);								\
16311.61SkreATF_TC_HEAD(test, tc)							\
16321.61Skre{									\
16331.61Skre	atf_tc_set_md_var(tc, "descr",					\
16341.61Skre	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
16351.61Skre	    "vfork(2)ed child");					\
16361.61Skre}									\
16371.61Skre									\
16381.61SkreATF_TC_BODY(test, tc)							\
16391.61Skre{									\
16401.61Skre									\
16411.61Skre	traceme_vfork_crash(sig);					\
16421.52Skamil}
16431.52Skamil
16441.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_trap, SIGTRAP)
16451.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_segv, SIGSEGV)
16461.71SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_ill, SIGILL)
16471.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_fpe, SIGFPE)
16481.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_bus, SIGBUS)
16491.52Skamil
16501.41Skamil/// ----------------------------------------------------------------------------
16511.41Skamil
16521.92Skamilstatic void
16531.92Skamiltraceme_vfork_signalmasked_crash(int sig)
16541.92Skamil{
16551.92Skamil	pid_t child, wpid;
16561.92Skamil#if defined(TWAIT_HAVE_STATUS)
16571.92Skamil	int status;
16581.92Skamil#endif
16591.92Skamil	sigset_t intmask;
16601.92Skamil
16611.92Skamil#ifndef PTRACE_ILLEGAL_ASM
16621.92Skamil	if (sig == SIGILL)
16631.92Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
16641.92Skamil#endif
16651.92Skamil
16661.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
16671.114Skamil		atf_tc_skip("FP exceptions are not supported");
16681.114Skamil
16691.92Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
16701.92Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
16711.92Skamil	if (child == 0) {
16721.92Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
16731.92Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
16741.92Skamil
16751.92Skamil		sigemptyset(&intmask);
16761.92Skamil		sigaddset(&intmask, sig);
16771.92Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
16781.92Skamil
16791.92Skamil		DPRINTF("Before executing a trap\n");
16801.92Skamil		switch (sig) {
16811.92Skamil		case SIGTRAP:
16821.92Skamil			trigger_trap();
16831.92Skamil			break;
16841.92Skamil		case SIGSEGV:
16851.92Skamil			trigger_segv();
16861.92Skamil			break;
16871.92Skamil		case SIGILL:
16881.92Skamil			trigger_ill();
16891.92Skamil			break;
16901.92Skamil		case SIGFPE:
16911.92Skamil			trigger_fpe();
16921.92Skamil			break;
16931.92Skamil		case SIGBUS:
16941.92Skamil			trigger_bus();
16951.92Skamil			break;
16961.92Skamil		default:
16971.92Skamil			/* NOTREACHED */
16981.92Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
16991.92Skamil		}
17001.92Skamil
17011.92Skamil		/* NOTREACHED */
17021.92Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
17031.92Skamil	}
17041.92Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
17051.92Skamil
17061.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17071.92Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17081.92Skamil
17091.92Skamil	validate_status_signaled(status, sig, 1);
17101.92Skamil
17111.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17121.92Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
17131.92Skamil}
17141.92Skamil
17151.92Skamil#define TRACEME_VFORK_SIGNALMASKED_CRASH(test, sig)			\
17161.92SkamilATF_TC(test);								\
17171.92SkamilATF_TC_HEAD(test, tc)							\
17181.92Skamil{									\
17191.92Skamil	atf_tc_set_md_var(tc, "descr",					\
17201.92Skamil	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
17211.92Skamil	    "vfork(2)ed child with a masked signal");			\
17221.92Skamil}									\
17231.92Skamil									\
17241.92SkamilATF_TC_BODY(test, tc)							\
17251.92Skamil{									\
17261.92Skamil									\
17271.92Skamil	traceme_vfork_signalmasked_crash(sig);				\
17281.92Skamil}
17291.92Skamil
17301.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_trap, SIGTRAP)
17311.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_segv, SIGSEGV)
17321.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_ill, SIGILL)
17331.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_fpe, SIGFPE)
17341.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_bus, SIGBUS)
17351.92Skamil
17361.92Skamil/// ----------------------------------------------------------------------------
17371.92Skamil
17381.92Skamilstatic void
17391.92Skamiltraceme_vfork_signalignored_crash(int sig)
17401.92Skamil{
17411.92Skamil	pid_t child, wpid;
17421.92Skamil#if defined(TWAIT_HAVE_STATUS)
17431.92Skamil	int status;
17441.92Skamil#endif
17451.92Skamil	struct sigaction sa;
17461.92Skamil
17471.92Skamil#ifndef PTRACE_ILLEGAL_ASM
17481.92Skamil	if (sig == SIGILL)
17491.92Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
17501.92Skamil#endif
17511.92Skamil
17521.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
17531.114Skamil		atf_tc_skip("FP exceptions are not supported");
17541.114Skamil
17551.92Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
17561.92Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
17571.92Skamil	if (child == 0) {
17581.92Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
17591.92Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
17601.92Skamil
17611.92Skamil		memset(&sa, 0, sizeof(sa));
17621.92Skamil		sa.sa_handler = SIG_IGN;
17631.92Skamil		sigemptyset(&sa.sa_mask);
17641.92Skamil
17651.92Skamil		FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
17661.92Skamil
17671.92Skamil		DPRINTF("Before executing a trap\n");
17681.92Skamil		switch (sig) {
17691.92Skamil		case SIGTRAP:
17701.92Skamil			trigger_trap();
17711.92Skamil			break;
17721.92Skamil		case SIGSEGV:
17731.92Skamil			trigger_segv();
17741.92Skamil			break;
17751.92Skamil		case SIGILL:
17761.92Skamil			trigger_ill();
17771.92Skamil			break;
17781.92Skamil		case SIGFPE:
17791.92Skamil			trigger_fpe();
17801.92Skamil			break;
17811.92Skamil		case SIGBUS:
17821.92Skamil			trigger_bus();
17831.92Skamil			break;
17841.92Skamil		default:
17851.92Skamil			/* NOTREACHED */
17861.92Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
17871.92Skamil		}
17881.92Skamil
17891.92Skamil		/* NOTREACHED */
17901.92Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
17911.92Skamil	}
17921.92Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
17931.92Skamil
17941.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17951.92Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17961.92Skamil
17971.92Skamil	validate_status_signaled(status, sig, 1);
17981.92Skamil
17991.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18001.92Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
18011.92Skamil}
18021.92Skamil
18031.92Skamil#define TRACEME_VFORK_SIGNALIGNORED_CRASH(test, sig)			\
18041.92SkamilATF_TC(test);								\
18051.92SkamilATF_TC_HEAD(test, tc)							\
18061.92Skamil{									\
18071.92Skamil	atf_tc_set_md_var(tc, "descr",					\
18081.92Skamil	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
18091.92Skamil	    "vfork(2)ed child with ignored signal");			\
18101.92Skamil}									\
18111.92Skamil									\
18121.92SkamilATF_TC_BODY(test, tc)							\
18131.92Skamil{									\
18141.92Skamil									\
18151.92Skamil	traceme_vfork_signalignored_crash(sig);				\
18161.92Skamil}
18171.92Skamil
18181.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_trap,
18191.92Skamil    SIGTRAP)
18201.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_segv,
18211.92Skamil    SIGSEGV)
18221.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_ill,
18231.92Skamil    SIGILL)
18241.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_fpe,
18251.92Skamil    SIGFPE)
18261.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_bus,
18271.92Skamil    SIGBUS)
18281.92Skamil
18291.92Skamil/// ----------------------------------------------------------------------------
18301.92Skamil
18311.96Skamilstatic void
18321.96Skamiltraceme_vfork_exec(bool masked, bool ignored)
18331.43Skamil{
18341.43Skamil	const int sigval = SIGTRAP;
18351.43Skamil	pid_t child, wpid;
18361.43Skamil#if defined(TWAIT_HAVE_STATUS)
18371.43Skamil	int status;
18381.43Skamil#endif
18391.96Skamil	struct sigaction sa;
18401.61Skre	struct ptrace_siginfo info;
18411.96Skamil	sigset_t intmask;
18421.96Skamil	struct kinfo_proc2 kp;
18431.96Skamil	size_t len = sizeof(kp);
18441.96Skamil
18451.96Skamil	int name[6];
18461.96Skamil	const size_t namelen = __arraycount(name);
18471.96Skamil	ki_sigset_t kp_sigmask;
18481.96Skamil	ki_sigset_t kp_sigignore;
18491.43Skamil
18501.43Skamil	memset(&info, 0, sizeof(info));
18511.43Skamil
18521.43Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
18531.43Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
18541.43Skamil	if (child == 0) {
18551.43Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
18561.43Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
18571.43Skamil
18581.96Skamil		if (masked) {
18591.96Skamil			sigemptyset(&intmask);
18601.96Skamil			sigaddset(&intmask, sigval);
18611.96Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
18621.96Skamil		}
18631.96Skamil
18641.96Skamil		if (ignored) {
18651.96Skamil			memset(&sa, 0, sizeof(sa));
18661.96Skamil			sa.sa_handler = SIG_IGN;
18671.96Skamil			sigemptyset(&sa.sa_mask);
18681.96Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
18691.96Skamil		}
18701.96Skamil
18711.43Skamil		DPRINTF("Before calling execve(2) from child\n");
18721.43Skamil		execlp("/bin/echo", "/bin/echo", NULL);
18731.43Skamil
18741.43Skamil		/* NOTREACHED */
18751.43Skamil		FORKEE_ASSERTX(0 && "Not reached");
18761.43Skamil	}
18771.43Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
18781.43Skamil
18791.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18801.43Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
18811.43Skamil
18821.43Skamil	validate_status_stopped(status, sigval);
18831.43Skamil
18841.96Skamil	name[0] = CTL_KERN,
18851.96Skamil	name[1] = KERN_PROC2,
18861.96Skamil	name[2] = KERN_PROC_PID;
18871.96Skamil	name[3] = getpid();
18881.96Skamil	name[4] = sizeof(kp);
18891.96Skamil	name[5] = 1;
18901.96Skamil
18911.96Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
18921.96Skamil
18931.96Skamil	if (masked)
18941.96Skamil		kp_sigmask = kp.p_sigmask;
18951.96Skamil
18961.96Skamil	if (ignored)
18971.96Skamil		kp_sigignore = kp.p_sigignore;
18981.96Skamil
18991.96Skamil	name[3] = getpid();
19001.96Skamil
19011.96Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
19021.96Skamil
19031.96Skamil	if (masked) {
19041.96Skamil		DPRINTF("kp_sigmask="
19051.96Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19061.96Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
19071.96Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
19081.96Skamil
19091.96Skamil	        DPRINTF("kp.p_sigmask="
19101.96Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19111.96Skamil	            kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
19121.96Skamil	            kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
19131.96Skamil
19141.96Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
19151.96Skamil		    sizeof(kp_sigmask)));
19161.96Skamil	}
19171.96Skamil
19181.96Skamil	if (ignored) {
19191.96Skamil		DPRINTF("kp_sigignore="
19201.96Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19211.96Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
19221.96Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
19231.96Skamil
19241.96Skamil	        DPRINTF("kp.p_sigignore="
19251.96Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19261.96Skamil	            kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
19271.96Skamil	            kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
19281.96Skamil
19291.96Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
19301.96Skamil		    sizeof(kp_sigignore)));
19311.96Skamil	}
19321.96Skamil
19331.43Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
19341.61Skre	SYSCALL_REQUIRE(
19351.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
19361.43Skamil
19371.43Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
19381.43Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
19391.43Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
19401.43Skamil	    info.psi_siginfo.si_errno);
19411.43Skamil
19421.43Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
19431.43Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
19441.43Skamil
19451.43Skamil	DPRINTF("Before resuming the child process where it left off and "
19461.43Skamil	    "without signal to be sent\n");
19471.43Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
19481.43Skamil
19491.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
19501.43Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
19511.43Skamil
19521.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
19531.43Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
19541.43Skamil}
19551.43Skamil
19561.96Skamil#define TRACEME_VFORK_EXEC(test, masked, ignored)			\
19571.96SkamilATF_TC(test);								\
19581.96SkamilATF_TC_HEAD(test, tc)							\
19591.96Skamil{									\
19601.96Skamil	atf_tc_set_md_var(tc, "descr",					\
19611.96Skamil	    "Verify PT_TRACE_ME followed by exec(3) in a vfork(2)ed "	\
19621.96Skamil	    "child%s%s", masked ? " with masked signal" : "",		\
19631.96Skamil	    masked ? " with ignored signal" : "");			\
19641.96Skamil}									\
19651.96Skamil									\
19661.96SkamilATF_TC_BODY(test, tc)							\
19671.96Skamil{									\
19681.96Skamil									\
19691.96Skamil	traceme_vfork_exec(masked, ignored);				\
19701.96Skamil}
19711.96Skamil
19721.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_exec, false, false)
19731.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalmasked_exec, true, false)
19741.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalignored_exec, false, true)
19751.96Skamil
19761.43Skamil/// ----------------------------------------------------------------------------
19771.43Skamil
19781.1Skamil#if defined(TWAIT_HAVE_PID)
19791.51Skamilstatic void
19801.94Skamilunrelated_tracer_sees_crash(int sig, bool masked, bool ignored)
19811.59Skamil{
19821.94Skamil	const int sigval = SIGSTOP;
19831.59Skamil	struct msg_fds parent_tracee, parent_tracer;
19841.59Skamil	const int exitval = 10;
19851.59Skamil	pid_t tracee, tracer, wpid;
19861.59Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
19871.59Skamil#if defined(TWAIT_HAVE_STATUS)
19881.59Skamil	int status;
19891.59Skamil#endif
19901.94Skamil	struct sigaction sa;
19911.59Skamil	struct ptrace_siginfo info;
19921.94Skamil	sigset_t intmask;
19931.94Skamil	struct kinfo_proc2 kp;
19941.94Skamil	size_t len = sizeof(kp);
19951.94Skamil
19961.94Skamil	int name[6];
19971.94Skamil	const size_t namelen = __arraycount(name);
19981.94Skamil	ki_sigset_t kp_sigmask;
19991.94Skamil	ki_sigset_t kp_sigignore;
20001.61Skre
20011.71Skamil#ifndef PTRACE_ILLEGAL_ASM
20021.71Skamil	if (sig == SIGILL)
20031.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
20041.71Skamil#endif
20051.71Skamil
20061.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
20071.114Skamil		atf_tc_skip("FP exceptions are not supported");
20081.114Skamil
20091.59Skamil	memset(&info, 0, sizeof(info));
20101.59Skamil
20111.59Skamil	DPRINTF("Spawn tracee\n");
20121.59Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
20131.59Skamil	tracee = atf_utils_fork();
20141.59Skamil	if (tracee == 0) {
20151.59Skamil		// Wait for parent to let us crash
20161.59Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
20171.61Skre
20181.94Skamil		if (masked) {
20191.94Skamil			sigemptyset(&intmask);
20201.94Skamil			sigaddset(&intmask, sig);
20211.94Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
20221.94Skamil		}
20231.94Skamil
20241.94Skamil		if (ignored) {
20251.94Skamil			memset(&sa, 0, sizeof(sa));
20261.94Skamil			sa.sa_handler = SIG_IGN;
20271.94Skamil			sigemptyset(&sa.sa_mask);
20281.94Skamil			FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
20291.94Skamil		}
20301.94Skamil
20311.94Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
20321.94Skamil		FORKEE_ASSERT(raise(sigval) == 0);
20331.94Skamil
20341.59Skamil		DPRINTF("Before executing a trap\n");
20351.59Skamil		switch (sig) {
20361.59Skamil		case SIGTRAP:
20371.59Skamil			trigger_trap();
20381.59Skamil			break;
20391.59Skamil		case SIGSEGV:
20401.59Skamil			trigger_segv();
20411.59Skamil			break;
20421.59Skamil		case SIGILL:
20431.59Skamil			trigger_ill();
20441.59Skamil			break;
20451.59Skamil		case SIGFPE:
20461.59Skamil			trigger_fpe();
20471.59Skamil			break;
20481.59Skamil		case SIGBUS:
20491.59Skamil			trigger_bus();
20501.59Skamil			break;
20511.59Skamil		default:
20521.59Skamil			/* NOTREACHED */
20531.59Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
20541.59Skamil		}
20551.59Skamil
20561.59Skamil		/* NOTREACHED */
20571.59Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
20581.59Skamil	}
20591.59Skamil
20601.59Skamil	DPRINTF("Spawn debugger\n");
20611.59Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
20621.59Skamil	tracer = atf_utils_fork();
20631.59Skamil	if (tracer == 0) {
20641.59Skamil		/* Fork again and drop parent to reattach to PID 1 */
20651.59Skamil		tracer = atf_utils_fork();
20661.59Skamil		if (tracer != 0)
20671.61Skre			_exit(exitval);
20681.59Skamil
20691.59Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
20701.59Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
20711.59Skamil
20721.59Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
20731.59Skamil		FORKEE_REQUIRE_SUCCESS(
20741.59Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
20751.59Skamil
20761.59Skamil		forkee_status_stopped(status, SIGSTOP);
20771.59Skamil
20781.94Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
20791.94Skamil		    "traced process\n");
20801.94Skamil		SYSCALL_REQUIRE(
20811.94Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
20821.94Skamil
20831.94Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
20841.94Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
20851.94Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
20861.94Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
20871.94Skamil
20881.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
20891.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
20901.94Skamil
20911.59Skamil		/* Resume tracee with PT_CONTINUE */
20921.59Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
20931.59Skamil
20941.59Skamil		/* Inform parent that tracer has attached to tracee */
20951.59Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
20961.59Skamil
20971.59Skamil		/* Wait for parent to tell use that tracee should have exited */
20981.59Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
20991.59Skamil
21001.59Skamil		/* Wait for tracee and assert that it exited */
21011.59Skamil		FORKEE_REQUIRE_SUCCESS(
21021.59Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
21031.59Skamil
21041.94Skamil		forkee_status_stopped(status, sigval);
21051.94Skamil
21061.94Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
21071.94Skamil		    "traced process\n");
21081.94Skamil		SYSCALL_REQUIRE(
21091.94Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
21101.94Skamil
21111.94Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
21121.94Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
21131.94Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
21141.94Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
21151.94Skamil
21161.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
21171.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
21181.94Skamil
21191.94Skamil		name[0] = CTL_KERN,
21201.94Skamil		name[1] = KERN_PROC2,
21211.94Skamil		name[2] = KERN_PROC_PID;
21221.94Skamil		name[3] = tracee;
21231.94Skamil		name[4] = sizeof(kp);
21241.94Skamil		name[5] = 1;
21251.94Skamil
21261.94Skamil		FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
21271.94Skamil
21281.94Skamil		if (masked)
21291.94Skamil			kp_sigmask = kp.p_sigmask;
21301.94Skamil
21311.94Skamil		if (ignored)
21321.94Skamil			kp_sigignore = kp.p_sigignore;
21331.94Skamil
21341.94Skamil		/* Resume tracee with PT_CONTINUE */
21351.94Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
21361.94Skamil
21371.94Skamil		/* Wait for tracee and assert that it exited */
21381.94Skamil		FORKEE_REQUIRE_SUCCESS(
21391.94Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
21401.94Skamil
21411.93Skamil		forkee_status_stopped(status, sig);
21421.59Skamil
21431.59Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
21441.61Skre		    "traced process\n");
21451.61Skre		SYSCALL_REQUIRE(
21461.61Skre		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
21471.59Skamil
21481.59Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
21491.59Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
21501.61Skre		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
21511.61Skre		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
21521.59Skamil
21531.93Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sig);
21541.94Skamil
21551.94Skamil		FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
21561.94Skamil
21571.94Skamil		if (masked) {
21581.94Skamil			DPRINTF("kp_sigmask="
21591.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21601.94Skamil			    PRIx32 "\n",
21611.94Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
21621.94Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
21631.94Skamil
21641.94Skamil			DPRINTF("kp.p_sigmask="
21651.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21661.94Skamil			    PRIx32 "\n",
21671.94Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
21681.94Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
21691.94Skamil
21701.94Skamil			FORKEE_ASSERTX(!memcmp(&kp_sigmask, &kp.p_sigmask,
21711.94Skamil			    sizeof(kp_sigmask)));
21721.94Skamil		}
21731.94Skamil
21741.94Skamil		if (ignored) {
21751.94Skamil			DPRINTF("kp_sigignore="
21761.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21771.94Skamil			    PRIx32 "\n",
21781.94Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
21791.94Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
21801.94Skamil
21811.94Skamil			DPRINTF("kp.p_sigignore="
21821.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21831.94Skamil			    PRIx32 "\n",
21841.94Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
21851.94Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
21861.94Skamil
21871.94Skamil			FORKEE_ASSERTX(!memcmp(&kp_sigignore, &kp.p_sigignore,
21881.94Skamil			    sizeof(kp_sigignore)));
21891.94Skamil		}
21901.94Skamil
21911.59Skamil		switch (sig) {
21921.59Skamil		case SIGTRAP:
21931.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
21941.59Skamil			break;
21951.59Skamil		case SIGSEGV:
21961.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
21971.59Skamil			break;
21981.71Skamil		case SIGILL:
21991.113Skamil			FORKEE_ASSERT(info.psi_siginfo.si_code >= ILL_ILLOPC &&
22001.112Skamil			            info.psi_siginfo.si_code <= ILL_BADSTK);
22011.71Skamil			break;
22021.59Skamil		case SIGFPE:
22031.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
22041.59Skamil			break;
22051.59Skamil		case SIGBUS:
22061.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
22071.59Skamil			break;
22081.59Skamil		}
22091.59Skamil
22101.59Skamil		FORKEE_ASSERT(ptrace(PT_KILL, tracee, NULL, 0) != -1);
22111.59Skamil		DPRINTF("Before calling %s() for the tracee\n", TWAIT_FNAME);
22121.93Skamil		FORKEE_REQUIRE_SUCCESS(
22131.61Skre		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
22141.59Skamil
22151.93Skamil		forkee_status_signaled(status, SIGKILL, 0);
22161.59Skamil
22171.71Skamil		/* Inform parent that tracer is exiting normally */
22181.71Skamil		CHILD_TO_PARENT("tracer done", parent_tracer, msg);
22191.71Skamil
22201.59Skamil		DPRINTF("Before exiting of the tracer process\n");
22211.59Skamil		_exit(0 /* collect by initproc */);
22221.59Skamil	}
22231.59Skamil
22241.59Skamil	DPRINTF("Wait for the tracer process (direct child) to exit "
22251.59Skamil	    "calling %s()\n", TWAIT_FNAME);
22261.59Skamil	TWAIT_REQUIRE_SUCCESS(
22271.59Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
22281.59Skamil
22291.59Skamil	validate_status_exited(status, exitval);
22301.59Skamil
22311.59Skamil	DPRINTF("Wait for the non-exited tracee process with %s()\n",
22321.59Skamil	    TWAIT_FNAME);
22331.59Skamil	TWAIT_REQUIRE_SUCCESS(
22341.59Skamil	    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
22351.59Skamil
22361.59Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
22371.59Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
22381.59Skamil
22391.59Skamil	DPRINTF("Resume the tracee and let it crash\n");
22401.59Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
22411.59Skamil
22421.59Skamil	DPRINTF("Resume the tracer and let it detect crashed tracee\n");
22431.59Skamil	PARENT_TO_CHILD("Message 2", parent_tracer, msg);
22441.59Skamil
22451.59Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
22461.59Skamil	    TWAIT_FNAME);
22471.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
22481.59Skamil
22491.59Skamil	validate_status_signaled(status, SIGKILL, 0);
22501.59Skamil
22511.71Skamil	DPRINTF("Await normal exit of tracer\n");
22521.71Skamil	PARENT_FROM_CHILD("tracer done", parent_tracer, msg);
22531.71Skamil
22541.59Skamil	msg_close(&parent_tracer);
22551.59Skamil	msg_close(&parent_tracee);
22561.59Skamil}
22571.59Skamil
22581.61Skre#define UNRELATED_TRACER_SEES_CRASH(test, sig)				\
22591.61SkreATF_TC(test);								\
22601.61SkreATF_TC_HEAD(test, tc)							\
22611.61Skre{									\
22621.61Skre	atf_tc_set_md_var(tc, "descr",					\
22631.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
22641.94Skamil	    "the debuggee");						\
22651.61Skre}									\
22661.61Skre									\
22671.61SkreATF_TC_BODY(test, tc)							\
22681.61Skre{									\
22691.61Skre									\
22701.94Skamil	unrelated_tracer_sees_crash(sig, false, false);			\
22711.59Skamil}
22721.59Skamil
22731.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_trap, SIGTRAP)
22741.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_segv, SIGSEGV)
22751.71SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_ill, SIGILL)
22761.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_fpe, SIGFPE)
22771.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_bus, SIGBUS)
22781.94Skamil
22791.94Skamil#define UNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(test, sig)		\
22801.94SkamilATF_TC(test);								\
22811.94SkamilATF_TC_HEAD(test, tc)							\
22821.94Skamil{									\
22831.94Skamil	atf_tc_set_md_var(tc, "descr",					\
22841.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
22851.94Skamil	    "the debuggee with masked signal");				\
22861.94Skamil}									\
22871.94Skamil									\
22881.94SkamilATF_TC_BODY(test, tc)							\
22891.94Skamil{									\
22901.94Skamil									\
22911.94Skamil	unrelated_tracer_sees_crash(sig, true, false);			\
22921.94Skamil}
22931.94Skamil
22941.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22951.94Skamil    unrelated_tracer_sees_signalmasked_crash_trap, SIGTRAP)
22961.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22971.94Skamil    unrelated_tracer_sees_signalmasked_crash_segv, SIGSEGV)
22981.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22991.94Skamil    unrelated_tracer_sees_signalmasked_crash_ill, SIGILL)
23001.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
23011.94Skamil    unrelated_tracer_sees_signalmasked_crash_fpe, SIGFPE)
23021.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
23031.94Skamil    unrelated_tracer_sees_signalmasked_crash_bus, SIGBUS)
23041.94Skamil
23051.94Skamil#define UNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(test, sig)		\
23061.94SkamilATF_TC(test);								\
23071.94SkamilATF_TC_HEAD(test, tc)							\
23081.94Skamil{									\
23091.94Skamil	atf_tc_set_md_var(tc, "descr",					\
23101.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
23111.94Skamil	    "the debuggee with signal ignored");			\
23121.94Skamil}									\
23131.94Skamil									\
23141.94SkamilATF_TC_BODY(test, tc)							\
23151.94Skamil{									\
23161.94Skamil									\
23171.94Skamil	unrelated_tracer_sees_crash(sig, false, true);			\
23181.94Skamil}
23191.94Skamil
23201.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23211.94Skamil    unrelated_tracer_sees_signalignored_crash_trap, SIGTRAP)
23221.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23231.94Skamil    unrelated_tracer_sees_signalignored_crash_segv, SIGSEGV)
23241.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23251.94Skamil    unrelated_tracer_sees_signalignored_crash_ill, SIGILL)
23261.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23271.94Skamil    unrelated_tracer_sees_signalignored_crash_fpe, SIGFPE)
23281.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23291.94Skamil    unrelated_tracer_sees_signalignored_crash_bus, SIGBUS)
23301.59Skamil#endif
23311.59Skamil
23321.59Skamil/// ----------------------------------------------------------------------------
23331.59Skamil
23341.59Skamil#if defined(TWAIT_HAVE_PID)
23351.59Skamilstatic void
23361.67Skamiltracer_sees_terminaton_before_the_parent_raw(bool notimeout, bool unrelated,
23371.67Skamil                                             bool stopped)
23381.1Skamil{
23391.51Skamil	/*
23401.51Skamil	 * notimeout - disable timeout in await zombie function
23411.51Skamil	 * unrelated - attach from unrelated tracer reparented to initproc
23421.67Skamil	 * stopped - attach to a stopped process
23431.51Skamil	 */
23441.1Skamil
23451.1Skamil	struct msg_fds parent_tracee, parent_tracer;
23461.1Skamil	const int exitval_tracee = 5;
23471.1Skamil	const int exitval_tracer = 10;
23481.1Skamil	pid_t tracee, tracer, wpid;
23491.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
23501.1Skamil#if defined(TWAIT_HAVE_STATUS)
23511.1Skamil	int status;
23521.1Skamil#endif
23531.1Skamil
23541.67Skamil	/*
23551.67Skamil	 * Only a subset of options are supported.
23561.67Skamil	 */
23571.67Skamil	ATF_REQUIRE((!notimeout && !unrelated && !stopped) ||
23581.67Skamil	            (!notimeout && unrelated && !stopped) ||
23591.67Skamil	            (notimeout && !unrelated && !stopped) ||
23601.67Skamil	            (!notimeout && unrelated && stopped));
23611.67Skamil
23621.13Schristos	DPRINTF("Spawn tracee\n");
23631.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
23641.1Skamil	tracee = atf_utils_fork();
23651.1Skamil	if (tracee == 0) {
23661.67Skamil		if (stopped) {
23671.67Skamil			DPRINTF("Stop self PID %d\n", getpid());
23681.67Skamil			raise(SIGSTOP);
23691.67Skamil		}
23701.67Skamil
23711.1Skamil		// Wait for parent to let us exit
23721.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
23731.1Skamil		_exit(exitval_tracee);
23741.1Skamil	}
23751.1Skamil
23761.13Schristos	DPRINTF("Spawn debugger\n");
23771.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
23781.1Skamil	tracer = atf_utils_fork();
23791.1Skamil	if (tracer == 0) {
23801.51Skamil		if(unrelated) {
23811.51Skamil			/* Fork again and drop parent to reattach to PID 1 */
23821.51Skamil			tracer = atf_utils_fork();
23831.51Skamil			if (tracer != 0)
23841.51Skamil				_exit(exitval_tracer);
23851.51Skamil		}
23861.51Skamil
23871.67Skamil		if (stopped) {
23881.67Skamil			DPRINTF("Await for a stopped parent PID %d\n", tracee);
23891.67Skamil			await_stopped(tracee);
23901.67Skamil		}
23911.67Skamil
23921.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
23931.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
23941.1Skamil
23951.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
23961.1Skamil		FORKEE_REQUIRE_SUCCESS(
23971.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
23981.1Skamil
23991.1Skamil		forkee_status_stopped(status, SIGSTOP);
24001.1Skamil
24011.1Skamil		/* Resume tracee with PT_CONTINUE */
24021.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
24031.1Skamil
24041.1Skamil		/* Inform parent that tracer has attached to tracee */
24051.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
24061.1Skamil
24071.1Skamil		/* Wait for parent to tell use that tracee should have exited */
24081.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
24091.1Skamil
24101.1Skamil		/* Wait for tracee and assert that it exited */
24111.1Skamil		FORKEE_REQUIRE_SUCCESS(
24121.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
24131.1Skamil
24141.1Skamil		forkee_status_exited(status, exitval_tracee);
24151.13Schristos		DPRINTF("Tracee %d exited with %d\n", tracee, exitval_tracee);
24161.1Skamil
24171.13Schristos		DPRINTF("Before exiting of the tracer process\n");
24181.51Skamil		_exit(unrelated ? 0 /* collect by initproc */ : exitval_tracer);
24191.51Skamil	}
24201.51Skamil
24211.51Skamil	if (unrelated) {
24221.51Skamil		DPRINTF("Wait for the tracer process (direct child) to exit "
24231.51Skamil		    "calling %s()\n", TWAIT_FNAME);
24241.51Skamil		TWAIT_REQUIRE_SUCCESS(
24251.51Skamil		    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
24261.51Skamil
24271.51Skamil		validate_status_exited(status, exitval_tracer);
24281.51Skamil
24291.51Skamil		DPRINTF("Wait for the non-exited tracee process with %s()\n",
24301.51Skamil		    TWAIT_FNAME);
24311.51Skamil		TWAIT_REQUIRE_SUCCESS(
24321.51Skamil		    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
24331.1Skamil	}
24341.1Skamil
24351.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
24361.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
24371.1Skamil
24381.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
24391.1Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
24401.1Skamil
24411.13Schristos	DPRINTF("Detect that tracee is zombie\n");
24421.51Skamil	if (notimeout)
24431.26Skamil		await_zombie_raw(tracee, 0);
24441.26Skamil	else
24451.26Skamil		await_zombie(tracee);
24461.1Skamil
24471.13Schristos	DPRINTF("Assert that there is no status about tracee %d - "
24481.1Skamil	    "Tracer must detect zombie first - calling %s()\n", tracee,
24491.1Skamil	    TWAIT_FNAME);
24501.1Skamil	TWAIT_REQUIRE_SUCCESS(
24511.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
24521.1Skamil
24531.51Skamil	if (unrelated) {
24541.51Skamil		DPRINTF("Resume the tracer and let it detect exited tracee\n");
24551.51Skamil		PARENT_TO_CHILD("Message 2", parent_tracer, msg);
24561.51Skamil	} else {
24571.51Skamil		DPRINTF("Tell the tracer child should have exited\n");
24581.51Skamil		PARENT_TO_CHILD("wait for tracee exit", parent_tracer,  msg);
24591.51Skamil		DPRINTF("Wait for tracer to finish its job and exit - calling "
24601.59Skamil			"%s()\n", TWAIT_FNAME);
24611.51Skamil
24621.51Skamil		DPRINTF("Wait from tracer child to complete waiting for "
24631.59Skamil			"tracee\n");
24641.51Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
24651.51Skamil		    tracer);
24661.1Skamil
24671.51Skamil		validate_status_exited(status, exitval_tracer);
24681.51Skamil	}
24691.1Skamil
24701.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
24711.1Skamil	    TWAIT_FNAME);
24721.51Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
24731.1Skamil
24741.1Skamil	validate_status_exited(status, exitval_tracee);
24751.1Skamil
24761.1Skamil	msg_close(&parent_tracer);
24771.1Skamil	msg_close(&parent_tracee);
24781.1Skamil}
24791.26Skamil
24801.51SkamilATF_TC(tracer_sees_terminaton_before_the_parent);
24811.51SkamilATF_TC_HEAD(tracer_sees_terminaton_before_the_parent, tc)
24821.51Skamil{
24831.51Skamil	atf_tc_set_md_var(tc, "descr",
24841.51Skamil	    "Assert that tracer sees process termination before the parent");
24851.51Skamil}
24861.51Skamil
24871.51SkamilATF_TC_BODY(tracer_sees_terminaton_before_the_parent, tc)
24881.26Skamil{
24891.26Skamil
24901.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, false, false);
24911.26Skamil}
24921.26Skamil
24931.51SkamilATF_TC(tracer_sysctl_lookup_without_duplicates);
24941.51SkamilATF_TC_HEAD(tracer_sysctl_lookup_without_duplicates, tc)
24951.1Skamil{
24961.1Skamil	atf_tc_set_md_var(tc, "descr",
24971.51Skamil	    "Assert that await_zombie() in attach1 always finds a single "
24981.51Skamil	    "process and no other error is reported");
24991.1Skamil}
25001.1Skamil
25011.51SkamilATF_TC_BODY(tracer_sysctl_lookup_without_duplicates, tc)
25021.1Skamil{
25031.51Skamil	time_t start, end;
25041.51Skamil	double diff;
25051.51Skamil	unsigned long N = 0;
25061.1Skamil
25071.51Skamil	/*
25081.51Skamil	 * Reuse this test with tracer_sees_terminaton_before_the_parent_raw().
25091.51Skamil	 * This test body isn't specific to this race, however it's just good
25101.51Skamil	 * enough for this purposes, no need to invent a dedicated code flow.
25111.51Skamil	 */
25121.1Skamil
25131.51Skamil	start = time(NULL);
25141.51Skamil	while (true) {
25151.51Skamil		DPRINTF("Step: %lu\n", N);
25161.67Skamil		tracer_sees_terminaton_before_the_parent_raw(true, false,
25171.67Skamil		                                             false);
25181.51Skamil		end = time(NULL);
25191.51Skamil		diff = difftime(end, start);
25201.51Skamil		if (diff >= 5.0)
25211.51Skamil			break;
25221.51Skamil		++N;
25231.1Skamil	}
25241.51Skamil	DPRINTF("Iterations: %lu\n", N);
25251.51Skamil}
25261.1Skamil
25271.51SkamilATF_TC(unrelated_tracer_sees_terminaton_before_the_parent);
25281.51SkamilATF_TC_HEAD(unrelated_tracer_sees_terminaton_before_the_parent, tc)
25291.51Skamil{
25301.51Skamil	atf_tc_set_md_var(tc, "descr",
25311.51Skamil	    "Assert that tracer sees process termination before the parent");
25321.51Skamil}
25331.1Skamil
25341.51SkamilATF_TC_BODY(unrelated_tracer_sees_terminaton_before_the_parent, tc)
25351.51Skamil{
25361.1Skamil
25371.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, false);
25381.67Skamil}
25391.67Skamil
25401.67SkamilATF_TC(tracer_attach_to_unrelated_stopped_process);
25411.67SkamilATF_TC_HEAD(tracer_attach_to_unrelated_stopped_process, tc)
25421.67Skamil{
25431.67Skamil	atf_tc_set_md_var(tc, "descr",
25441.67Skamil	    "Assert that tracer can attach to an unrelated stopped process");
25451.67Skamil}
25461.67Skamil
25471.67SkamilATF_TC_BODY(tracer_attach_to_unrelated_stopped_process, tc)
25481.67Skamil{
25491.67Skamil
25501.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, true);
25511.1Skamil}
25521.1Skamil#endif
25531.1Skamil
25541.51Skamil/// ----------------------------------------------------------------------------
25551.51Skamil
25561.66Skamilstatic void
25571.66Skamilparent_attach_to_its_child(bool stopped)
25581.1Skamil{
25591.1Skamil	struct msg_fds parent_tracee;
25601.1Skamil	const int exitval_tracee = 5;
25611.1Skamil	pid_t tracee, wpid;
25621.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
25631.1Skamil#if defined(TWAIT_HAVE_STATUS)
25641.1Skamil	int status;
25651.1Skamil#endif
25661.1Skamil
25671.13Schristos	DPRINTF("Spawn tracee\n");
25681.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
25691.1Skamil	tracee = atf_utils_fork();
25701.1Skamil	if (tracee == 0) {
25711.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
25721.13Schristos		DPRINTF("Parent should now attach to tracee\n");
25731.1Skamil
25741.66Skamil		if (stopped) {
25751.66Skamil			DPRINTF("Stop self PID %d\n", getpid());
25761.66Skamil			SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
25771.66Skamil		}
25781.66Skamil
25791.1Skamil		CHILD_FROM_PARENT("Message 2", parent_tracee, msg);
25801.1Skamil		/* Wait for message from the parent */
25811.1Skamil		_exit(exitval_tracee);
25821.1Skamil	}
25831.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
25841.57Skamil
25851.66Skamil	if (stopped) {
25861.66Skamil		DPRINTF("Await for a stopped tracee PID %d\n", tracee);
25871.66Skamil		await_stopped(tracee);
25881.66Skamil	}
25891.66Skamil
25901.13Schristos	DPRINTF("Before calling PT_ATTACH for tracee %d\n", tracee);
25911.13Schristos	SYSCALL_REQUIRE(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
25921.1Skamil
25931.13Schristos	DPRINTF("Wait for the stopped tracee process with %s()\n",
25941.1Skamil	    TWAIT_FNAME);
25951.1Skamil	TWAIT_REQUIRE_SUCCESS(
25961.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
25971.1Skamil
25981.1Skamil	validate_status_stopped(status, SIGSTOP);
25991.1Skamil
26001.13Schristos	DPRINTF("Resume tracee with PT_CONTINUE\n");
26011.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
26021.1Skamil
26031.13Schristos	DPRINTF("Let the tracee exit now\n");
26041.1Skamil	PARENT_TO_CHILD("Message 2", parent_tracee, msg);
26051.1Skamil
26061.13Schristos	DPRINTF("Wait for tracee to exit with %s()\n", TWAIT_FNAME);
26071.1Skamil	TWAIT_REQUIRE_SUCCESS(
26081.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
26091.1Skamil
26101.1Skamil	validate_status_exited(status, exitval_tracee);
26111.1Skamil
26121.13Schristos	DPRINTF("Before calling %s() for tracee\n", TWAIT_FNAME);
26131.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
26141.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0));
26151.1Skamil
26161.1Skamil	msg_close(&parent_tracee);
26171.1Skamil}
26181.1Skamil
26191.66SkamilATF_TC(parent_attach_to_its_child);
26201.66SkamilATF_TC_HEAD(parent_attach_to_its_child, tc)
26211.66Skamil{
26221.66Skamil	atf_tc_set_md_var(tc, "descr",
26231.66Skamil	    "Assert that tracer parent can PT_ATTACH to its child");
26241.66Skamil}
26251.66Skamil
26261.66SkamilATF_TC_BODY(parent_attach_to_its_child, tc)
26271.66Skamil{
26281.66Skamil
26291.66Skamil	parent_attach_to_its_child(false);
26301.66Skamil}
26311.66Skamil
26321.66SkamilATF_TC(parent_attach_to_its_stopped_child);
26331.66SkamilATF_TC_HEAD(parent_attach_to_its_stopped_child, tc)
26341.66Skamil{
26351.66Skamil	atf_tc_set_md_var(tc, "descr",
26361.66Skamil	    "Assert that tracer parent can PT_ATTACH to its stopped child");
26371.66Skamil}
26381.66Skamil
26391.66SkamilATF_TC_BODY(parent_attach_to_its_stopped_child, tc)
26401.66Skamil{
26411.66Skamil
26421.66Skamil	parent_attach_to_its_child(true);
26431.66Skamil}
26441.66Skamil
26451.51Skamil/// ----------------------------------------------------------------------------
26461.51Skamil
26471.65Skamilstatic void
26481.65Skamilchild_attach_to_its_parent(bool stopped)
26491.1Skamil{
26501.1Skamil	struct msg_fds parent_tracee;
26511.1Skamil	const int exitval_tracer = 5;
26521.1Skamil	pid_t tracer, wpid;
26531.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
26541.1Skamil#if defined(TWAIT_HAVE_STATUS)
26551.1Skamil	int status;
26561.1Skamil#endif
26571.1Skamil
26581.13Schristos	DPRINTF("Spawn tracer\n");
26591.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
26601.1Skamil	tracer = atf_utils_fork();
26611.1Skamil	if (tracer == 0) {
26621.1Skamil		/* Wait for message from the parent */
26631.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
26641.1Skamil
26651.65Skamil		if (stopped) {
26661.65Skamil			DPRINTF("Await for a stopped parent PID %d\n",
26671.65Skamil			        getppid());
26681.65Skamil			await_stopped(getppid());
26691.65Skamil		}
26701.65Skamil
26711.13Schristos		DPRINTF("Attach to parent PID %d with PT_ATTACH from child\n",
26721.1Skamil		    getppid());
26731.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, getppid(), NULL, 0) != -1);
26741.1Skamil
26751.13Schristos		DPRINTF("Wait for the stopped parent process with %s()\n",
26761.1Skamil		    TWAIT_FNAME);
26771.1Skamil		FORKEE_REQUIRE_SUCCESS(
26781.1Skamil		    wpid = TWAIT_GENERIC(getppid(), &status, 0), getppid());
26791.1Skamil
26801.1Skamil		forkee_status_stopped(status, SIGSTOP);
26811.1Skamil
26821.13Schristos		DPRINTF("Resume parent with PT_DETACH\n");
26831.1Skamil		FORKEE_ASSERT(ptrace(PT_DETACH, getppid(), (void *)1, 0)
26841.1Skamil		    != -1);
26851.1Skamil
26861.1Skamil		/* Tell parent we are ready */
26871.1Skamil		CHILD_TO_PARENT("Message 1", parent_tracee, msg);
26881.1Skamil
26891.1Skamil		_exit(exitval_tracer);
26901.1Skamil	}
26911.1Skamil
26921.13Schristos	DPRINTF("Wait for the tracer to become ready\n");
26931.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
26941.65Skamil
26951.65Skamil	if (stopped) {
26961.65Skamil		DPRINTF("Stop self PID %d\n", getpid());
26971.65Skamil		SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
26981.65Skamil	}
26991.65Skamil
27001.13Schristos	DPRINTF("Allow the tracer to exit now\n");
27011.1Skamil	PARENT_FROM_CHILD("Message 1", parent_tracee, msg);
27021.1Skamil
27031.13Schristos	DPRINTF("Wait for tracer to exit with %s()\n", TWAIT_FNAME);
27041.1Skamil	TWAIT_REQUIRE_SUCCESS(
27051.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
27061.1Skamil
27071.1Skamil	validate_status_exited(status, exitval_tracer);
27081.1Skamil
27091.13Schristos	DPRINTF("Before calling %s() for tracer\n", TWAIT_FNAME);
27101.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
27111.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0));
27121.1Skamil
27131.1Skamil	msg_close(&parent_tracee);
27141.1Skamil}
27151.1Skamil
27161.65SkamilATF_TC(child_attach_to_its_parent);
27171.65SkamilATF_TC_HEAD(child_attach_to_its_parent, tc)
27181.65Skamil{
27191.65Skamil	atf_tc_set_md_var(tc, "descr",
27201.65Skamil	    "Assert that tracer child can PT_ATTACH to its parent");
27211.65Skamil}
27221.65Skamil
27231.65SkamilATF_TC_BODY(child_attach_to_its_parent, tc)
27241.65Skamil{
27251.65Skamil
27261.65Skamil	child_attach_to_its_parent(false);
27271.65Skamil}
27281.65Skamil
27291.65SkamilATF_TC(child_attach_to_its_stopped_parent);
27301.65SkamilATF_TC_HEAD(child_attach_to_its_stopped_parent, tc)
27311.65Skamil{
27321.65Skamil	atf_tc_set_md_var(tc, "descr",
27331.65Skamil	    "Assert that tracer child can PT_ATTACH to its stopped parent");
27341.65Skamil}
27351.65Skamil
27361.65SkamilATF_TC_BODY(child_attach_to_its_stopped_parent, tc)
27371.65Skamil{
27381.65Skamil	/*
27391.65Skamil	 * The ATF framework (atf-run) does not tolerate raise(SIGSTOP), as
27401.65Skamil	 * this causes a pipe (established from atf-run) to be broken.
27411.65Skamil	 * atf-run uses this mechanism to monitor whether a test is alive.
27421.65Skamil	 *
27431.65Skamil	 * As a workaround spawn this test as a subprocess.
27441.65Skamil	 */
27451.65Skamil
27461.65Skamil	const int exitval = 15;
27471.65Skamil	pid_t child, wpid;
27481.65Skamil#if defined(TWAIT_HAVE_STATUS)
27491.65Skamil	int status;
27501.65Skamil#endif
27511.65Skamil
27521.65Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
27531.65Skamil	if (child == 0) {
27541.65Skamil		child_attach_to_its_parent(true);
27551.65Skamil		_exit(exitval);
27561.65Skamil	} else {
27571.65Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
27581.65Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
27591.65Skamil
27601.65Skamil		validate_status_exited(status, exitval);
27611.65Skamil
27621.65Skamil		DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
27631.65Skamil		TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
27641.65Skamil	}
27651.65Skamil}
27661.65Skamil
27671.51Skamil/// ----------------------------------------------------------------------------
27681.51Skamil
27691.1Skamil#if defined(TWAIT_HAVE_PID)
27701.1Skamil
27711.51Skamilenum tracee_sees_its_original_parent_type {
27721.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
27731.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
27741.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS
27751.51Skamil};
27761.51Skamil
27771.51Skamilstatic void
27781.51Skamiltracee_sees_its_original_parent(enum tracee_sees_its_original_parent_type type)
27791.1Skamil{
27801.1Skamil	struct msg_fds parent_tracer, parent_tracee;
27811.1Skamil	const int exitval_tracee = 5;
27821.1Skamil	const int exitval_tracer = 10;
27831.1Skamil	pid_t parent, tracee, tracer, wpid;
27841.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
27851.1Skamil#if defined(TWAIT_HAVE_STATUS)
27861.1Skamil	int status;
27871.1Skamil#endif
27881.51Skamil	/* sysctl(3) - kinfo_proc2 */
27891.51Skamil	int name[CTL_MAXNAME];
27901.51Skamil	struct kinfo_proc2 kp;
27911.51Skamil	size_t len = sizeof(kp);
27921.51Skamil	unsigned int namelen;
27931.51Skamil
27941.51Skamil	/* procfs - status  */
27951.51Skamil	FILE *fp;
27961.51Skamil	struct stat st;
27971.51Skamil	const char *fname = "/proc/curproc/status";
27981.51Skamil	char s_executable[MAXPATHLEN];
27991.51Skamil	int s_pid, s_ppid;
28001.51Skamil	int rv;
28011.51Skamil
28021.51Skamil	if (type == TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS) {
28031.61Skre		SYSCALL_REQUIRE(
28041.61Skre		    (rv = stat(fname, &st)) == 0 || (errno == ENOENT));
28051.61Skre		if (rv != 0)
28061.51Skamil			atf_tc_skip("/proc/curproc/status not found");
28071.51Skamil	}
28081.1Skamil
28091.13Schristos	DPRINTF("Spawn tracee\n");
28101.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
28111.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
28121.1Skamil	tracee = atf_utils_fork();
28131.1Skamil	if (tracee == 0) {
28141.1Skamil		parent = getppid();
28151.1Skamil
28161.1Skamil		/* Emit message to the parent */
28171.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
28181.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
28191.1Skamil
28201.51Skamil		switch (type) {
28211.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID:
28221.51Skamil			FORKEE_ASSERT_EQ(parent, getppid());
28231.51Skamil			break;
28241.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2:
28251.51Skamil			namelen = 0;
28261.51Skamil			name[namelen++] = CTL_KERN;
28271.51Skamil			name[namelen++] = KERN_PROC2;
28281.51Skamil			name[namelen++] = KERN_PROC_PID;
28291.51Skamil			name[namelen++] = getpid();
28301.51Skamil			name[namelen++] = len;
28311.51Skamil			name[namelen++] = 1;
28321.51Skamil
28331.61Skre			FORKEE_ASSERT_EQ(
28341.61Skre			    sysctl(name, namelen, &kp, &len, NULL, 0), 0);
28351.51Skamil			FORKEE_ASSERT_EQ(parent, kp.p_ppid);
28361.51Skamil			break;
28371.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS:
28381.51Skamil			/*
28391.51Skamil			 * Format:
28401.51Skamil			 *  EXECUTABLE PID PPID ...
28411.51Skamil			 */
28421.51Skamil			FORKEE_ASSERT((fp = fopen(fname, "r")) != NULL);
28431.51Skamil			fscanf(fp, "%s %d %d", s_executable, &s_pid, &s_ppid);
28441.51Skamil			FORKEE_ASSERT_EQ(fclose(fp), 0);
28451.51Skamil			FORKEE_ASSERT_EQ(parent, s_ppid);
28461.51Skamil			break;
28471.51Skamil		}
28481.1Skamil
28491.1Skamil		_exit(exitval_tracee);
28501.1Skamil	}
28511.13Schristos	DPRINTF("Wait for child to record its parent identifier (pid)\n");
28521.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
28531.1Skamil
28541.13Schristos	DPRINTF("Spawn debugger\n");
28551.1Skamil	tracer = atf_utils_fork();
28561.1Skamil	if (tracer == 0) {
28571.1Skamil		/* No IPC to communicate with the child */
28581.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
28591.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
28601.1Skamil
28611.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
28621.1Skamil		FORKEE_REQUIRE_SUCCESS(
28631.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
28641.1Skamil
28651.1Skamil		forkee_status_stopped(status, SIGSTOP);
28661.1Skamil
28671.1Skamil		/* Resume tracee with PT_CONTINUE */
28681.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
28691.1Skamil
28701.1Skamil		/* Inform parent that tracer has attached to tracee */
28711.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
28721.1Skamil
28731.1Skamil		/* Wait for parent to tell use that tracee should have exited */
28741.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
28751.1Skamil
28761.1Skamil		/* Wait for tracee and assert that it exited */
28771.1Skamil		FORKEE_REQUIRE_SUCCESS(
28781.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
28791.1Skamil
28801.1Skamil		forkee_status_exited(status, exitval_tracee);
28811.1Skamil
28821.13Schristos		DPRINTF("Before exiting of the tracer process\n");
28831.1Skamil		_exit(exitval_tracer);
28841.1Skamil	}
28851.1Skamil
28861.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
28871.1Skamil	PARENT_FROM_CHILD("tracer ready",  parent_tracer, msg);
28881.1Skamil
28891.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
28901.1Skamil	PARENT_TO_CHILD("exit tracee",  parent_tracee, msg);
28911.1Skamil
28921.13Schristos	DPRINTF("Detect that tracee is zombie\n");
28931.1Skamil	await_zombie(tracee);
28941.1Skamil
28951.13Schristos	DPRINTF("Assert that there is no status about tracee - "
28961.1Skamil	    "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
28971.1Skamil	TWAIT_REQUIRE_SUCCESS(
28981.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
28991.1Skamil
29001.13Schristos	DPRINTF("Tell the tracer child should have exited\n");
29011.1Skamil	PARENT_TO_CHILD("wait for tracee exit",  parent_tracer, msg);
29021.1Skamil
29031.13Schristos	DPRINTF("Wait from tracer child to complete waiting for tracee\n");
29041.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
29051.1Skamil	    tracer);
29061.1Skamil
29071.1Skamil	validate_status_exited(status, exitval_tracer);
29081.1Skamil
29091.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
29101.1Skamil	    TWAIT_FNAME);
29111.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
29121.1Skamil	    tracee);
29131.1Skamil
29141.1Skamil	validate_status_exited(status, exitval_tracee);
29151.1Skamil
29161.1Skamil	msg_close(&parent_tracer);
29171.1Skamil	msg_close(&parent_tracee);
29181.1Skamil}
29191.1Skamil
29201.61Skre#define TRACEE_SEES_ITS_ORIGINAL_PARENT(test, type, descr)		\
29211.61SkreATF_TC(test);								\
29221.61SkreATF_TC_HEAD(test, tc)							\
29231.61Skre{									\
29241.61Skre	atf_tc_set_md_var(tc, "descr",					\
29251.61Skre	    "Assert that tracee sees its original parent when being traced " \
29261.61Skre	    "(check " descr ")");					\
29271.61Skre}									\
29281.61Skre									\
29291.61SkreATF_TC_BODY(test, tc)							\
29301.61Skre{									\
29311.61Skre									\
29321.61Skre	tracee_sees_its_original_parent(type);				\
29331.1Skamil}
29341.1Skamil
29351.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29361.51Skamil	tracee_sees_its_original_parent_getppid,
29371.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
29381.51Skamil	"getppid(2)");
29391.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29401.51Skamil	tracee_sees_its_original_parent_sysctl_kinfo_proc2,
29411.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
29421.51Skamil	"sysctl(3) and kinfo_proc2");
29431.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29441.51Skamil	tracee_sees_its_original_parent_procfs_status,
29451.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS,
29461.51Skamil	"the status file in procfs");
29471.1Skamil#endif
29481.1Skamil
29491.51Skamil/// ----------------------------------------------------------------------------
29501.1Skamil
29511.53Skamilstatic void
29521.53Skamileventmask_preserved(int event)
29531.1Skamil{
29541.1Skamil	const int exitval = 5;
29551.1Skamil	const int sigval = SIGSTOP;
29561.1Skamil	pid_t child, wpid;
29571.1Skamil#if defined(TWAIT_HAVE_STATUS)
29581.1Skamil	int status;
29591.1Skamil#endif
29601.1Skamil	ptrace_event_t set_event, get_event;
29611.1Skamil	const int len = sizeof(ptrace_event_t);
29621.1Skamil
29631.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
29641.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
29651.1Skamil	if (child == 0) {
29661.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
29671.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
29681.1Skamil
29691.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
29701.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
29711.1Skamil
29721.13Schristos		DPRINTF("Before exiting of the child process\n");
29731.1Skamil		_exit(exitval);
29741.1Skamil	}
29751.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
29761.1Skamil
29771.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29781.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
29791.1Skamil
29801.1Skamil	validate_status_stopped(status, sigval);
29811.1Skamil
29821.53Skamil	set_event.pe_set_event = event;
29831.61Skre	SYSCALL_REQUIRE(
29841.61Skre	    ptrace(PT_SET_EVENT_MASK, child, &set_event, len) != -1);
29851.61Skre	SYSCALL_REQUIRE(
29861.61Skre	    ptrace(PT_GET_EVENT_MASK, child, &get_event, len) != -1);
29871.125Skamil	DPRINTF("set_event=%#x get_event=%#x\n", set_event.pe_set_event,
29881.125Skamil	    get_event.pe_set_event);
29891.1Skamil	ATF_REQUIRE(memcmp(&set_event, &get_event, len) == 0);
29901.1Skamil
29911.13Schristos	DPRINTF("Before resuming the child process where it left off and "
29921.1Skamil	    "without signal to be sent\n");
29931.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
29941.1Skamil
29951.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29961.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
29971.1Skamil
29981.1Skamil	validate_status_exited(status, exitval);
29991.1Skamil
30001.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
30011.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
30021.1Skamil}
30031.1Skamil
30041.61Skre#define EVENTMASK_PRESERVED(test, event)				\
30051.61SkreATF_TC(test);								\
30061.61SkreATF_TC_HEAD(test, tc)							\
30071.61Skre{									\
30081.61Skre	atf_tc_set_md_var(tc, "descr",					\
30091.61Skre	    "Verify that eventmask " #event " is preserved");		\
30101.61Skre}									\
30111.61Skre									\
30121.61SkreATF_TC_BODY(test, tc)							\
30131.61Skre{									\
30141.61Skre									\
30151.61Skre	eventmask_preserved(event);					\
30161.1Skamil}
30171.1Skamil
30181.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_empty, 0)
30191.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_fork, PTRACE_FORK)
30201.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_vfork, PTRACE_VFORK)
30211.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_vfork_done, PTRACE_VFORK_DONE)
30221.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_lwp_create, PTRACE_LWP_CREATE)
30231.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_lwp_exit, PTRACE_LWP_EXIT)
30241.125SkamilEVENTMASK_PRESERVED(eventmask_preserved_posix_spawn, PTRACE_POSIX_SPAWN)
30251.1Skamil
30261.53Skamil/// ----------------------------------------------------------------------------
30271.1Skamil
30281.28Skamilstatic void
30291.125Skamilfork_body(const char *fn, bool trackspawn, bool trackfork, bool trackvfork,
30301.105Skamil    bool trackvforkdone)
30311.1Skamil{
30321.1Skamil	const int exitval = 5;
30331.125Skamil	const int exitval2 = 0; /* This matched exit status from /bin/echo */
30341.1Skamil	const int sigval = SIGSTOP;
30351.31Skamil	pid_t child, child2 = 0, wpid;
30361.1Skamil#if defined(TWAIT_HAVE_STATUS)
30371.1Skamil	int status;
30381.1Skamil#endif
30391.1Skamil	ptrace_state_t state;
30401.1Skamil	const int slen = sizeof(state);
30411.1Skamil	ptrace_event_t event;
30421.1Skamil	const int elen = sizeof(event);
30431.1Skamil
30441.124Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
30451.124Skamil
30461.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
30471.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
30481.1Skamil	if (child == 0) {
30491.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
30501.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
30511.1Skamil
30521.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
30531.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
30541.1Skamil
30551.125Skamil		if (strcmp(fn, "spawn") == 0) {
30561.124Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
30571.124Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
30581.125Skamil		} else {
30591.125Skamil			if (strcmp(fn, "fork") == 0) {
30601.125Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
30611.125Skamil			} else if (strcmp(fn, "vfork") == 0) {
30621.125Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
30631.125Skamil			}
30641.1Skamil
30651.124Skamil			if (child2 == 0)
30661.124Skamil				_exit(exitval2);
30671.124Skamil		}
30681.1Skamil		FORKEE_REQUIRE_SUCCESS
30691.1Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
30701.1Skamil
30711.1Skamil		forkee_status_exited(status, exitval2);
30721.1Skamil
30731.13Schristos		DPRINTF("Before exiting of the child process\n");
30741.1Skamil		_exit(exitval);
30751.1Skamil	}
30761.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
30771.1Skamil
30781.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
30791.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
30801.1Skamil
30811.1Skamil	validate_status_stopped(status, sigval);
30821.1Skamil
30831.125Skamil	DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
30841.125Skamil	    trackspawn ? "|PTRACE_POSIX_SPAWN" : "",
30851.61Skre	    trackfork ? "|PTRACE_FORK" : "",
30861.61Skre	    trackvfork ? "|PTRACE_VFORK" : "",
30871.61Skre	    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", child);
30881.30Skamil	event.pe_set_event = 0;
30891.125Skamil	if (trackspawn)
30901.125Skamil		event.pe_set_event |= PTRACE_POSIX_SPAWN;
30911.30Skamil	if (trackfork)
30921.30Skamil		event.pe_set_event |= PTRACE_FORK;
30931.30Skamil	if (trackvfork)
30941.30Skamil		event.pe_set_event |= PTRACE_VFORK;
30951.30Skamil	if (trackvforkdone)
30961.30Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
30971.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
30981.1Skamil
30991.13Schristos	DPRINTF("Before resuming the child process where it left off and "
31001.1Skamil	    "without signal to be sent\n");
31011.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31021.1Skamil
31031.29Skamil#if defined(TWAIT_HAVE_PID)
31041.125Skamil	if ((trackspawn && strcmp(fn, "spawn") == 0) ||
31051.125Skamil	    (trackfork && strcmp(fn, "fork") == 0) ||
31061.125Skamil	    (trackvfork && strcmp(fn, "vfork") == 0)) {
31071.29Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
31081.61Skre		    child);
31091.29Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
31101.61Skre		    child);
31111.1Skamil
31121.29Skamil		validate_status_stopped(status, SIGTRAP);
31131.1Skamil
31141.61Skre		SYSCALL_REQUIRE(
31151.61Skre		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
31161.125Skamil		if (trackspawn && strcmp(fn, "spawn") == 0) {
31171.125Skamil			ATF_REQUIRE_EQ(
31181.125Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
31191.125Skamil			       PTRACE_POSIX_SPAWN);
31201.125Skamil		}
31211.125Skamil		if (trackfork && strcmp(fn, "fork") == 0) {
31221.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
31231.30Skamil			       PTRACE_FORK);
31241.30Skamil		}
31251.125Skamil		if (trackvfork && strcmp(fn, "vfork") == 0) {
31261.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
31271.30Skamil			       PTRACE_VFORK);
31281.30Skamil		}
31291.29Skamil
31301.29Skamil		child2 = state.pe_other_pid;
31311.30Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
31321.29Skamil
31331.29Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
31341.61Skre		    "%d\n", TWAIT_FNAME, child2, child);
31351.29Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
31361.29Skamil		    child2);
31371.1Skamil
31381.29Skamil		validate_status_stopped(status, SIGTRAP);
31391.1Skamil
31401.61Skre		SYSCALL_REQUIRE(
31411.61Skre		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
31421.125Skamil		if (trackspawn && strcmp(fn, "spawn") == 0) {
31431.125Skamil			ATF_REQUIRE_EQ(
31441.125Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
31451.125Skamil			       PTRACE_POSIX_SPAWN);
31461.125Skamil		}
31471.125Skamil		if (trackfork && strcmp(fn, "fork") == 0) {
31481.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
31491.30Skamil			       PTRACE_FORK);
31501.30Skamil		}
31511.125Skamil		if (trackvfork && strcmp(fn, "vfork") == 0) {
31521.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
31531.30Skamil			       PTRACE_VFORK);
31541.30Skamil		}
31551.30Skamil
31561.29Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
31571.29Skamil
31581.29Skamil		DPRINTF("Before resuming the forkee process where it left off "
31591.29Skamil		    "and without signal to be sent\n");
31601.61Skre		SYSCALL_REQUIRE(
31611.61Skre		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
31621.29Skamil
31631.29Skamil		DPRINTF("Before resuming the child process where it left off "
31641.61Skre		    "and without signal to be sent\n");
31651.29Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31661.30Skamil	}
31671.30Skamil#endif
31681.30Skamil
31691.125Skamil	if (trackvforkdone && strcmp(fn, "vfork") == 0) {
31701.30Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
31711.61Skre		    child);
31721.61Skre		TWAIT_REQUIRE_SUCCESS(
31731.61Skre		    wpid = TWAIT_GENERIC(child, &status, 0), child);
31741.30Skamil
31751.30Skamil		validate_status_stopped(status, SIGTRAP);
31761.30Skamil
31771.61Skre		SYSCALL_REQUIRE(
31781.61Skre		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
31791.30Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
31801.30Skamil
31811.30Skamil		child2 = state.pe_other_pid;
31821.30Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
31831.61Skre		    child2);
31841.30Skamil
31851.30Skamil		DPRINTF("Before resuming the child process where it left off "
31861.61Skre		    "and without signal to be sent\n");
31871.30Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31881.30Skamil	}
31891.29Skamil
31901.30Skamil#if defined(TWAIT_HAVE_PID)
31911.125Skamil	if ((trackspawn && strcmp(fn, "spawn") == 0) ||
31921.125Skamil	    (trackfork && strcmp(fn, "fork") == 0) ||
31931.125Skamil	    (trackvfork && strcmp(fn, "vfork") == 0)) {
31941.29Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
31951.61Skre		    "\n", TWAIT_FNAME);
31961.61Skre		TWAIT_REQUIRE_SUCCESS(
31971.61Skre		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
31981.29Skamil
31991.29Skamil		validate_status_exited(status, exitval2);
32001.29Skamil
32011.29Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
32021.61Skre		    "process\n", TWAIT_FNAME);
32031.29Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
32041.29Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
32051.29Skamil	}
32061.29Skamil#endif
32071.1Skamil
32081.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
32091.1Skamil	    "SIGCHLD\n", TWAIT_FNAME);
32101.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
32111.1Skamil
32121.1Skamil	validate_status_stopped(status, SIGCHLD);
32131.1Skamil
32141.13Schristos	DPRINTF("Before resuming the child process where it left off and "
32151.1Skamil	    "without signal to be sent\n");
32161.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
32171.1Skamil
32181.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
32191.1Skamil	    TWAIT_FNAME);
32201.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
32211.1Skamil
32221.1Skamil	validate_status_exited(status, exitval);
32231.1Skamil
32241.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
32251.1Skamil	    TWAIT_FNAME);
32261.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
32271.1Skamil}
32281.28Skamil
32291.125Skamil#define FORK_TEST(name,fun,tspawn,tfork,tvfork,tvforkdone)		\
32301.61SkreATF_TC(name);								\
32311.61SkreATF_TC_HEAD(name, tc)							\
32321.61Skre{									\
32331.125Skamil	atf_tc_set_md_var(tc, "descr", "Verify " fun "() "		\
32341.125Skamil	    "called with 0%s%s%s%s in EVENT_MASK",			\
32351.126Skamil	    tspawn ? "|PTRACE_POSIX_SPAWN" : "",			\
32361.105Skamil	    tfork ? "|PTRACE_FORK" : "",				\
32371.105Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
32381.105Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
32391.61Skre}									\
32401.61Skre									\
32411.61SkreATF_TC_BODY(name, tc)							\
32421.61Skre{									\
32431.61Skre									\
32441.125Skamil	fork_body(fun, tspawn, tfork, tvfork, tvforkdone);		\
32451.32Skamil}
32461.32Skamil
32471.125SkamilFORK_TEST(fork1, "fork", false, false, false, false)
32481.31Skamil#if defined(TWAIT_HAVE_PID)
32491.125SkamilFORK_TEST(fork2, "fork", false, true, false, false)
32501.125SkamilFORK_TEST(fork3, "fork", false, false, true, false)
32511.125SkamilFORK_TEST(fork4, "fork", false, true, true, false)
32521.31Skamil#endif
32531.125SkamilFORK_TEST(fork5, "fork", false, false, false, true)
32541.31Skamil#if defined(TWAIT_HAVE_PID)
32551.125SkamilFORK_TEST(fork6, "fork", false, true, false, true)
32561.125SkamilFORK_TEST(fork7, "fork", false, false, true, true)
32571.125SkamilFORK_TEST(fork8, "fork", false, true, true, true)
32581.125Skamil#endif
32591.125SkamilFORK_TEST(fork9, "fork", true, false, false, false)
32601.125Skamil#if defined(TWAIT_HAVE_PID)
32611.125SkamilFORK_TEST(fork10, "fork", true, true, false, false)
32621.125SkamilFORK_TEST(fork11, "fork", true, false, true, false)
32631.125SkamilFORK_TEST(fork12, "fork", true, true, true, false)
32641.125Skamil#endif
32651.125SkamilFORK_TEST(fork13, "fork", true, false, false, true)
32661.125Skamil#if defined(TWAIT_HAVE_PID)
32671.125SkamilFORK_TEST(fork14, "fork", true, true, false, true)
32681.125SkamilFORK_TEST(fork15, "fork", true, false, true, true)
32691.125SkamilFORK_TEST(fork16, "fork", true, true, true, true)
32701.31Skamil#endif
32711.1Skamil
32721.110Skamil#if TEST_VFORK_ENABLED
32731.125SkamilFORK_TEST(vfork1, "vfork", false, false, false, false)
32741.31Skamil#if defined(TWAIT_HAVE_PID)
32751.125SkamilFORK_TEST(vfork2, "vfork", false, true, false, false)
32761.125SkamilFORK_TEST(vfork3, "vfork", false, false, true, false)
32771.125SkamilFORK_TEST(vfork4, "vfork", false, true, true, false)
32781.31Skamil#endif
32791.125SkamilFORK_TEST(vfork5, "vfork", false, false, false, true)
32801.31Skamil#if defined(TWAIT_HAVE_PID)
32811.125SkamilFORK_TEST(vfork6, "vfork", false, true, false, true)
32821.125SkamilFORK_TEST(vfork7, "vfork", false, false, true, true)
32831.125SkamilFORK_TEST(vfork8, "vfork", false, true, true, true)
32841.31Skamil#endif
32851.125SkamilFORK_TEST(vfork9, "vfork", true, false, false, false)
32861.125Skamil#if defined(TWAIT_HAVE_PID)
32871.125SkamilFORK_TEST(vfork10, "vfork", true, true, false, false)
32881.125SkamilFORK_TEST(vfork11, "vfork", true, false, true, false)
32891.125SkamilFORK_TEST(vfork12, "vfork", true, true, true, false)
32901.110Skamil#endif
32911.125SkamilFORK_TEST(vfork13, "vfork", true, false, false, true)
32921.124Skamil#if defined(TWAIT_HAVE_PID)
32931.125SkamilFORK_TEST(vfork14, "vfork", true, true, false, true)
32941.125SkamilFORK_TEST(vfork15, "vfork", true, false, true, true)
32951.125SkamilFORK_TEST(vfork16, "vfork", true, true, true, true)
32961.124Skamil#endif
32971.125Skamil#endif
32981.125Skamil
32991.125SkamilFORK_TEST(posix_spawn1, "spawn", false, false, false, false)
33001.125SkamilFORK_TEST(posix_spawn2, "spawn", false, true, false, false)
33011.125SkamilFORK_TEST(posix_spawn3, "spawn", false, false, true, false)
33021.125SkamilFORK_TEST(posix_spawn4, "spawn", false, true, true, false)
33031.125SkamilFORK_TEST(posix_spawn5, "spawn", false, false, false, true)
33041.125SkamilFORK_TEST(posix_spawn6, "spawn", false, true, false, true)
33051.125SkamilFORK_TEST(posix_spawn7, "spawn", false, false, true, true)
33061.125SkamilFORK_TEST(posix_spawn8, "spawn", false, true, true, true)
33071.124Skamil#if defined(TWAIT_HAVE_PID)
33081.125SkamilFORK_TEST(posix_spawn9, "spawn", true, false, false, false)
33091.125SkamilFORK_TEST(posix_spawn10, "spawn", true, true, false, false)
33101.125SkamilFORK_TEST(posix_spawn11, "spawn", true, false, true, false)
33111.125SkamilFORK_TEST(posix_spawn12, "spawn", true, true, true, false)
33121.125SkamilFORK_TEST(posix_spawn13, "spawn", true, false, false, true)
33131.125SkamilFORK_TEST(posix_spawn14, "spawn", true, true, false, true)
33141.125SkamilFORK_TEST(posix_spawn15, "spawn", true, false, true, true)
33151.125SkamilFORK_TEST(posix_spawn16, "spawn", true, true, true, true)
33161.124Skamil#endif
33171.124Skamil
33181.54Skamil/// ----------------------------------------------------------------------------
33191.31Skamil
33201.116Skamil#if defined(TWAIT_HAVE_PID)
33211.116Skamilstatic void
33221.126Skamilfork_detach_forker_body(const char *fn, bool kill_process)
33231.116Skamil{
33241.116Skamil	const int exitval = 5;
33251.126Skamil	const int exitval2 = 0; /* Matches exit value from /bin/echo */
33261.116Skamil	const int sigval = SIGSTOP;
33271.116Skamil	pid_t child, child2 = 0, wpid;
33281.116Skamil#if defined(TWAIT_HAVE_STATUS)
33291.116Skamil	int status;
33301.116Skamil#endif
33311.116Skamil	ptrace_state_t state;
33321.116Skamil	const int slen = sizeof(state);
33331.116Skamil	ptrace_event_t event;
33341.116Skamil	const int elen = sizeof(event);
33351.116Skamil
33361.116Skamil	int op;
33371.116Skamil
33381.126Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
33391.116Skamil
33401.116Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
33411.116Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
33421.116Skamil	if (child == 0) {
33431.116Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
33441.116Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
33451.116Skamil
33461.116Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
33471.116Skamil		FORKEE_ASSERT(raise(sigval) == 0);
33481.116Skamil
33491.126Skamil		if (strcmp(fn, "spawn") == 0) {
33501.126Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
33511.126Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
33521.126Skamil		} else  {
33531.126Skamil			if (strcmp(fn, "fork") == 0) {
33541.126Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
33551.126Skamil			} else {
33561.126Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
33571.126Skamil			}
33581.116Skamil
33591.126Skamil			if (child2 == 0)
33601.126Skamil				_exit(exitval2);
33611.126Skamil		}
33621.116Skamil
33631.116Skamil		FORKEE_REQUIRE_SUCCESS
33641.116Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
33651.116Skamil
33661.116Skamil		forkee_status_exited(status, exitval2);
33671.116Skamil
33681.116Skamil		DPRINTF("Before exiting of the child process\n");
33691.116Skamil		_exit(exitval);
33701.116Skamil	}
33711.116Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
33721.116Skamil
33731.116Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
33741.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
33751.116Skamil
33761.116Skamil	validate_status_stopped(status, sigval);
33771.116Skamil
33781.116Skamil	DPRINTF("Set EVENT_MASK for the child %d\n", child);
33791.126Skamil	event.pe_set_event = PTRACE_POSIX_SPAWN | PTRACE_FORK | PTRACE_VFORK
33801.126Skamil		| PTRACE_VFORK_DONE;
33811.116Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
33821.116Skamil
33831.116Skamil	DPRINTF("Before resuming the child process where it left off and "
33841.116Skamil	    "without signal to be sent\n");
33851.116Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
33861.116Skamil
33871.116Skamil	DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME, child);
33881.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
33891.116Skamil
33901.116Skamil	validate_status_stopped(status, SIGTRAP);
33911.116Skamil
33921.116Skamil	SYSCALL_REQUIRE(
33931.116Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
33941.126Skamil
33951.126Skamil	if (strcmp(fn, "spawn") == 0)
33961.126Skamil		op = PTRACE_POSIX_SPAWN;
33971.126Skamil	else if (strcmp(fn, "fork") == 0)
33981.126Skamil		op = PTRACE_FORK;
33991.126Skamil	else
34001.126Skamil		op = PTRACE_VFORK;
34011.126Skamil
34021.116Skamil	ATF_REQUIRE_EQ(state.pe_report_event & op, op);
34031.116Skamil
34041.116Skamil	child2 = state.pe_other_pid;
34051.116Skamil	DPRINTF("Reported ptrace event with forkee %d\n", child2);
34061.116Skamil
34071.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
34081.126Skamil	    strcmp(fn, "vfork") == 0)
34091.116Skamil		op = kill_process ? PT_KILL : PT_DETACH;
34101.116Skamil	else
34111.116Skamil		op = PT_CONTINUE;
34121.116Skamil	SYSCALL_REQUIRE(ptrace(op, child, (void *)1, 0) != -1);
34131.116Skamil
34141.116Skamil	DPRINTF("Before calling %s() for the forkee %d of the child %d\n",
34151.116Skamil	    TWAIT_FNAME, child2, child);
34161.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0), child2);
34171.116Skamil
34181.116Skamil	validate_status_stopped(status, SIGTRAP);
34191.116Skamil
34201.116Skamil	SYSCALL_REQUIRE(
34211.116Skamil	    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
34221.126Skamil	if (strcmp(fn, "spawn") == 0)
34231.126Skamil		op = PTRACE_POSIX_SPAWN;
34241.126Skamil	else if (strcmp(fn, "fork") == 0)
34251.126Skamil		op = PTRACE_FORK;
34261.126Skamil	else
34271.126Skamil		op = PTRACE_VFORK;
34281.126Skamil
34291.116Skamil	ATF_REQUIRE_EQ(state.pe_report_event & op, op);
34301.116Skamil	ATF_REQUIRE_EQ(state.pe_other_pid, child);
34311.116Skamil
34321.116Skamil	DPRINTF("Before resuming the forkee process where it left off "
34331.116Skamil	    "and without signal to be sent\n");
34341.116Skamil 	SYSCALL_REQUIRE(
34351.116Skamil	    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
34361.116Skamil
34371.126Skamil	if (strcmp(fn, "vforkdone") == 0) {
34381.116Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
34391.116Skamil		    child);
34401.116Skamil		TWAIT_REQUIRE_SUCCESS(
34411.116Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
34421.116Skamil
34431.116Skamil		validate_status_stopped(status, SIGTRAP);
34441.116Skamil
34451.116Skamil		SYSCALL_REQUIRE(
34461.116Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
34471.116Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
34481.116Skamil
34491.116Skamil		child2 = state.pe_other_pid;
34501.116Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
34511.116Skamil		    child2);
34521.116Skamil
34531.116Skamil		op = kill_process ? PT_KILL : PT_DETACH;
34541.116Skamil		DPRINTF("Before resuming the child process where it left off "
34551.116Skamil		    "and without signal to be sent\n");
34561.116Skamil		SYSCALL_REQUIRE(ptrace(op, child, (void *)1, 0) != -1);
34571.116Skamil	}
34581.116Skamil
34591.116Skamil	DPRINTF("Before calling %s() for the forkee - expected exited\n",
34601.116Skamil	    TWAIT_FNAME);
34611.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0), child2);
34621.116Skamil
34631.116Skamil	validate_status_exited(status, exitval2);
34641.116Skamil
34651.116Skamil	DPRINTF("Before calling %s() for the forkee - expected no process\n",
34661.116Skamil	    TWAIT_FNAME);
34671.116Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child2, &status, 0));
34681.116Skamil
34691.116Skamil	DPRINTF("Before calling %s() for the forkee - expected exited\n",
34701.116Skamil	    TWAIT_FNAME);
34711.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
34721.116Skamil
34731.116Skamil	if (kill_process) {
34741.116Skamil		validate_status_signaled(status, SIGKILL, 0);
34751.116Skamil	} else {
34761.116Skamil		validate_status_exited(status, exitval);
34771.116Skamil	}
34781.116Skamil
34791.116Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
34801.116Skamil	    TWAIT_FNAME);
34811.116Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
34821.116Skamil}
34831.116Skamil
34841.126Skamil#define FORK_DETACH_FORKER(name,event,kprocess)				\
34851.116SkamilATF_TC(name);								\
34861.116SkamilATF_TC_HEAD(name, tc)							\
34871.116Skamil{									\
34881.126Skamil	atf_tc_set_md_var(tc, "descr", "Verify %s " event,		\
34891.126Skamil	    kprocess ? "killed" : "detached");				\
34901.116Skamil}									\
34911.116Skamil									\
34921.116SkamilATF_TC_BODY(name, tc)							\
34931.116Skamil{									\
34941.116Skamil									\
34951.126Skamil	fork_detach_forker_body(event, kprocess);			\
34961.116Skamil}
34971.116Skamil
34981.126SkamilFORK_DETACH_FORKER(posix_spawn_detach_spawner, "spawn", false)
34991.126SkamilFORK_DETACH_FORKER(fork_detach_forker, "fork", false)
35001.116Skamil#if TEST_VFORK_ENABLED
35011.126SkamilFORK_DETACH_FORKER(vfork_detach_vforker, "vfork", false)
35021.126SkamilFORK_DETACH_FORKER(vfork_detach_vforkerdone, "vforkdone", false)
35031.116Skamil#endif
35041.126Skamil
35051.126SkamilFORK_DETACH_FORKER(posix_spawn_kill_spawner, "spawn", true)
35061.126SkamilFORK_DETACH_FORKER(fork_kill_forker, "fork", true)
35071.116Skamil#if TEST_VFORK_ENABLED
35081.126SkamilFORK_DETACH_FORKER(vfork_kill_vforker, "vfork", true)
35091.126SkamilFORK_DETACH_FORKER(vfork_kill_vforkerdone, "vforkdone", true)
35101.116Skamil#endif
35111.116Skamil#endif
35121.116Skamil
35131.116Skamil/// ----------------------------------------------------------------------------
35141.116Skamil
35151.110Skamil#if TEST_VFORK_ENABLED
35161.108Skamilstatic void
35171.108Skamiltraceme_vfork_fork_body(pid_t (*fn)(void))
35181.108Skamil{
35191.108Skamil	const int exitval = 5;
35201.108Skamil	const int exitval2 = 15;
35211.108Skamil	pid_t child, child2 = 0, wpid;
35221.108Skamil#if defined(TWAIT_HAVE_STATUS)
35231.108Skamil	int status;
35241.108Skamil#endif
35251.108Skamil
35261.108Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
35271.108Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
35281.108Skamil	if (child == 0) {
35291.108Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
35301.108Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
35311.108Skamil
35321.108Skamil		FORKEE_ASSERT((child2 = (fn)()) != -1);
35331.108Skamil
35341.108Skamil		if (child2 == 0)
35351.108Skamil			_exit(exitval2);
35361.108Skamil
35371.108Skamil		FORKEE_REQUIRE_SUCCESS
35381.108Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
35391.108Skamil
35401.108Skamil		forkee_status_exited(status, exitval2);
35411.108Skamil
35421.108Skamil		DPRINTF("Before exiting of the child process\n");
35431.108Skamil		_exit(exitval);
35441.108Skamil	}
35451.108Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
35461.108Skamil
35471.108Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
35481.108Skamil	    TWAIT_FNAME);
35491.108Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
35501.108Skamil
35511.108Skamil	validate_status_exited(status, exitval);
35521.108Skamil
35531.108Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
35541.108Skamil	    TWAIT_FNAME);
35551.108Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
35561.108Skamil}
35571.108Skamil
35581.108Skamil#define TRACEME_VFORK_FORK_TEST(name,fun)				\
35591.108SkamilATF_TC(name);								\
35601.108SkamilATF_TC_HEAD(name, tc)							\
35611.108Skamil{									\
35621.108Skamil	atf_tc_set_md_var(tc, "descr", "Verify " #fun "(2) "		\
35631.108Skamil	    "called from vfork(2)ed child");				\
35641.108Skamil}									\
35651.108Skamil									\
35661.108SkamilATF_TC_BODY(name, tc)							\
35671.108Skamil{									\
35681.108Skamil									\
35691.108Skamil	traceme_vfork_fork_body(fun);					\
35701.108Skamil}
35711.108Skamil
35721.108SkamilTRACEME_VFORK_FORK_TEST(traceme_vfork_fork, fork)
35731.108SkamilTRACEME_VFORK_FORK_TEST(traceme_vfork_vfork, vfork)
35741.110Skamil#endif
35751.108Skamil
35761.108Skamil/// ----------------------------------------------------------------------------
35771.108Skamil
35781.54Skamilenum bytes_transfer_type {
35791.54Skamil	BYTES_TRANSFER_DATA,
35801.54Skamil	BYTES_TRANSFER_DATAIO,
35811.54Skamil	BYTES_TRANSFER_TEXT,
35821.54Skamil	BYTES_TRANSFER_TEXTIO,
35831.54Skamil	BYTES_TRANSFER_AUXV
35841.54Skamil};
35851.31Skamil
35861.54Skamilstatic int __used
35871.54Skamilbytes_transfer_dummy(int a, int b, int c, int d)
35881.54Skamil{
35891.54Skamil	int e, f, g, h;
35901.1Skamil
35911.54Skamil	a *= 4;
35921.54Skamil	b += 3;
35931.54Skamil	c -= 2;
35941.54Skamil	d /= 1;
35951.1Skamil
35961.54Skamil	e = strtol("10", NULL, 10);
35971.54Skamil	f = strtol("20", NULL, 10);
35981.54Skamil	g = strtol("30", NULL, 10);
35991.54Skamil	h = strtol("40", NULL, 10);
36001.1Skamil
36011.54Skamil	return (a + b * c - d) + (e * f - g / h);
36021.1Skamil}
36031.1Skamil
36041.54Skamilstatic void
36051.55Schristosbytes_transfer(int operation, size_t size, enum bytes_transfer_type type)
36061.1Skamil{
36071.1Skamil	const int exitval = 5;
36081.1Skamil	const int sigval = SIGSTOP;
36091.1Skamil	pid_t child, wpid;
36101.54Skamil	bool skip = false;
36111.1Skamil
36121.54Skamil	int lookup_me = 0;
36131.54Skamil	uint8_t lookup_me8 = 0;
36141.54Skamil	uint16_t lookup_me16 = 0;
36151.54Skamil	uint32_t lookup_me32 = 0;
36161.54Skamil	uint64_t lookup_me64 = 0;
36171.1Skamil
36181.54Skamil	int magic = 0x13579246;
36191.54Skamil	uint8_t magic8 = 0xab;
36201.54Skamil	uint16_t magic16 = 0x1234;
36211.54Skamil	uint32_t magic32 = 0x98765432;
36221.54Skamil	uint64_t magic64 = 0xabcdef0123456789;
36231.1Skamil
36241.54Skamil	struct ptrace_io_desc io;
36251.1Skamil#if defined(TWAIT_HAVE_STATUS)
36261.1Skamil	int status;
36271.1Skamil#endif
36281.60Skre	/* 513 is just enough, for the purposes of ATF it's good enough */
36291.60Skre	AuxInfo ai[513], *aip;
36301.55Schristos
36311.55Schristos	ATF_REQUIRE(size < sizeof(ai));
36321.1Skamil
36331.54Skamil	/* Prepare variables for .TEXT transfers */
36341.54Skamil	switch (type) {
36351.54Skamil	case BYTES_TRANSFER_TEXT:
36361.54Skamil		memcpy(&magic, bytes_transfer_dummy, sizeof(magic));
36371.54Skamil		break;
36381.54Skamil	case BYTES_TRANSFER_TEXTIO:
36391.54Skamil		switch (size) {
36401.54Skamil		case 8:
36411.54Skamil			memcpy(&magic8, bytes_transfer_dummy, sizeof(magic8));
36421.54Skamil			break;
36431.54Skamil		case 16:
36441.54Skamil			memcpy(&magic16, bytes_transfer_dummy, sizeof(magic16));
36451.54Skamil			break;
36461.54Skamil		case 32:
36471.54Skamil			memcpy(&magic32, bytes_transfer_dummy, sizeof(magic32));
36481.54Skamil			break;
36491.54Skamil		case 64:
36501.54Skamil			memcpy(&magic64, bytes_transfer_dummy, sizeof(magic64));
36511.54Skamil			break;
36521.54Skamil		}
36531.54Skamil		break;
36541.54Skamil	default:
36551.54Skamil		break;
36561.54Skamil	}
36571.1Skamil
36581.54Skamil	/* Prepare variables for PIOD and AUXV transfers */
36591.54Skamil	switch (type) {
36601.54Skamil	case BYTES_TRANSFER_TEXTIO:
36611.54Skamil	case BYTES_TRANSFER_DATAIO:
36621.54Skamil		io.piod_op = operation;
36631.54Skamil		switch (size) {
36641.54Skamil		case 8:
36651.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
36661.54Skamil			               (void *)bytes_transfer_dummy :
36671.54Skamil			               &lookup_me8;
36681.54Skamil			io.piod_addr = &lookup_me8;
36691.54Skamil			io.piod_len = sizeof(lookup_me8);
36701.54Skamil			break;
36711.54Skamil		case 16:
36721.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
36731.54Skamil			               (void *)bytes_transfer_dummy :
36741.54Skamil			               &lookup_me16;
36751.54Skamil			io.piod_addr = &lookup_me16;
36761.54Skamil			io.piod_len = sizeof(lookup_me16);
36771.54Skamil			break;
36781.54Skamil		case 32:
36791.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
36801.54Skamil			               (void *)bytes_transfer_dummy :
36811.54Skamil			               &lookup_me32;
36821.54Skamil			io.piod_addr = &lookup_me32;
36831.54Skamil			io.piod_len = sizeof(lookup_me32);
36841.54Skamil			break;
36851.54Skamil		case 64:
36861.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
36871.54Skamil			               (void *)bytes_transfer_dummy :
36881.54Skamil			               &lookup_me64;
36891.54Skamil			io.piod_addr = &lookup_me64;
36901.54Skamil			io.piod_len = sizeof(lookup_me64);
36911.54Skamil			break;
36921.54Skamil		default:
36931.54Skamil			break;
36941.54Skamil		}
36951.54Skamil		break;
36961.54Skamil	case BYTES_TRANSFER_AUXV:
36971.54Skamil		io.piod_op = operation;
36981.54Skamil		io.piod_offs = 0;
36991.54Skamil		io.piod_addr = ai;
37001.54Skamil		io.piod_len = size;
37011.54Skamil		break;
37021.54Skamil	default:
37031.54Skamil		break;
37041.1Skamil	}
37051.1Skamil
37061.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
37071.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
37081.1Skamil	if (child == 0) {
37091.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
37101.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
37111.1Skamil
37121.54Skamil		switch (type) {
37131.54Skamil		case BYTES_TRANSFER_DATA:
37141.54Skamil			switch (operation) {
37151.54Skamil			case PT_READ_D:
37161.54Skamil			case PT_READ_I:
37171.54Skamil				lookup_me = magic;
37181.54Skamil				break;
37191.54Skamil			default:
37201.54Skamil				break;
37211.54Skamil			}
37221.54Skamil			break;
37231.54Skamil		case BYTES_TRANSFER_DATAIO:
37241.54Skamil			switch (operation) {
37251.54Skamil			case PIOD_READ_D:
37261.54Skamil			case PIOD_READ_I:
37271.54Skamil				switch (size) {
37281.54Skamil				case 8:
37291.54Skamil					lookup_me8 = magic8;
37301.54Skamil					break;
37311.54Skamil				case 16:
37321.54Skamil					lookup_me16 = magic16;
37331.54Skamil					break;
37341.54Skamil				case 32:
37351.54Skamil					lookup_me32 = magic32;
37361.54Skamil					break;
37371.54Skamil				case 64:
37381.54Skamil					lookup_me64 = magic64;
37391.54Skamil					break;
37401.54Skamil				default:
37411.54Skamil					break;
37421.54Skamil				}
37431.54Skamil				break;
37441.54Skamil			default:
37451.54Skamil				break;
37461.54Skamil			}
37471.54Skamil		default:
37481.54Skamil			break;
37491.54Skamil		}
37501.54Skamil
37511.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
37521.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
37531.1Skamil
37541.54Skamil		/* Handle PIOD and PT separately as operation values overlap */
37551.54Skamil		switch (type) {
37561.54Skamil		case BYTES_TRANSFER_DATA:
37571.54Skamil			switch (operation) {
37581.54Skamil			case PT_WRITE_D:
37591.54Skamil			case PT_WRITE_I:
37601.54Skamil				FORKEE_ASSERT_EQ(lookup_me, magic);
37611.54Skamil				break;
37621.54Skamil			default:
37631.54Skamil				break;
37641.54Skamil			}
37651.54Skamil			break;
37661.54Skamil		case BYTES_TRANSFER_DATAIO:
37671.54Skamil			switch (operation) {
37681.54Skamil			case PIOD_WRITE_D:
37691.54Skamil			case PIOD_WRITE_I:
37701.54Skamil				switch (size) {
37711.54Skamil				case 8:
37721.54Skamil					FORKEE_ASSERT_EQ(lookup_me8, magic8);
37731.54Skamil					break;
37741.54Skamil				case 16:
37751.54Skamil					FORKEE_ASSERT_EQ(lookup_me16, magic16);
37761.54Skamil					break;
37771.54Skamil				case 32:
37781.54Skamil					FORKEE_ASSERT_EQ(lookup_me32, magic32);
37791.54Skamil					break;
37801.54Skamil				case 64:
37811.54Skamil					FORKEE_ASSERT_EQ(lookup_me64, magic64);
37821.54Skamil					break;
37831.54Skamil				default:
37841.54Skamil					break;
37851.54Skamil				}
37861.54Skamil				break;
37871.54Skamil			default:
37881.54Skamil				break;
37891.54Skamil			}
37901.54Skamil			break;
37911.54Skamil		case BYTES_TRANSFER_TEXT:
37921.54Skamil			FORKEE_ASSERT(memcmp(&magic, bytes_transfer_dummy,
37931.54Skamil			                     sizeof(magic)) == 0);
37941.54Skamil			break;
37951.54Skamil		case BYTES_TRANSFER_TEXTIO:
37961.54Skamil			switch (size) {
37971.54Skamil			case 8:
37981.54Skamil				FORKEE_ASSERT(memcmp(&magic8,
37991.54Skamil				                     bytes_transfer_dummy,
38001.54Skamil				                     sizeof(magic8)) == 0);
38011.54Skamil				break;
38021.54Skamil			case 16:
38031.54Skamil				FORKEE_ASSERT(memcmp(&magic16,
38041.54Skamil				                     bytes_transfer_dummy,
38051.54Skamil				                     sizeof(magic16)) == 0);
38061.54Skamil				break;
38071.54Skamil			case 32:
38081.54Skamil				FORKEE_ASSERT(memcmp(&magic32,
38091.54Skamil				                     bytes_transfer_dummy,
38101.54Skamil				                     sizeof(magic32)) == 0);
38111.54Skamil				break;
38121.54Skamil			case 64:
38131.54Skamil				FORKEE_ASSERT(memcmp(&magic64,
38141.54Skamil				                     bytes_transfer_dummy,
38151.54Skamil				                     sizeof(magic64)) == 0);
38161.54Skamil				break;
38171.54Skamil			}
38181.54Skamil			break;
38191.54Skamil		default:
38201.54Skamil			break;
38211.54Skamil		}
38221.54Skamil
38231.13Schristos		DPRINTF("Before exiting of the child process\n");
38241.1Skamil		_exit(exitval);
38251.1Skamil	}
38261.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
38271.1Skamil
38281.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
38291.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
38301.1Skamil
38311.1Skamil	validate_status_stopped(status, sigval);
38321.1Skamil
38331.54Skamil	/* Check PaX MPROTECT */
38341.54Skamil	if (!can_we_write_to_text(child)) {
38351.54Skamil		switch (type) {
38361.54Skamil		case BYTES_TRANSFER_TEXTIO:
38371.54Skamil			switch (operation) {
38381.54Skamil			case PIOD_WRITE_D:
38391.54Skamil			case PIOD_WRITE_I:
38401.54Skamil				skip = true;
38411.54Skamil				break;
38421.54Skamil			default:
38431.54Skamil				break;
38441.54Skamil			}
38451.54Skamil			break;
38461.54Skamil		case BYTES_TRANSFER_TEXT:
38471.54Skamil			switch (operation) {
38481.54Skamil			case PT_WRITE_D:
38491.54Skamil			case PT_WRITE_I:
38501.54Skamil				skip = true;
38511.54Skamil				break;
38521.54Skamil			default:
38531.54Skamil				break;
38541.54Skamil			}
38551.54Skamil			break;
38561.54Skamil		default:
38571.54Skamil			break;
38581.54Skamil		}
38591.54Skamil	}
38601.1Skamil
38611.54Skamil	/* Bailout cleanly killing the child process */
38621.54Skamil	if (skip) {
38631.54Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
38641.54Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
38651.54Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
38661.54Skamil		                      child);
38671.1Skamil
38681.54Skamil		validate_status_signaled(status, SIGKILL, 0);
38691.1Skamil
38701.54Skamil		atf_tc_skip("PaX MPROTECT setup prevents writes to .text");
38711.54Skamil	}
38721.1Skamil
38731.54Skamil	DPRINTF("Calling operation to transfer bytes between child=%d and "
38741.54Skamil	       "parent=%d\n", child, getpid());
38751.1Skamil
38761.54Skamil	switch (type) {
38771.54Skamil	case BYTES_TRANSFER_TEXTIO:
38781.54Skamil	case BYTES_TRANSFER_DATAIO:
38791.54Skamil	case BYTES_TRANSFER_AUXV:
38801.54Skamil		switch (operation) {
38811.54Skamil		case PIOD_WRITE_D:
38821.54Skamil		case PIOD_WRITE_I:
38831.54Skamil			switch (size) {
38841.54Skamil			case 8:
38851.54Skamil				lookup_me8 = magic8;
38861.54Skamil				break;
38871.54Skamil			case 16:
38881.54Skamil				lookup_me16 = magic16;
38891.54Skamil				break;
38901.54Skamil			case 32:
38911.54Skamil				lookup_me32 = magic32;
38921.54Skamil				break;
38931.54Skamil			case 64:
38941.54Skamil				lookup_me64 = magic64;
38951.54Skamil				break;
38961.54Skamil			default:
38971.54Skamil				break;
38981.54Skamil			}
38991.54Skamil			break;
39001.54Skamil		default:
39011.54Skamil			break;
39021.54Skamil		}
39031.54Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
39041.54Skamil		switch (operation) {
39051.54Skamil		case PIOD_READ_D:
39061.54Skamil		case PIOD_READ_I:
39071.54Skamil			switch (size) {
39081.54Skamil			case 8:
39091.54Skamil				ATF_REQUIRE_EQ(lookup_me8, magic8);
39101.54Skamil				break;
39111.54Skamil			case 16:
39121.54Skamil				ATF_REQUIRE_EQ(lookup_me16, magic16);
39131.54Skamil				break;
39141.54Skamil			case 32:
39151.54Skamil				ATF_REQUIRE_EQ(lookup_me32, magic32);
39161.54Skamil				break;
39171.54Skamil			case 64:
39181.54Skamil				ATF_REQUIRE_EQ(lookup_me64, magic64);
39191.54Skamil				break;
39201.54Skamil			default:
39211.54Skamil				break;
39221.54Skamil			}
39231.54Skamil			break;
39241.54Skamil		case PIOD_READ_AUXV:
39251.54Skamil			DPRINTF("Asserting that AUXV length (%zu) is > 0\n",
39261.54Skamil			        io.piod_len);
39271.54Skamil			ATF_REQUIRE(io.piod_len > 0);
39281.54Skamil			for (aip = ai; aip->a_type != AT_NULL; aip++)
39291.54Skamil				DPRINTF("a_type=%#llx a_v=%#llx\n",
39301.54Skamil				    (long long int)aip->a_type,
39311.54Skamil				    (long long int)aip->a_v);
39321.54Skamil			break;
39331.54Skamil		default:
39341.54Skamil			break;
39351.54Skamil		}
39361.54Skamil		break;
39371.54Skamil	case BYTES_TRANSFER_TEXT:
39381.54Skamil		switch (operation) {
39391.54Skamil		case PT_READ_D:
39401.54Skamil		case PT_READ_I:
39411.54Skamil			errno = 0;
39421.54Skamil			lookup_me = ptrace(operation, child,
39431.54Skamil			                   bytes_transfer_dummy, 0);
39441.54Skamil			ATF_REQUIRE_EQ(lookup_me, magic);
39451.54Skamil			SYSCALL_REQUIRE_ERRNO(errno, 0);
39461.54Skamil			break;
39471.54Skamil		case PT_WRITE_D:
39481.54Skamil		case PT_WRITE_I:
39491.54Skamil			SYSCALL_REQUIRE(ptrace(operation, child,
39501.54Skamil			                       bytes_transfer_dummy, magic)
39511.54Skamil			                != -1);
39521.54Skamil			break;
39531.54Skamil		default:
39541.54Skamil			break;
39551.54Skamil		}
39561.54Skamil		break;
39571.54Skamil	case BYTES_TRANSFER_DATA:
39581.54Skamil		switch (operation) {
39591.54Skamil		case PT_READ_D:
39601.54Skamil		case PT_READ_I:
39611.54Skamil			errno = 0;
39621.54Skamil			lookup_me = ptrace(operation, child, &lookup_me, 0);
39631.54Skamil			ATF_REQUIRE_EQ(lookup_me, magic);
39641.54Skamil			SYSCALL_REQUIRE_ERRNO(errno, 0);
39651.54Skamil			break;
39661.54Skamil		case PT_WRITE_D:
39671.54Skamil		case PT_WRITE_I:
39681.54Skamil			lookup_me = magic;
39691.54Skamil			SYSCALL_REQUIRE(ptrace(operation, child, &lookup_me,
39701.54Skamil			                       magic) != -1);
39711.54Skamil			break;
39721.54Skamil		default:
39731.54Skamil			break;
39741.54Skamil		}
39751.54Skamil		break;
39761.54Skamil	default:
39771.54Skamil		break;
39781.54Skamil	}
39791.1Skamil
39801.13Schristos	DPRINTF("Before resuming the child process where it left off and "
39811.1Skamil	    "without signal to be sent\n");
39821.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
39831.1Skamil
39841.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
39851.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
39861.1Skamil
39871.1Skamil	validate_status_exited(status, exitval);
39881.1Skamil
39891.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
39901.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
39911.1Skamil}
39921.1Skamil
39931.61Skre#define BYTES_TRANSFER(test, operation, size, type)			\
39941.61SkreATF_TC(test);								\
39951.61SkreATF_TC_HEAD(test, tc)							\
39961.61Skre{									\
39971.61Skre	atf_tc_set_md_var(tc, "descr",					\
39981.61Skre	    "Verify bytes transfer operation" #operation " and size " #size \
39991.61Skre	    " of type " #type);						\
40001.61Skre}									\
40011.61Skre									\
40021.61SkreATF_TC_BODY(test, tc)							\
40031.61Skre{									\
40041.61Skre									\
40051.61Skre	bytes_transfer(operation, size, BYTES_TRANSFER_##type);		\
40061.1Skamil}
40071.1Skamil
40081.54Skamil// DATA
40091.1Skamil
40101.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_8, PIOD_READ_D, 8, DATAIO)
40111.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_16, PIOD_READ_D, 16, DATAIO)
40121.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_32, PIOD_READ_D, 32, DATAIO)
40131.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_64, PIOD_READ_D, 64, DATAIO)
40141.54Skamil
40151.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_8, PIOD_READ_I, 8, DATAIO)
40161.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_16, PIOD_READ_I, 16, DATAIO)
40171.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_32, PIOD_READ_I, 32, DATAIO)
40181.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_64, PIOD_READ_I, 64, DATAIO)
40191.54Skamil
40201.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_8, PIOD_WRITE_D, 8, DATAIO)
40211.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_16, PIOD_WRITE_D, 16, DATAIO)
40221.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_32, PIOD_WRITE_D, 32, DATAIO)
40231.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_64, PIOD_WRITE_D, 64, DATAIO)
40241.54Skamil
40251.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_8, PIOD_WRITE_I, 8, DATAIO)
40261.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_16, PIOD_WRITE_I, 16, DATAIO)
40271.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_32, PIOD_WRITE_I, 32, DATAIO)
40281.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_64, PIOD_WRITE_I, 64, DATAIO)
40291.54Skamil
40301.54SkamilBYTES_TRANSFER(bytes_transfer_read_d, PT_READ_D, 32, DATA)
40311.54SkamilBYTES_TRANSFER(bytes_transfer_read_i, PT_READ_I, 32, DATA)
40321.54SkamilBYTES_TRANSFER(bytes_transfer_write_d, PT_WRITE_D, 32, DATA)
40331.54SkamilBYTES_TRANSFER(bytes_transfer_write_i, PT_WRITE_I, 32, DATA)
40341.54Skamil
40351.54Skamil// TEXT
40361.54Skamil
40371.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_8_text, PIOD_READ_D, 8, TEXTIO)
40381.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_16_text, PIOD_READ_D, 16, TEXTIO)
40391.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_32_text, PIOD_READ_D, 32, TEXTIO)
40401.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_64_text, PIOD_READ_D, 64, TEXTIO)
40411.54Skamil
40421.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_8_text, PIOD_READ_I, 8, TEXTIO)
40431.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_16_text, PIOD_READ_I, 16, TEXTIO)
40441.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_32_text, PIOD_READ_I, 32, TEXTIO)
40451.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_64_text, PIOD_READ_I, 64, TEXTIO)
40461.54Skamil
40471.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_8_text, PIOD_WRITE_D, 8, TEXTIO)
40481.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_16_text, PIOD_WRITE_D, 16, TEXTIO)
40491.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_32_text, PIOD_WRITE_D, 32, TEXTIO)
40501.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_64_text, PIOD_WRITE_D, 64, TEXTIO)
40511.54Skamil
40521.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_8_text, PIOD_WRITE_I, 8, TEXTIO)
40531.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_16_text, PIOD_WRITE_I, 16, TEXTIO)
40541.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_32_text, PIOD_WRITE_I, 32, TEXTIO)
40551.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_64_text, PIOD_WRITE_I, 64, TEXTIO)
40561.54Skamil
40571.54SkamilBYTES_TRANSFER(bytes_transfer_read_d_text, PT_READ_D, 32, TEXT)
40581.54SkamilBYTES_TRANSFER(bytes_transfer_read_i_text, PT_READ_I, 32, TEXT)
40591.54SkamilBYTES_TRANSFER(bytes_transfer_write_d_text, PT_WRITE_D, 32, TEXT)
40601.54SkamilBYTES_TRANSFER(bytes_transfer_write_i_text, PT_WRITE_I, 32, TEXT)
40611.1Skamil
40621.54Skamil// AUXV
40631.1Skamil
40641.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_auxv, PIOD_READ_AUXV, 4096, AUXV)
40651.1Skamil
40661.54Skamil/// ----------------------------------------------------------------------------
40671.1Skamil
40681.101Skamilstatic void
40691.101Skamilbytes_transfer_alignment(const char *operation)
40701.101Skamil{
40711.101Skamil	const int exitval = 5;
40721.101Skamil	const int sigval = SIGSTOP;
40731.101Skamil	pid_t child, wpid;
40741.101Skamil#if defined(TWAIT_HAVE_STATUS)
40751.101Skamil	int status;
40761.101Skamil#endif
40771.101Skamil	char *buffer;
40781.101Skamil	int vector;
40791.101Skamil	size_t len;
40801.101Skamil	size_t i;
40811.101Skamil	int op;
40821.101Skamil
40831.101Skamil	struct ptrace_io_desc io;
40841.101Skamil	struct ptrace_siginfo info;
40851.101Skamil
40861.101Skamil	memset(&io, 0, sizeof(io));
40871.101Skamil	memset(&info, 0, sizeof(info));
40881.101Skamil
40891.101Skamil	/* Testing misaligned byte transfer crossing page boundaries */
40901.101Skamil	len = sysconf(_SC_PAGESIZE) * 2;
40911.101Skamil	buffer = malloc(len);
40921.101Skamil	ATF_REQUIRE(buffer != NULL);
40931.101Skamil
40941.101Skamil	/* Initialize the buffer with random data */
40951.101Skamil	for (i = 0; i < len; i++)
40961.101Skamil		buffer[i] = i & 0xff;
40971.101Skamil
40981.101Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
40991.101Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
41001.101Skamil	if (child == 0) {
41011.101Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
41021.101Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
41031.101Skamil
41041.101Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
41051.101Skamil		FORKEE_ASSERT(raise(sigval) == 0);
41061.101Skamil
41071.101Skamil		DPRINTF("Before exiting of the child process\n");
41081.101Skamil		_exit(exitval);
41091.101Skamil	}
41101.101Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
41111.101Skamil
41121.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
41131.101Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
41141.101Skamil
41151.101Skamil	validate_status_stopped(status, sigval);
41161.101Skamil
41171.101Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
41181.101Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info))
41191.101Skamil		!= -1);
41201.101Skamil
41211.101Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
41221.101Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
41231.101Skamil		"si_errno=%#x\n",
41241.101Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
41251.101Skamil		info.psi_siginfo.si_errno);
41261.101Skamil
41271.101Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
41281.101Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
41291.101Skamil
41301.101Skamil	if (strcmp(operation, "PT_READ_I") == 0 ||
41311.101Skamil	    strcmp(operation, "PT_READ_D") == 0) {
41321.101Skamil		if (strcmp(operation, "PT_READ_I"))
41331.101Skamil			op = PT_READ_I;
41341.101Skamil		else
41351.101Skamil			op = PT_READ_D;
41361.101Skamil
41371.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
41381.101Skamil			errno = 0;
41391.101Skamil			vector = ptrace(op, child, buffer + i, 0);
41401.101Skamil			ATF_REQUIRE_EQ(errno, 0);
41411.101Skamil			ATF_REQUIRE(!memcmp(&vector, buffer + i, sizeof(int)));
41421.101Skamil		}
41431.101Skamil	} else if (strcmp(operation, "PT_WRITE_I") == 0 ||
41441.101Skamil	           strcmp(operation, "PT_WRITE_D") == 0) {
41451.101Skamil		if (strcmp(operation, "PT_WRITE_I"))
41461.101Skamil			op = PT_WRITE_I;
41471.101Skamil		else
41481.101Skamil			op = PT_WRITE_D;
41491.101Skamil
41501.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
41511.101Skamil			memcpy(&vector, buffer + i, sizeof(int));
41521.101Skamil			SYSCALL_REQUIRE(ptrace(op, child, buffer + 1, vector)
41531.101Skamil			    != -1);
41541.101Skamil		}
41551.101Skamil	} else if (strcmp(operation, "PIOD_READ_I") == 0 ||
41561.101Skamil	           strcmp(operation, "PIOD_READ_D") == 0) {
41571.101Skamil		if (strcmp(operation, "PIOD_READ_I"))
41581.101Skamil			op = PIOD_READ_I;
41591.101Skamil		else
41601.101Skamil			op = PIOD_READ_D;
41611.101Skamil
41621.101Skamil		io.piod_op = op;
41631.101Skamil		io.piod_addr = &vector;
41641.101Skamil		io.piod_len = sizeof(int);
41651.101Skamil
41661.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
41671.101Skamil			io.piod_offs = buffer + i;
41681.101Skamil
41691.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
41701.101Skamil			                != -1);
41711.101Skamil			ATF_REQUIRE(!memcmp(&vector, buffer + i, sizeof(int)));
41721.101Skamil		}
41731.101Skamil	} else if (strcmp(operation, "PIOD_WRITE_I") == 0 ||
41741.101Skamil	           strcmp(operation, "PIOD_WRITE_D") == 0) {
41751.101Skamil		if (strcmp(operation, "PIOD_WRITE_I"))
41761.101Skamil			op = PIOD_WRITE_I;
41771.101Skamil		else
41781.101Skamil			op = PIOD_WRITE_D;
41791.101Skamil
41801.101Skamil		io.piod_op = op;
41811.101Skamil		io.piod_addr = &vector;
41821.101Skamil		io.piod_len = sizeof(int);
41831.101Skamil
41841.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
41851.101Skamil			io.piod_offs = buffer + i;
41861.101Skamil
41871.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
41881.101Skamil			                != -1);
41891.101Skamil		}
41901.101Skamil	} else if (strcmp(operation, "PIOD_READ_AUXV") == 0) {
41911.101Skamil		io.piod_op = PIOD_READ_AUXV;
41921.101Skamil		io.piod_addr = &vector;
41931.101Skamil		io.piod_len = sizeof(int);
41941.101Skamil
41951.101Skamil		errno = 0;
41961.101Skamil		i = 0;
41971.101Skamil		/* Read the whole AUXV vector, it has no clear length */
41981.120Skamil		while (io.piod_len > 0) {
41991.101Skamil			io.piod_offs = (void *)(intptr_t)i;
42001.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
42011.120Skamil			                != -1 || (io.piod_len == 0 && i > 0));
42021.101Skamil			++i;
42031.101Skamil		}
42041.101Skamil	}
42051.101Skamil
42061.101Skamil	DPRINTF("Before resuming the child process where it left off "
42071.101Skamil	    "and without signal to be sent\n");
42081.101Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
42091.101Skamil
42101.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
42111.101Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
42121.101Skamil	    child);
42131.101Skamil
42141.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
42151.101Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
42161.101Skamil}
42171.101Skamil
42181.101Skamil#define BYTES_TRANSFER_ALIGNMENT(test, operation)			\
42191.101SkamilATF_TC(test);								\
42201.101SkamilATF_TC_HEAD(test, tc)							\
42211.101Skamil{									\
42221.101Skamil	atf_tc_set_md_var(tc, "descr",					\
42231.101Skamil	    "Verify bytes transfer for potentially misaligned "		\
42241.101Skamil	    "operation " operation);					\
42251.101Skamil}									\
42261.101Skamil									\
42271.101SkamilATF_TC_BODY(test, tc)							\
42281.101Skamil{									\
42291.101Skamil									\
42301.101Skamil	bytes_transfer_alignment(operation);				\
42311.101Skamil}
42321.101Skamil
42331.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_read_i, "PT_READ_I")
42341.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_read_d, "PT_READ_D")
42351.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_write_i, "PT_WRITE_I")
42361.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_write_d, "PT_WRITE_D")
42371.101Skamil
42381.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_i, "PIOD_READ_I")
42391.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_d, "PIOD_READ_D")
42401.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_write_i, "PIOD_WRITE_I")
42411.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_write_d, "PIOD_WRITE_D")
42421.101Skamil
42431.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_auxv, "PIOD_READ_AUXV")
42441.101Skamil
42451.101Skamil/// ----------------------------------------------------------------------------
42461.101Skamil
42471.115Skamilstatic void
42481.115Skamilbytes_transfer_eof(const char *operation)
42491.115Skamil{
42501.115Skamil	const int exitval = 5;
42511.115Skamil	const int sigval = SIGSTOP;
42521.115Skamil	pid_t child, wpid;
42531.115Skamil#if defined(TWAIT_HAVE_STATUS)
42541.115Skamil	int status;
42551.115Skamil#endif
42561.115Skamil	FILE *fp;
42571.115Skamil	char *p;
42581.115Skamil	int vector;
42591.115Skamil	int op;
42601.115Skamil
42611.115Skamil	struct ptrace_io_desc io;
42621.115Skamil	struct ptrace_siginfo info;
42631.115Skamil
42641.115Skamil	memset(&io, 0, sizeof(io));
42651.115Skamil	memset(&info, 0, sizeof(info));
42661.115Skamil
42671.115Skamil	vector = 0;
42681.115Skamil
42691.115Skamil	fp = tmpfile();
42701.115Skamil	ATF_REQUIRE(fp != NULL);
42711.115Skamil
42721.115Skamil	p = mmap(0, 1, PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(fp), 0);
42731.115Skamil	ATF_REQUIRE(p != MAP_FAILED);
42741.115Skamil
42751.115Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
42761.115Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
42771.115Skamil	if (child == 0) {
42781.115Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
42791.115Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
42801.115Skamil
42811.115Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
42821.115Skamil		FORKEE_ASSERT(raise(sigval) == 0);
42831.115Skamil
42841.115Skamil		DPRINTF("Before exiting of the child process\n");
42851.115Skamil		_exit(exitval);
42861.115Skamil	}
42871.115Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
42881.115Skamil
42891.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
42901.115Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
42911.115Skamil
42921.115Skamil	validate_status_stopped(status, sigval);
42931.115Skamil
42941.115Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
42951.115Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info))
42961.115Skamil		!= -1);
42971.115Skamil
42981.115Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
42991.115Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
43001.115Skamil		"si_errno=%#x\n",
43011.115Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
43021.115Skamil		info.psi_siginfo.si_errno);
43031.115Skamil
43041.115Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
43051.115Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
43061.115Skamil
43071.115Skamil	if (strcmp(operation, "PT_READ_I") == 0 ||
43081.115Skamil	    strcmp(operation, "PT_READ_D") == 0) {
43091.115Skamil		if (strcmp(operation, "PT_READ_I"))
43101.115Skamil			op = PT_READ_I;
43111.115Skamil		else
43121.115Skamil			op = PT_READ_D;
43131.115Skamil
43141.115Skamil		errno = 0;
43151.115Skamil		SYSCALL_REQUIRE(ptrace(op, child, p, 0) == -1);
43161.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
43171.115Skamil	} else if (strcmp(operation, "PT_WRITE_I") == 0 ||
43181.115Skamil	           strcmp(operation, "PT_WRITE_D") == 0) {
43191.115Skamil		if (strcmp(operation, "PT_WRITE_I"))
43201.115Skamil			op = PT_WRITE_I;
43211.115Skamil		else
43221.115Skamil			op = PT_WRITE_D;
43231.115Skamil
43241.115Skamil		errno = 0;
43251.115Skamil		SYSCALL_REQUIRE(ptrace(op, child, p, vector) == -1);
43261.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
43271.115Skamil	} else if (strcmp(operation, "PIOD_READ_I") == 0 ||
43281.115Skamil	           strcmp(operation, "PIOD_READ_D") == 0) {
43291.115Skamil		if (strcmp(operation, "PIOD_READ_I"))
43301.115Skamil			op = PIOD_READ_I;
43311.115Skamil		else
43321.115Skamil			op = PIOD_READ_D;
43331.115Skamil
43341.115Skamil		io.piod_op = op;
43351.115Skamil		io.piod_addr = &vector;
43361.115Skamil		io.piod_len = sizeof(int);
43371.115Skamil		io.piod_offs = p;
43381.115Skamil
43391.115Skamil		errno = 0;
43401.115Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io)) == -1);
43411.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
43421.115Skamil	} else if (strcmp(operation, "PIOD_WRITE_I") == 0 ||
43431.115Skamil	           strcmp(operation, "PIOD_WRITE_D") == 0) {
43441.115Skamil		if (strcmp(operation, "PIOD_WRITE_I"))
43451.115Skamil			op = PIOD_WRITE_I;
43461.115Skamil		else
43471.115Skamil			op = PIOD_WRITE_D;
43481.115Skamil
43491.115Skamil		io.piod_op = op;
43501.115Skamil		io.piod_addr = &vector;
43511.115Skamil		io.piod_len = sizeof(int);
43521.115Skamil		io.piod_offs = p;
43531.115Skamil
43541.115Skamil		errno = 0;
43551.115Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io)) == -1);
43561.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
43571.115Skamil	}
43581.115Skamil
43591.115Skamil	DPRINTF("Before resuming the child process where it left off "
43601.115Skamil	    "and without signal to be sent\n");
43611.115Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
43621.115Skamil
43631.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
43641.115Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
43651.115Skamil	    child);
43661.115Skamil
43671.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
43681.115Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
43691.115Skamil}
43701.115Skamil
43711.115Skamil#define BYTES_TRANSFER_EOF(test, operation)				\
43721.115SkamilATF_TC(test);								\
43731.115SkamilATF_TC_HEAD(test, tc)							\
43741.115Skamil{									\
43751.115Skamil	atf_tc_set_md_var(tc, "descr",					\
43761.115Skamil	    "Verify bytes EOF byte transfer for the " operation		\
43771.115Skamil	    " operation");						\
43781.115Skamil}									\
43791.115Skamil									\
43801.115SkamilATF_TC_BODY(test, tc)							\
43811.115Skamil{									\
43821.115Skamil									\
43831.115Skamil	bytes_transfer_eof(operation);					\
43841.115Skamil}
43851.115Skamil
43861.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_read_i, "PT_READ_I")
43871.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_read_d, "PT_READ_D")
43881.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_write_i, "PT_WRITE_I")
43891.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_write_d, "PT_WRITE_D")
43901.115Skamil
43911.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_read_i, "PIOD_READ_I")
43921.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_read_d, "PIOD_READ_D")
43931.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_i, "PIOD_WRITE_I")
43941.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_d, "PIOD_WRITE_D")
43951.115Skamil
43961.115Skamil/// ----------------------------------------------------------------------------
43971.115Skamil
43981.76Sscole#if defined(HAVE_GPREGS) || defined(HAVE_FPREGS)
43991.72Skamilstatic void
44001.72Skamilaccess_regs(const char *regset, const char *aux)
44011.1Skamil{
44021.1Skamil	const int exitval = 5;
44031.1Skamil	const int sigval = SIGSTOP;
44041.1Skamil	pid_t child, wpid;
44051.1Skamil#if defined(TWAIT_HAVE_STATUS)
44061.1Skamil	int status;
44071.1Skamil#endif
44081.72Skamil#if defined(HAVE_GPREGS)
44091.72Skamil	struct reg gpr;
44101.76Sscole	register_t rgstr;
44111.1Skamil#endif
44121.72Skamil#if defined(HAVE_FPREGS)
44131.72Skamil	struct fpreg fpr;
44141.1Skamil#endif
44151.76Sscole
44161.72Skamil#if !defined(HAVE_GPREGS)
44171.72Skamil	if (strcmp(regset, "regs") == 0)
44181.72Skamil		atf_tc_fail("Impossible test scenario!");
44191.1Skamil#endif
44201.1Skamil
44211.72Skamil#if !defined(HAVE_FPREGS)
44221.72Skamil	if (strcmp(regset, "fpregs") == 0)
44231.72Skamil		atf_tc_fail("Impossible test scenario!");
44241.1Skamil#endif
44251.1Skamil
44261.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
44271.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
44281.1Skamil	if (child == 0) {
44291.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
44301.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
44311.1Skamil
44321.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
44331.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
44341.1Skamil
44351.13Schristos		DPRINTF("Before exiting of the child process\n");
44361.1Skamil		_exit(exitval);
44371.1Skamil	}
44381.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
44391.1Skamil
44401.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
44411.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
44421.1Skamil
44431.1Skamil	validate_status_stopped(status, sigval);
44441.1Skamil
44451.1Skamil#if defined(HAVE_GPREGS)
44461.72Skamil	if (strcmp(regset, "regs") == 0) {
44471.72Skamil		DPRINTF("Call GETREGS for the child process\n");
44481.72Skamil		SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1);
44491.72Skamil
44501.72Skamil		if (strcmp(aux, "none") == 0) {
44511.72Skamil			DPRINTF("Retrieved registers\n");
44521.72Skamil		} else if (strcmp(aux, "pc") == 0) {
44531.72Skamil			rgstr = PTRACE_REG_PC(&gpr);
44541.72Skamil			DPRINTF("Retrieved %" PRIxREGISTER "\n", rgstr);
44551.72Skamil		} else if (strcmp(aux, "set_pc") == 0) {
44561.72Skamil			rgstr = PTRACE_REG_PC(&gpr);
44571.72Skamil			PTRACE_REG_SET_PC(&gpr, rgstr);
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.72Skamil			    ptrace(PT_GETREGS, 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.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
44921.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
44931.1Skamil
44941.1Skamil	validate_status_exited(status, exitval);
44951.1Skamil
44961.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
44971.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
44981.1Skamil}
44991.1Skamil
45001.72Skamil#define ACCESS_REGS(test, regset, aux)					\
45011.72SkamilATF_TC(test);								\
45021.72SkamilATF_TC_HEAD(test, tc)							\
45031.72Skamil{									\
45041.72Skamil        atf_tc_set_md_var(tc, "descr",					\
45051.72Skamil            "Verify " regset " with auxiliary operation: " aux);	\
45061.72Skamil}									\
45071.72Skamil									\
45081.72SkamilATF_TC_BODY(test, tc)							\
45091.72Skamil{									\
45101.72Skamil									\
45111.72Skamil        access_regs(regset, aux);					\
45121.1Skamil}
45131.1Skamil#endif
45141.1Skamil
45151.72Skamil#if defined(HAVE_GPREGS)
45161.72SkamilACCESS_REGS(access_regs1, "regs", "none")
45171.72SkamilACCESS_REGS(access_regs2, "regs", "pc")
45181.72SkamilACCESS_REGS(access_regs3, "regs", "set_pc")
45191.72SkamilACCESS_REGS(access_regs4, "regs", "sp")
45201.72SkamilACCESS_REGS(access_regs5, "regs", "intrv")
45211.72SkamilACCESS_REGS(access_regs6, "regs", "setregs")
45221.1Skamil#endif
45231.1Skamil#if defined(HAVE_FPREGS)
45241.72SkamilACCESS_REGS(access_fpregs1, "fpregs", "getfpregs")
45251.72SkamilACCESS_REGS(access_fpregs2, "fpregs", "setfpregs")
45261.1Skamil#endif
45271.1Skamil
45281.72Skamil/// ----------------------------------------------------------------------------
45291.1Skamil
45301.1Skamil#if defined(PT_STEP)
45311.1Skamilstatic void
45321.95Skamilptrace_step(int N, int setstep, bool masked, bool ignored)
45331.1Skamil{
45341.1Skamil	const int exitval = 5;
45351.1Skamil	const int sigval = SIGSTOP;
45361.1Skamil	pid_t child, wpid;
45371.1Skamil#if defined(TWAIT_HAVE_STATUS)
45381.1Skamil	int status;
45391.1Skamil#endif
45401.1Skamil	int happy;
45411.95Skamil	struct sigaction sa;
45421.81Skamil	struct ptrace_siginfo info;
45431.95Skamil	sigset_t intmask;
45441.95Skamil	struct kinfo_proc2 kp;
45451.95Skamil	size_t len = sizeof(kp);
45461.95Skamil
45471.95Skamil	int name[6];
45481.95Skamil	const size_t namelen = __arraycount(name);
45491.95Skamil	ki_sigset_t kp_sigmask;
45501.95Skamil	ki_sigset_t kp_sigignore;
45511.1Skamil
45521.1Skamil#if defined(__arm__)
45531.1Skamil	/* PT_STEP not supported on arm 32-bit */
45541.1Skamil	atf_tc_expect_fail("PR kern/52119");
45551.1Skamil#endif
45561.1Skamil
45571.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
45581.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
45591.1Skamil	if (child == 0) {
45601.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
45611.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
45621.1Skamil
45631.95Skamil		if (masked) {
45641.95Skamil			sigemptyset(&intmask);
45651.95Skamil			sigaddset(&intmask, SIGTRAP);
45661.95Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
45671.95Skamil		}
45681.95Skamil
45691.95Skamil		if (ignored) {
45701.95Skamil			memset(&sa, 0, sizeof(sa));
45711.95Skamil			sa.sa_handler = SIG_IGN;
45721.95Skamil			sigemptyset(&sa.sa_mask);
45731.95Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
45741.95Skamil		}
45751.95Skamil
45761.1Skamil		happy = check_happy(999);
45771.1Skamil
45781.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
45791.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
45801.1Skamil
45811.1Skamil		FORKEE_ASSERT_EQ(happy, check_happy(999));
45821.1Skamil
45831.13Schristos		DPRINTF("Before exiting of the child process\n");
45841.1Skamil		_exit(exitval);
45851.1Skamil	}
45861.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
45871.1Skamil
45881.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
45891.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
45901.1Skamil
45911.1Skamil	validate_status_stopped(status, sigval);
45921.1Skamil
45931.81Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
45941.81Skamil	SYSCALL_REQUIRE(
45951.81Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
45961.81Skamil
45971.81Skamil	DPRINTF("Before checking siginfo_t\n");
45981.81Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
45991.81Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
46001.81Skamil
46011.95Skamil	name[0] = CTL_KERN,
46021.95Skamil	name[1] = KERN_PROC2,
46031.95Skamil	name[2] = KERN_PROC_PID;
46041.95Skamil	name[3] = child;
46051.95Skamil	name[4] = sizeof(kp);
46061.95Skamil	name[5] = 1;
46071.95Skamil
46081.95Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
46091.95Skamil
46101.95Skamil	if (masked)
46111.95Skamil		kp_sigmask = kp.p_sigmask;
46121.95Skamil
46131.95Skamil	if (ignored)
46141.95Skamil		kp_sigignore = kp.p_sigignore;
46151.95Skamil
46161.1Skamil	while (N --> 0) {
46171.2Skamil		if (setstep) {
46181.13Schristos			DPRINTF("Before resuming the child process where it "
46191.2Skamil			    "left off and without signal to be sent (use "
46201.9Skamil			    "PT_SETSTEP and PT_CONTINUE)\n");
46211.13Schristos			SYSCALL_REQUIRE(ptrace(PT_SETSTEP, child, 0, 0) != -1);
46221.13Schristos			SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0)
46231.2Skamil			    != -1);
46241.2Skamil		} else {
46251.13Schristos			DPRINTF("Before resuming the child process where it "
46261.2Skamil			    "left off and without signal to be sent (use "
46271.2Skamil			    "PT_STEP)\n");
46281.13Schristos			SYSCALL_REQUIRE(ptrace(PT_STEP, child, (void *)1, 0)
46291.2Skamil			    != -1);
46301.2Skamil		}
46311.1Skamil
46321.13Schristos		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46331.1Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
46341.1Skamil		    child);
46351.1Skamil
46361.1Skamil		validate_status_stopped(status, SIGTRAP);
46371.2Skamil
46381.81Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
46391.81Skamil		SYSCALL_REQUIRE(
46401.81Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
46411.81Skamil
46421.81Skamil		DPRINTF("Before checking siginfo_t\n");
46431.81Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
46441.81Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_TRACE);
46451.81Skamil
46461.2Skamil		if (setstep) {
46471.13Schristos			SYSCALL_REQUIRE(ptrace(PT_CLEARSTEP, child, 0, 0) != -1);
46481.2Skamil		}
46491.95Skamil
46501.95Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
46511.95Skamil
46521.95Skamil		if (masked) {
46531.95Skamil			DPRINTF("kp_sigmask="
46541.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
46551.95Skamil			    PRIx32 "\n",
46561.95Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
46571.95Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
46581.95Skamil
46591.95Skamil			DPRINTF("kp.p_sigmask="
46601.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
46611.95Skamil			    PRIx32 "\n",
46621.95Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
46631.95Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
46641.95Skamil
46651.95Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
46661.95Skamil			    sizeof(kp_sigmask)));
46671.95Skamil		}
46681.95Skamil
46691.95Skamil		if (ignored) {
46701.95Skamil			DPRINTF("kp_sigignore="
46711.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
46721.95Skamil			    PRIx32 "\n",
46731.95Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
46741.95Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
46751.95Skamil
46761.95Skamil			DPRINTF("kp.p_sigignore="
46771.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
46781.95Skamil			    PRIx32 "\n",
46791.95Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
46801.95Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
46811.95Skamil
46821.95Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
46831.95Skamil			    sizeof(kp_sigignore)));
46841.95Skamil		}
46851.1Skamil	}
46861.1Skamil
46871.13Schristos	DPRINTF("Before resuming the child process where it left off and "
46881.1Skamil	    "without signal to be sent\n");
46891.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
46901.1Skamil
46911.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46921.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
46931.1Skamil
46941.1Skamil	validate_status_exited(status, exitval);
46951.1Skamil
46961.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46971.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
46981.1Skamil}
46991.1Skamil
47001.73Skamil#define PTRACE_STEP(test, N, setstep)					\
47011.73SkamilATF_TC(test);								\
47021.73SkamilATF_TC_HEAD(test, tc)							\
47031.73Skamil{									\
47041.73Skamil        atf_tc_set_md_var(tc, "descr",					\
47051.74Skamil            "Verify " #N " (PT_SETSTEP set to: " #setstep ")");		\
47061.73Skamil}									\
47071.73Skamil									\
47081.73SkamilATF_TC_BODY(test, tc)							\
47091.73Skamil{									\
47101.73Skamil									\
47111.95Skamil        ptrace_step(N, setstep, false, false);				\
47121.1Skamil}
47131.1Skamil
47141.73SkamilPTRACE_STEP(step1, 1, 0)
47151.73SkamilPTRACE_STEP(step2, 2, 0)
47161.73SkamilPTRACE_STEP(step3, 3, 0)
47171.73SkamilPTRACE_STEP(step4, 4, 0)
47181.73SkamilPTRACE_STEP(setstep1, 1, 1)
47191.73SkamilPTRACE_STEP(setstep2, 2, 1)
47201.73SkamilPTRACE_STEP(setstep3, 3, 1)
47211.73SkamilPTRACE_STEP(setstep4, 4, 1)
47221.95Skamil
47231.95SkamilATF_TC(step_signalmasked);
47241.95SkamilATF_TC_HEAD(step_signalmasked, tc)
47251.95Skamil{
47261.95Skamil	atf_tc_set_md_var(tc, "descr", "Verify PT_STEP with masked SIGTRAP");
47271.95Skamil}
47281.95Skamil
47291.95SkamilATF_TC_BODY(step_signalmasked, tc)
47301.95Skamil{
47311.95Skamil
47321.95Skamil	ptrace_step(1, 0, true, false);
47331.95Skamil}
47341.95Skamil
47351.95SkamilATF_TC(step_signalignored);
47361.95SkamilATF_TC_HEAD(step_signalignored, tc)
47371.95Skamil{
47381.95Skamil	atf_tc_set_md_var(tc, "descr", "Verify PT_STEP with ignored SIGTRAP");
47391.95Skamil}
47401.95Skamil
47411.95SkamilATF_TC_BODY(step_signalignored, tc)
47421.95Skamil{
47431.95Skamil
47441.95Skamil	ptrace_step(1, 0, false, true);
47451.95Skamil}
47461.1Skamil#endif
47471.1Skamil
47481.73Skamil/// ----------------------------------------------------------------------------
47491.1Skamil
47501.75Skamilstatic void
47511.75Skamilptrace_kill(const char *type)
47521.1Skamil{
47531.75Skamil	const int sigval = SIGSTOP;
47541.1Skamil	pid_t child, wpid;
47551.1Skamil#if defined(TWAIT_HAVE_STATUS)
47561.1Skamil	int status;
47571.1Skamil#endif
47581.1Skamil
47591.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
47601.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
47611.1Skamil	if (child == 0) {
47621.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
47631.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
47641.1Skamil
47651.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
47661.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
47671.1Skamil
47681.1Skamil		/* NOTREACHED */
47691.1Skamil		FORKEE_ASSERTX(0 &&
47701.1Skamil		    "Child should be terminated by a signal from its parent");
47711.1Skamil	}
47721.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
47731.1Skamil
47741.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
47751.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
47761.1Skamil
47771.1Skamil	validate_status_stopped(status, sigval);
47781.1Skamil
47791.75Skamil	DPRINTF("Before killing the child process with %s\n", type);
47801.75Skamil	if (strcmp(type, "ptrace(PT_KILL)") == 0) {
47811.75Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void*)1, 0) != -1);
47821.75Skamil	} else if (strcmp(type, "kill(SIGKILL)") == 0) {
47831.75Skamil		kill(child, SIGKILL);
47841.75Skamil	} else if (strcmp(type, "killpg(SIGKILL)") == 0) {
47851.75Skamil		setpgid(child, 0);
47861.75Skamil		killpg(getpgid(child), SIGKILL);
47871.75Skamil	}
47881.1Skamil
47891.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
47901.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
47911.1Skamil
47921.75Skamil	validate_status_signaled(status, SIGKILL, 0);
47931.1Skamil
47941.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
47951.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
47961.1Skamil}
47971.1Skamil
47981.75Skamil#define PTRACE_KILL(test, type)						\
47991.75SkamilATF_TC(test);								\
48001.75SkamilATF_TC_HEAD(test, tc)							\
48011.75Skamil{									\
48021.75Skamil        atf_tc_set_md_var(tc, "descr",					\
48031.75Skamil            "Verify killing the child with " type);			\
48041.75Skamil}									\
48051.75Skamil									\
48061.75SkamilATF_TC_BODY(test, tc)							\
48071.75Skamil{									\
48081.75Skamil									\
48091.75Skamil        ptrace_kill(type);						\
48101.1Skamil}
48111.1Skamil
48121.75Skamil// PT_CONTINUE with SIGKILL is covered by traceme_sendsignal_simple1
48131.75SkamilPTRACE_KILL(kill1, "ptrace(PT_KILL)")
48141.75SkamilPTRACE_KILL(kill2, "kill(SIGKILL)")
48151.75SkamilPTRACE_KILL(kill3, "killpg(SIGKILL)")
48161.1Skamil
48171.75Skamil/// ----------------------------------------------------------------------------
48181.1Skamil
48191.77Skamilstatic void
48201.77Skamiltraceme_lwpinfo(const int threads)
48211.1Skamil{
48221.1Skamil	const int sigval = SIGSTOP;
48231.77Skamil	const int sigval2 = SIGINT;
48241.1Skamil	pid_t child, wpid;
48251.1Skamil#if defined(TWAIT_HAVE_STATUS)
48261.1Skamil	int status;
48271.1Skamil#endif
48281.77Skamil	struct ptrace_lwpinfo lwp = {0, 0};
48291.77Skamil	struct ptrace_siginfo info;
48301.77Skamil
48311.77Skamil	/* Maximum number of supported threads in this test */
48321.77Skamil	pthread_t t[3];
48331.77Skamil	int n, rv;
48341.77Skamil
48351.77Skamil	ATF_REQUIRE((int)__arraycount(t) >= threads);
48361.1Skamil
48371.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
48381.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
48391.1Skamil	if (child == 0) {
48401.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
48411.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
48421.1Skamil
48431.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
48441.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
48451.1Skamil
48461.77Skamil		for (n = 0; n < threads; n++) {
48471.77Skamil			rv = pthread_create(&t[n], NULL, infinite_thread, NULL);
48481.77Skamil			FORKEE_ASSERT(rv == 0);
48491.77Skamil		}
48501.77Skamil
48511.77Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval2));
48521.77Skamil		FORKEE_ASSERT(raise(sigval2) == 0);
48531.77Skamil
48541.77Skamil		/* NOTREACHED */
48551.77Skamil		FORKEE_ASSERTX(0 && "Not reached");
48561.1Skamil	}
48571.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
48581.1Skamil
48591.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48601.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
48611.1Skamil
48621.1Skamil	validate_status_stopped(status, sigval);
48631.1Skamil
48641.77Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
48651.77Skamil	SYSCALL_REQUIRE(
48661.77Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
48671.77Skamil
48681.77Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
48691.77Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
48701.77Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
48711.77Skamil	    info.psi_siginfo.si_errno);
48721.77Skamil
48731.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
48741.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
48751.77Skamil
48761.13Schristos	DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
48771.77Skamil	SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
48781.1Skamil
48791.77Skamil	DPRINTF("Assert that there exists a single thread only\n");
48801.77Skamil	ATF_REQUIRE(lwp.pl_lwpid > 0);
48811.1Skamil
48821.13Schristos	DPRINTF("Assert that lwp thread %d received event PL_EVENT_SIGNAL\n",
48831.77Skamil	    lwp.pl_lwpid);
48841.77Skamil	FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
48851.1Skamil
48861.13Schristos	DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
48871.77Skamil	SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
48881.1Skamil
48891.77Skamil	DPRINTF("Assert that there exists a single thread only\n");
48901.77Skamil	ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
48911.1Skamil
48921.13Schristos	DPRINTF("Before resuming the child process where it left off and "
48931.1Skamil	    "without signal to be sent\n");
48941.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
48951.1Skamil
48961.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48971.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
48981.1Skamil
48991.77Skamil	validate_status_stopped(status, sigval2);
49001.77Skamil
49011.77Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
49021.77Skamil	SYSCALL_REQUIRE(
49031.77Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
49041.77Skamil
49051.77Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
49061.77Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
49071.77Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
49081.77Skamil	    info.psi_siginfo.si_errno);
49091.77Skamil
49101.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval2);
49111.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
49121.77Skamil
49131.77Skamil	memset(&lwp, 0, sizeof(lwp));
49141.77Skamil
49151.77Skamil	for (n = 0; n <= threads; n++) {
49161.77Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
49171.77Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
49181.77Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
49191.77Skamil
49201.77Skamil		DPRINTF("Assert that the thread exists\n");
49211.77Skamil		ATF_REQUIRE(lwp.pl_lwpid > 0);
49221.77Skamil
49231.77Skamil		DPRINTF("Assert that lwp thread %d received expected event\n",
49241.77Skamil		    lwp.pl_lwpid);
49251.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, info.psi_lwpid == lwp.pl_lwpid ?
49261.77Skamil		    PL_EVENT_SIGNAL : PL_EVENT_NONE);
49271.77Skamil	}
49281.77Skamil	DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
49291.77Skamil	SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
49301.77Skamil	DPRINTF("LWP=%d\n", lwp.pl_lwpid);
49311.77Skamil
49321.77Skamil	DPRINTF("Assert that there are no more threads\n");
49331.77Skamil	ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
49341.77Skamil
49351.77Skamil	DPRINTF("Before resuming the child process where it left off and "
49361.77Skamil	    "without signal to be sent\n");
49371.77Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, SIGKILL) != -1);
49381.77Skamil
49391.77Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
49401.77Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
49411.77Skamil
49421.77Skamil	validate_status_signaled(status, SIGKILL, 0);
49431.1Skamil
49441.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
49451.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
49461.1Skamil}
49471.1Skamil
49481.77Skamil#define TRACEME_LWPINFO(test, threads)					\
49491.77SkamilATF_TC(test);								\
49501.77SkamilATF_TC_HEAD(test, tc)							\
49511.77Skamil{									\
49521.77Skamil	atf_tc_set_md_var(tc, "descr",					\
49531.77Skamil	    "Verify LWPINFO with the child with " #threads		\
49541.77Skamil	    " spawned extra threads");					\
49551.77Skamil}									\
49561.77Skamil									\
49571.77SkamilATF_TC_BODY(test, tc)							\
49581.77Skamil{									\
49591.77Skamil									\
49601.77Skamil	traceme_lwpinfo(threads);					\
49611.1Skamil}
49621.1Skamil
49631.77SkamilTRACEME_LWPINFO(traceme_lwpinfo0, 0)
49641.77SkamilTRACEME_LWPINFO(traceme_lwpinfo1, 1)
49651.77SkamilTRACEME_LWPINFO(traceme_lwpinfo2, 2)
49661.77SkamilTRACEME_LWPINFO(traceme_lwpinfo3, 3)
49671.77Skamil
49681.77Skamil/// ----------------------------------------------------------------------------
49691.77Skamil
49701.77Skamil#if defined(TWAIT_HAVE_PID)
49711.77Skamilstatic void
49721.77Skamilattach_lwpinfo(const int threads)
49731.1Skamil{
49741.77Skamil	const int sigval = SIGINT;
49751.1Skamil	struct msg_fds parent_tracee, parent_tracer;
49761.1Skamil	const int exitval_tracer = 10;
49771.1Skamil	pid_t tracee, tracer, wpid;
49781.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
49791.1Skamil#if defined(TWAIT_HAVE_STATUS)
49801.1Skamil	int status;
49811.1Skamil#endif
49821.77Skamil	struct ptrace_lwpinfo lwp = {0, 0};
49831.77Skamil	struct ptrace_siginfo info;
49841.77Skamil
49851.77Skamil	/* Maximum number of supported threads in this test */
49861.77Skamil	pthread_t t[3];
49871.77Skamil	int n, rv;
49881.1Skamil
49891.13Schristos	DPRINTF("Spawn tracee\n");
49901.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
49911.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
49921.1Skamil	tracee = atf_utils_fork();
49931.1Skamil	if (tracee == 0) {
49941.1Skamil		/* Wait for message from the parent */
49951.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
49961.1Skamil
49971.77Skamil		CHILD_FROM_PARENT("spawn threads", parent_tracee, msg);
49981.77Skamil
49991.77Skamil		for (n = 0; n < threads; n++) {
50001.77Skamil			rv = pthread_create(&t[n], NULL, infinite_thread, NULL);
50011.77Skamil			FORKEE_ASSERT(rv == 0);
50021.77Skamil		}
50031.77Skamil
50041.77Skamil		CHILD_TO_PARENT("tracee exit", parent_tracee, msg);
50051.77Skamil
50061.77Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
50071.77Skamil		FORKEE_ASSERT(raise(sigval) == 0);
50081.77Skamil
50091.77Skamil		/* NOTREACHED */
50101.77Skamil		FORKEE_ASSERTX(0 && "Not reached");
50111.1Skamil	}
50121.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
50131.1Skamil
50141.13Schristos	DPRINTF("Spawn debugger\n");
50151.1Skamil	tracer = atf_utils_fork();
50161.1Skamil	if (tracer == 0) {
50171.1Skamil		/* No IPC to communicate with the child */
50181.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
50191.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
50201.1Skamil
50211.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
50221.1Skamil		FORKEE_REQUIRE_SUCCESS(
50231.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
50241.1Skamil
50251.1Skamil		forkee_status_stopped(status, SIGSTOP);
50261.1Skamil
50271.77Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
50281.77Skamil		    "tracee");
50291.77Skamil		FORKEE_ASSERT(
50301.77Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
50311.77Skamil
50321.77Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
50331.77Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
50341.77Skamil		    "si_errno=%#x\n",
50351.77Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
50361.77Skamil		    info.psi_siginfo.si_errno);
50371.77Skamil
50381.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
50391.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
50401.77Skamil
50411.13Schristos		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
50421.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
50431.1Skamil		    != -1);
50441.1Skamil
50451.13Schristos		DPRINTF("Assert that there exists a thread\n");
50461.77Skamil		FORKEE_ASSERTX(lwp.pl_lwpid > 0);
50471.1Skamil
50481.13Schristos		DPRINTF("Assert that lwp thread %d received event "
50491.77Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
50501.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
50511.1Skamil
50521.77Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
50531.77Skamil		    "tracee\n");
50541.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
50551.1Skamil		    != -1);
50561.1Skamil
50571.77Skamil		DPRINTF("Assert that there are no more lwp threads in "
50581.77Skamil		    "tracee\n");
50591.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
50601.1Skamil
50611.1Skamil		/* Resume tracee with PT_CONTINUE */
50621.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
50631.1Skamil
50641.1Skamil		/* Inform parent that tracer has attached to tracee */
50651.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
50661.77Skamil
50671.1Skamil		/* Wait for parent */
50681.1Skamil		CHILD_FROM_PARENT("tracer wait", parent_tracer, msg);
50691.1Skamil
50701.77Skamil		/* Wait for tracee and assert that it raised a signal */
50711.77Skamil		FORKEE_REQUIRE_SUCCESS(
50721.77Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
50731.77Skamil
50741.77Skamil		forkee_status_stopped(status, SIGINT);
50751.77Skamil
50761.77Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
50771.77Skamil		    "child");
50781.77Skamil		FORKEE_ASSERT(
50791.77Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
50801.77Skamil
50811.77Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
50821.77Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
50831.77Skamil		    "si_errno=%#x\n",
50841.77Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
50851.77Skamil		    info.psi_siginfo.si_errno);
50861.77Skamil
50871.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
50881.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
50891.77Skamil
50901.77Skamil		memset(&lwp, 0, sizeof(lwp));
50911.77Skamil
50921.77Skamil		for (n = 0; n <= threads; n++) {
50931.77Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
50941.77Skamil			    "child\n");
50951.77Skamil			FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp,
50961.77Skamil			    sizeof(lwp)) != -1);
50971.77Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
50981.77Skamil
50991.77Skamil			DPRINTF("Assert that the thread exists\n");
51001.77Skamil			FORKEE_ASSERT(lwp.pl_lwpid > 0);
51011.77Skamil
51021.77Skamil			DPRINTF("Assert that lwp thread %d received expected "
51031.77Skamil			    "event\n", lwp.pl_lwpid);
51041.77Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
51051.77Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
51061.77Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
51071.77Skamil		}
51081.77Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
51091.77Skamil		    "tracee\n");
51101.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
51111.77Skamil		    != -1);
51121.77Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
51131.77Skamil
51141.77Skamil		DPRINTF("Assert that there are no more threads\n");
51151.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
51161.77Skamil
51171.77Skamil		DPRINTF("Before resuming the child process where it left off "
51181.77Skamil		    "and without signal to be sent\n");
51191.77Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, SIGKILL)
51201.77Skamil		    != -1);
51211.77Skamil
51221.1Skamil		/* Wait for tracee and assert that it exited */
51231.1Skamil		FORKEE_REQUIRE_SUCCESS(
51241.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
51251.1Skamil
51261.77Skamil		forkee_status_signaled(status, SIGKILL, 0);
51271.1Skamil
51281.13Schristos		DPRINTF("Before exiting of the tracer process\n");
51291.1Skamil		_exit(exitval_tracer);
51301.1Skamil	}
51311.1Skamil
51321.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
51331.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
51341.1Skamil
51351.77Skamil	DPRINTF("Resume the tracee and spawn threads\n");
51361.77Skamil	PARENT_TO_CHILD("spawn threads", parent_tracee, msg);
51371.77Skamil
51381.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
51391.77Skamil	PARENT_FROM_CHILD("tracee exit", parent_tracee, msg);
51401.1Skamil
51411.77Skamil	DPRINTF("Resume the tracer and let it detect multiple threads\n");
51421.1Skamil	PARENT_TO_CHILD("tracer wait", parent_tracer, msg);
51431.1Skamil
51441.13Schristos	DPRINTF("Wait for tracer to finish its job and exit - calling %s()\n",
51451.1Skamil	    TWAIT_FNAME);
51461.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
51471.1Skamil	    tracer);
51481.1Skamil
51491.1Skamil	validate_status_exited(status, exitval_tracer);
51501.1Skamil
51511.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
51521.1Skamil	    TWAIT_FNAME);
51531.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
51541.1Skamil	    tracee);
51551.1Skamil
51561.77Skamil	validate_status_signaled(status, SIGKILL, 0);
51571.1Skamil
51581.1Skamil	msg_close(&parent_tracer);
51591.1Skamil	msg_close(&parent_tracee);
51601.1Skamil}
51611.77Skamil
51621.77Skamil#define ATTACH_LWPINFO(test, threads)					\
51631.77SkamilATF_TC(test);								\
51641.77SkamilATF_TC_HEAD(test, tc)							\
51651.77Skamil{									\
51661.77Skamil	atf_tc_set_md_var(tc, "descr",					\
51671.77Skamil	    "Verify LWPINFO with the child with " #threads		\
51681.77Skamil	    " spawned extra threads (tracer is not the original "	\
51691.77Skamil	    "parent)");							\
51701.77Skamil}									\
51711.77Skamil									\
51721.77SkamilATF_TC_BODY(test, tc)							\
51731.77Skamil{									\
51741.77Skamil									\
51751.77Skamil	attach_lwpinfo(threads);					\
51761.77Skamil}
51771.77Skamil
51781.77SkamilATTACH_LWPINFO(attach_lwpinfo0, 0)
51791.77SkamilATTACH_LWPINFO(attach_lwpinfo1, 1)
51801.77SkamilATTACH_LWPINFO(attach_lwpinfo2, 2)
51811.77SkamilATTACH_LWPINFO(attach_lwpinfo3, 3)
51821.1Skamil#endif
51831.1Skamil
51841.77Skamil/// ----------------------------------------------------------------------------
51851.77Skamil
51861.1Skamilstatic void
51871.79Skamilptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c), int *signal_caught)
51881.1Skamil{
51891.1Skamil	const int exitval = 5;
51901.1Skamil	const int sigval = SIGINT;
51911.1Skamil	const int sigfaked = SIGTRAP;
51921.1Skamil	const int sicodefaked = TRAP_BRKPT;
51931.1Skamil	pid_t child, wpid;
51941.1Skamil	struct sigaction sa;
51951.1Skamil#if defined(TWAIT_HAVE_STATUS)
51961.1Skamil	int status;
51971.1Skamil#endif
51981.1Skamil	struct ptrace_siginfo info;
51991.1Skamil	memset(&info, 0, sizeof(info));
52001.1Skamil
52011.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
52021.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
52031.1Skamil	if (child == 0) {
52041.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
52051.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
52061.1Skamil
52071.79Skamil		sa.sa_sigaction = sah;
52081.1Skamil		sa.sa_flags = SA_SIGINFO;
52091.1Skamil		sigemptyset(&sa.sa_mask);
52101.1Skamil
52111.79Skamil		FORKEE_ASSERT(sigaction(faked ? sigfaked : sigval, &sa, NULL)
52121.79Skamil		    != -1);
52131.1Skamil
52141.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
52151.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
52161.1Skamil
52171.79Skamil		FORKEE_ASSERT_EQ(*signal_caught, 1);
52181.1Skamil
52191.13Schristos		DPRINTF("Before exiting of the child process\n");
52201.1Skamil		_exit(exitval);
52211.1Skamil	}
52221.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
52231.1Skamil
52241.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
52251.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
52261.1Skamil
52271.1Skamil	validate_status_stopped(status, sigval);
52281.1Skamil
52291.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
52301.61Skre	SYSCALL_REQUIRE(
52311.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
52321.1Skamil
52331.13Schristos	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
52341.13Schristos	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
52351.1Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
52361.1Skamil	    info.psi_siginfo.si_errno);
52371.1Skamil
52381.79Skamil	if (faked) {
52391.79Skamil		DPRINTF("Before setting new faked signal to signo=%d "
52401.79Skamil		    "si_code=%d\n", sigfaked, sicodefaked);
52411.79Skamil		info.psi_siginfo.si_signo = sigfaked;
52421.79Skamil		info.psi_siginfo.si_code = sicodefaked;
52431.79Skamil	}
52441.1Skamil
52451.13Schristos	DPRINTF("Before calling ptrace(2) with PT_SET_SIGINFO for child\n");
52461.61Skre	SYSCALL_REQUIRE(
52471.61Skre	    ptrace(PT_SET_SIGINFO, child, &info, sizeof(info)) != -1);
52481.1Skamil
52491.79Skamil	if (faked) {
52501.79Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
52511.79Skamil		    "child\n");
52521.79Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
52531.79Skamil		    sizeof(info)) != -1);
52541.1Skamil
52551.79Skamil		DPRINTF("Before checking siginfo_t\n");
52561.79Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigfaked);
52571.79Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, sicodefaked);
52581.79Skamil	}
52591.1Skamil
52601.13Schristos	DPRINTF("Before resuming the child process where it left off and "
52611.1Skamil	    "without signal to be sent\n");
52621.79Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
52631.79Skamil	    faked ? sigfaked : sigval) != -1);
52641.1Skamil
52651.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
52661.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
52671.1Skamil
52681.1Skamil	validate_status_exited(status, exitval);
52691.1Skamil
52701.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
52711.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
52721.1Skamil}
52731.1Skamil
52741.79Skamil#define PTRACE_SIGINFO(test, faked)					\
52751.79SkamilATF_TC(test);								\
52761.79SkamilATF_TC_HEAD(test, tc)							\
52771.79Skamil{									\
52781.79Skamil	atf_tc_set_md_var(tc, "descr",					\
52791.79Skamil	    "Verify basic PT_GET_SIGINFO and PT_SET_SIGINFO calls"	\
52801.79Skamil	    "with%s setting signal to new value", faked ? "" : "out");	\
52811.79Skamil}									\
52821.79Skamil									\
52831.79Skamilstatic int test##_caught = 0;						\
52841.79Skamil									\
52851.79Skamilstatic void								\
52861.79Skamiltest##_sighandler(int sig, siginfo_t *info, void *ctx)			\
52871.79Skamil{									\
52881.79Skamil	if (faked) {							\
52891.79Skamil		FORKEE_ASSERT_EQ(sig, SIGTRAP);				\
52901.79Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGTRAP);		\
52911.79Skamil		FORKEE_ASSERT_EQ(info->si_code, TRAP_BRKPT);		\
52921.79Skamil	} else {							\
52931.79Skamil		FORKEE_ASSERT_EQ(sig, SIGINT);				\
52941.79Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGINT);		\
52951.79Skamil		FORKEE_ASSERT_EQ(info->si_code, SI_LWP);		\
52961.79Skamil	}								\
52971.79Skamil									\
52981.79Skamil	++ test##_caught;						\
52991.79Skamil}									\
53001.79Skamil									\
53011.79SkamilATF_TC_BODY(test, tc)							\
53021.79Skamil{									\
53031.79Skamil									\
53041.79Skamil	ptrace_siginfo(faked, test##_sighandler, & test##_caught); 	\
53051.79Skamil}
53061.79Skamil
53071.79SkamilPTRACE_SIGINFO(siginfo_set_unmodified, false)
53081.79SkamilPTRACE_SIGINFO(siginfo_set_faked, true)
53091.79Skamil
53101.79Skamil/// ----------------------------------------------------------------------------
53111.79Skamil
53121.97Skamilstatic void
53131.97Skamiltraceme_exec(bool masked, bool ignored)
53141.1Skamil{
53151.1Skamil	const int sigval = SIGTRAP;
53161.1Skamil	pid_t child, wpid;
53171.1Skamil#if defined(TWAIT_HAVE_STATUS)
53181.1Skamil	int status;
53191.1Skamil#endif
53201.97Skamil	struct sigaction sa;
53211.97Skamil	struct ptrace_siginfo info;
53221.97Skamil	sigset_t intmask;
53231.97Skamil	struct kinfo_proc2 kp;
53241.97Skamil	size_t len = sizeof(kp);
53251.97Skamil
53261.97Skamil	int name[6];
53271.97Skamil	const size_t namelen = __arraycount(name);
53281.97Skamil	ki_sigset_t kp_sigmask;
53291.97Skamil	ki_sigset_t kp_sigignore;
53301.1Skamil
53311.1Skamil	memset(&info, 0, sizeof(info));
53321.1Skamil
53331.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
53341.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
53351.1Skamil	if (child == 0) {
53361.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
53371.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
53381.1Skamil
53391.97Skamil		if (masked) {
53401.97Skamil			sigemptyset(&intmask);
53411.97Skamil			sigaddset(&intmask, sigval);
53421.97Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
53431.97Skamil		}
53441.97Skamil
53451.97Skamil		if (ignored) {
53461.97Skamil			memset(&sa, 0, sizeof(sa));
53471.97Skamil			sa.sa_handler = SIG_IGN;
53481.97Skamil			sigemptyset(&sa.sa_mask);
53491.97Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
53501.97Skamil		}
53511.97Skamil
53521.13Schristos		DPRINTF("Before calling execve(2) from child\n");
53531.1Skamil		execlp("/bin/echo", "/bin/echo", NULL);
53541.1Skamil
53551.1Skamil		FORKEE_ASSERT(0 && "Not reached");
53561.1Skamil	}
53571.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
53581.1Skamil
53591.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
53601.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
53611.1Skamil
53621.1Skamil	validate_status_stopped(status, sigval);
53631.1Skamil
53641.97Skamil	name[0] = CTL_KERN,
53651.97Skamil	name[1] = KERN_PROC2,
53661.97Skamil	name[2] = KERN_PROC_PID;
53671.97Skamil	name[3] = getpid();
53681.97Skamil	name[4] = sizeof(kp);
53691.97Skamil	name[5] = 1;
53701.97Skamil
53711.97Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
53721.97Skamil
53731.97Skamil	if (masked)
53741.97Skamil		kp_sigmask = kp.p_sigmask;
53751.97Skamil
53761.97Skamil	if (ignored)
53771.97Skamil		kp_sigignore = kp.p_sigignore;
53781.97Skamil
53791.97Skamil	name[3] = getpid();
53801.97Skamil
53811.97Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
53821.97Skamil
53831.97Skamil	if (masked) {
53841.97Skamil		DPRINTF("kp_sigmask="
53851.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
53861.97Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
53871.97Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
53881.97Skamil
53891.97Skamil		DPRINTF("kp.p_sigmask="
53901.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
53911.97Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
53921.97Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
53931.97Skamil
53941.97Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
53951.97Skamil		    sizeof(kp_sigmask)));
53961.97Skamil	}
53971.97Skamil
53981.97Skamil	if (ignored) {
53991.97Skamil		DPRINTF("kp_sigignore="
54001.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
54011.97Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
54021.97Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
54031.97Skamil
54041.97Skamil		DPRINTF("kp.p_sigignore="
54051.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
54061.97Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
54071.97Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
54081.97Skamil
54091.97Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
54101.97Skamil		    sizeof(kp_sigignore)));
54111.97Skamil	}
54121.97Skamil
54131.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
54141.61Skre	SYSCALL_REQUIRE(
54151.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
54161.1Skamil
54171.13Schristos	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
54181.13Schristos	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
54191.1Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
54201.1Skamil	    info.psi_siginfo.si_errno);
54211.1Skamil
54221.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
54231.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
54241.1Skamil
54251.13Schristos	DPRINTF("Before resuming the child process where it left off and "
54261.1Skamil	    "without signal to be sent\n");
54271.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
54281.1Skamil
54291.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
54301.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
54311.1Skamil
54321.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
54331.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
54341.1Skamil}
54351.1Skamil
54361.97Skamil#define TRACEME_EXEC(test, masked, ignored)				\
54371.97SkamilATF_TC(test);								\
54381.97SkamilATF_TC_HEAD(test, tc)							\
54391.97Skamil{									\
54401.97Skamil       atf_tc_set_md_var(tc, "descr",					\
54411.97Skamil           "Detect SIGTRAP TRAP_EXEC from "				\
54421.97Skamil           "child%s%s", masked ? " with masked signal" : "",		\
54431.97Skamil           masked ? " with ignored signal" : "");			\
54441.97Skamil}									\
54451.97Skamil									\
54461.97SkamilATF_TC_BODY(test, tc)							\
54471.97Skamil{									\
54481.97Skamil									\
54491.97Skamil       traceme_exec(masked, ignored);					\
54501.97Skamil}
54511.97Skamil
54521.97SkamilTRACEME_EXEC(traceme_exec, false, false)
54531.97SkamilTRACEME_EXEC(traceme_signalmasked_exec, true, false)
54541.97SkamilTRACEME_EXEC(traceme_signalignored_exec, false, true)
54551.97Skamil
54561.82Skamil/// ----------------------------------------------------------------------------
54571.82Skamil
54581.83Skamilstatic volatile int done;
54591.1Skamil
54601.83Skamilstatic void *
54611.83Skamiltrace_threads_cb(void *arg __unused)
54621.1Skamil{
54631.1Skamil
54641.83Skamil	done++;
54651.83Skamil
54661.83Skamil	while (done < 3)
54671.83Skamil		continue;
54681.83Skamil
54691.83Skamil	return NULL;
54701.1Skamil}
54711.1Skamil
54721.83Skamilstatic void
54731.83Skamiltrace_threads(bool trace_create, bool trace_exit)
54741.1Skamil{
54751.1Skamil	const int sigval = SIGSTOP;
54761.1Skamil	pid_t child, wpid;
54771.1Skamil#if defined(TWAIT_HAVE_STATUS)
54781.1Skamil	int status;
54791.1Skamil#endif
54801.1Skamil	ptrace_state_t state;
54811.1Skamil	const int slen = sizeof(state);
54821.1Skamil	ptrace_event_t event;
54831.1Skamil	const int elen = sizeof(event);
54841.83Skamil	struct ptrace_siginfo info;
54851.83Skamil
54861.83Skamil	pthread_t t[3];
54871.83Skamil	int rv;
54881.83Skamil	size_t n;
54891.1Skamil	lwpid_t lid;
54901.83Skamil
54911.83Skamil	/* Track created and exited threads */
54921.83Skamil	bool traced_lwps[__arraycount(t)];
54931.83Skamil
54941.128Skamil#if !TEST_LWP_ENABLED
54951.120Skamil	if (trace_create || trace_exit)
54961.119Skamil		atf_tc_skip("PR kern/51995");
54971.128Skamil#endif
54981.1Skamil
54991.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
55001.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
55011.1Skamil	if (child == 0) {
55021.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
55031.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
55041.1Skamil
55051.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
55061.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
55071.1Skamil
55081.83Skamil		for (n = 0; n < __arraycount(t); n++) {
55091.83Skamil			rv = pthread_create(&t[n], NULL, trace_threads_cb,
55101.83Skamil			    NULL);
55111.83Skamil			FORKEE_ASSERT(rv == 0);
55121.83Skamil		}
55131.1Skamil
55141.83Skamil		for (n = 0; n < __arraycount(t); n++) {
55151.83Skamil			rv = pthread_join(t[n], NULL);
55161.83Skamil			FORKEE_ASSERT(rv == 0);
55171.83Skamil		}
55181.1Skamil
55191.83Skamil		/*
55201.83Skamil		 * There is race between _exit() and pthread_join() detaching
55211.83Skamil		 * a thread. For simplicity kill the process after detecting
55221.83Skamil		 * LWP events.
55231.83Skamil		 */
55241.83Skamil		while (true)
55251.83Skamil			continue;
55261.1Skamil
55271.83Skamil		FORKEE_ASSERT(0 && "Not reached");
55281.1Skamil	}
55291.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
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_stopped(status, sigval);
55351.1Skamil
55361.83Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
55371.83Skamil	SYSCALL_REQUIRE(
55381.83Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
55391.1Skamil
55401.83Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
55411.83Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
55421.83Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
55431.83Skamil	    info.psi_siginfo.si_errno);
55441.1Skamil
55451.83Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
55461.83Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
55471.1Skamil
55481.83Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
55491.83Skamil	memset(&event, 0, sizeof(event));
55501.83Skamil	if (trace_create)
55511.83Skamil		event.pe_set_event |= PTRACE_LWP_CREATE;
55521.83Skamil	if (trace_exit)
55531.83Skamil		event.pe_set_event |= PTRACE_LWP_EXIT;
55541.83Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
55551.1Skamil
55561.13Schristos	DPRINTF("Before resuming the child process where it left off and "
55571.1Skamil	    "without signal to be sent\n");
55581.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
55591.1Skamil
55601.83Skamil	memset(traced_lwps, 0, sizeof(traced_lwps));
55611.1Skamil
55621.83Skamil	for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
55631.83Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
55641.83Skamil		    "SIGTRAP\n", TWAIT_FNAME);
55651.83Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
55661.83Skamil		    child);
55671.1Skamil
55681.83Skamil		validate_status_stopped(status, SIGTRAP);
55691.1Skamil
55701.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
55711.83Skamil		    "child\n");
55721.83Skamil		SYSCALL_REQUIRE(
55731.83Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
55741.1Skamil
55751.83Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
55761.83Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
55771.83Skamil		    "si_errno=%#x\n",
55781.83Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
55791.83Skamil		    info.psi_siginfo.si_errno);
55801.1Skamil
55811.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
55821.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
55831.1Skamil
55841.83Skamil		SYSCALL_REQUIRE(
55851.83Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
55861.1Skamil
55871.83Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
55881.83Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
55891.1Skamil
55901.83Skamil		lid = state.pe_lwp;
55911.83Skamil		DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
55921.1Skamil
55931.83Skamil		traced_lwps[lid - 1] = true;
55941.1Skamil
55951.83Skamil		DPRINTF("Before resuming the child process where it left off "
55961.83Skamil		    "and without signal to be sent\n");
55971.83Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
55981.83Skamil	}
55991.1Skamil
56001.83Skamil	for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
56011.83Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
56021.83Skamil		    "SIGTRAP\n", TWAIT_FNAME);
56031.83Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
56041.83Skamil		    child);
56051.1Skamil
56061.83Skamil		validate_status_stopped(status, SIGTRAP);
56071.1Skamil
56081.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
56091.83Skamil		    "child\n");
56101.83Skamil		SYSCALL_REQUIRE(
56111.83Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
56121.1Skamil
56131.83Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
56141.83Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
56151.83Skamil		    "si_errno=%#x\n",
56161.83Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
56171.83Skamil		    info.psi_siginfo.si_errno);
56181.1Skamil
56191.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
56201.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
56211.1Skamil
56221.83Skamil		SYSCALL_REQUIRE(
56231.83Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
56241.1Skamil
56251.83Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
56261.83Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
56271.1Skamil
56281.83Skamil		lid = state.pe_lwp;
56291.83Skamil		DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
56301.1Skamil
56311.83Skamil		if (trace_create) {
56321.83Skamil			ATF_REQUIRE(traced_lwps[lid - 1] == true);
56331.83Skamil			traced_lwps[lid - 1] = false;
56341.83Skamil		}
56351.1Skamil
56361.83Skamil		DPRINTF("Before resuming the child process where it left off "
56371.83Skamil		    "and without signal to be sent\n");
56381.83Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
56391.83Skamil	}
56401.1Skamil
56411.83Skamil	kill(child, SIGKILL);
56421.1Skamil
56431.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
56441.1Skamil	    TWAIT_FNAME);
56451.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
56461.1Skamil
56471.83Skamil	validate_status_signaled(status, SIGKILL, 0);
56481.1Skamil
56491.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
56501.1Skamil	    TWAIT_FNAME);
56511.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
56521.1Skamil}
56531.1Skamil
56541.83Skamil#define TRACE_THREADS(test, trace_create, trace_exit)			\
56551.83SkamilATF_TC(test);								\
56561.83SkamilATF_TC_HEAD(test, tc)							\
56571.83Skamil{									\
56581.83Skamil        atf_tc_set_md_var(tc, "descr",					\
56591.83Skamil            "Verify spawning threads with%s tracing LWP create and"	\
56601.83Skamil	    "with%s tracing LWP exit", trace_create ? "" : "out",	\
56611.83Skamil	    trace_exit ? "" : "out");					\
56621.83Skamil}									\
56631.83Skamil									\
56641.83SkamilATF_TC_BODY(test, tc)							\
56651.83Skamil{									\
56661.83Skamil									\
56671.83Skamil        trace_threads(trace_create, trace_exit);			\
56681.83Skamil}
56691.83Skamil
56701.119SkamilTRACE_THREADS(trace_thread_nolwpevents, false, false)
56711.119SkamilTRACE_THREADS(trace_thread_lwpexit, false, true)
56721.119SkamilTRACE_THREADS(trace_thread_lwpcreate, true, false)
56731.119SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true)
56741.83Skamil
56751.83Skamil/// ----------------------------------------------------------------------------
56761.83Skamil
56771.84SkamilATF_TC(signal_mask_unrelated);
56781.84SkamilATF_TC_HEAD(signal_mask_unrelated, tc)
56791.1Skamil{
56801.1Skamil	atf_tc_set_md_var(tc, "descr",
56811.1Skamil	    "Verify that masking single unrelated signal does not stop tracer "
56821.1Skamil	    "from catching other signals");
56831.1Skamil}
56841.1Skamil
56851.84SkamilATF_TC_BODY(signal_mask_unrelated, tc)
56861.1Skamil{
56871.1Skamil	const int exitval = 5;
56881.1Skamil	const int sigval = SIGSTOP;
56891.1Skamil	const int sigmasked = SIGTRAP;
56901.1Skamil	const int signotmasked = SIGINT;
56911.1Skamil	pid_t child, wpid;
56921.1Skamil#if defined(TWAIT_HAVE_STATUS)
56931.1Skamil	int status;
56941.1Skamil#endif
56951.1Skamil	sigset_t intmask;
56961.1Skamil
56971.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
56981.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
56991.1Skamil	if (child == 0) {
57001.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
57011.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
57021.1Skamil
57031.1Skamil		sigemptyset(&intmask);
57041.1Skamil		sigaddset(&intmask, sigmasked);
57051.1Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
57061.1Skamil
57071.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
57081.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
57091.1Skamil
57101.13Schristos		DPRINTF("Before raising %s from child\n",
57111.1Skamil		    strsignal(signotmasked));
57121.1Skamil		FORKEE_ASSERT(raise(signotmasked) == 0);
57131.1Skamil
57141.13Schristos		DPRINTF("Before exiting of the child process\n");
57151.1Skamil		_exit(exitval);
57161.1Skamil	}
57171.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
57181.1Skamil
57191.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
57201.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
57211.1Skamil
57221.1Skamil	validate_status_stopped(status, sigval);
57231.1Skamil
57241.13Schristos	DPRINTF("Before resuming the child process where it left off and "
57251.1Skamil	    "without signal to be sent\n");
57261.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
57271.1Skamil
57281.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
57291.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
57301.1Skamil
57311.1Skamil	validate_status_stopped(status, signotmasked);
57321.1Skamil
57331.13Schristos	DPRINTF("Before resuming the child process where it left off and "
57341.1Skamil	    "without signal to be sent\n");
57351.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
57361.1Skamil
57371.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
57381.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
57391.1Skamil
57401.1Skamil	validate_status_exited(status, exitval);
57411.1Skamil
57421.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
57431.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
57441.1Skamil}
57451.1Skamil
57461.84Skamil/// ----------------------------------------------------------------------------
57471.84Skamil
57481.1Skamil#if defined(TWAIT_HAVE_PID)
57491.99Skamilstatic void
57501.126Skamilfork2_body(const char *fn, bool masked, bool ignored)
57511.1Skamil{
57521.1Skamil	const int exitval = 5;
57531.126Skamil	const int exitval2 = 0; /* Match exit status from /bin/echo */
57541.1Skamil	const int sigval = SIGSTOP;
57551.99Skamil	pid_t child, child2 = 0, wpid;
57561.1Skamil#if defined(TWAIT_HAVE_STATUS)
57571.1Skamil	int status;
57581.1Skamil#endif
57591.1Skamil	ptrace_state_t state;
57601.1Skamil	const int slen = sizeof(state);
57611.1Skamil	ptrace_event_t event;
57621.1Skamil	const int elen = sizeof(event);
57631.99Skamil	struct sigaction sa;
57641.99Skamil	struct ptrace_siginfo info;
57651.99Skamil	sigset_t intmask;
57661.99Skamil	struct kinfo_proc2 kp;
57671.99Skamil	size_t len = sizeof(kp);
57681.99Skamil
57691.99Skamil	int name[6];
57701.99Skamil	const size_t namelen = __arraycount(name);
57711.99Skamil	ki_sigset_t kp_sigmask;
57721.99Skamil	ki_sigset_t kp_sigignore;
57731.1Skamil
57741.126Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
57751.14Schristos
57761.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
57771.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
57781.1Skamil	if (child == 0) {
57791.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
57801.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
57811.1Skamil
57821.99Skamil		if (masked) {
57831.99Skamil			sigemptyset(&intmask);
57841.99Skamil			sigaddset(&intmask, SIGTRAP);
57851.99Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
57861.99Skamil		}
57871.99Skamil
57881.99Skamil		if (ignored) {
57891.99Skamil			memset(&sa, 0, sizeof(sa));
57901.99Skamil			sa.sa_handler = SIG_IGN;
57911.99Skamil			sigemptyset(&sa.sa_mask);
57921.99Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
57931.99Skamil		}
57941.1Skamil
57951.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
57961.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
57971.1Skamil
57981.126Skamil		if (strcmp(fn, "spawn") == 0) {
57991.126Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
58001.126Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
58011.126Skamil		} else  {
58021.126Skamil			if (strcmp(fn, "fork") == 0) {
58031.126Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
58041.126Skamil			} else {
58051.126Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
58061.126Skamil			}
58071.126Skamil			if (child2 == 0)
58081.126Skamil				_exit(exitval2);
58091.126Skamil		}
58101.1Skamil
58111.1Skamil		FORKEE_REQUIRE_SUCCESS
58121.99Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
58131.1Skamil
58141.1Skamil		forkee_status_exited(status, exitval2);
58151.1Skamil
58161.13Schristos		DPRINTF("Before exiting of the child process\n");
58171.1Skamil		_exit(exitval);
58181.1Skamil	}
58191.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
58201.1Skamil
58211.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
58221.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
58231.1Skamil
58241.1Skamil	validate_status_stopped(status, sigval);
58251.1Skamil
58261.99Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
58271.99Skamil	SYSCALL_REQUIRE(
58281.99Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
58291.99Skamil
58301.99Skamil	DPRINTF("Before checking siginfo_t\n");
58311.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
58321.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
58331.1Skamil
58341.99Skamil	name[0] = CTL_KERN,
58351.99Skamil	name[1] = KERN_PROC2,
58361.99Skamil	name[2] = KERN_PROC_PID;
58371.99Skamil	name[3] = child;
58381.99Skamil	name[4] = sizeof(kp);
58391.99Skamil	name[5] = 1;
58401.1Skamil
58411.99Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
58421.1Skamil
58431.99Skamil	if (masked)
58441.99Skamil		kp_sigmask = kp.p_sigmask;
58451.1Skamil
58461.99Skamil	if (ignored)
58471.99Skamil		kp_sigignore = kp.p_sigignore;
58481.1Skamil
58491.126Skamil	DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
58501.126Skamil	    strcmp(fn, "spawn") == 0 ? "|PTRACE_POSIX_SPAWN" : "",
58511.126Skamil	    strcmp(fn, "fork") == 0 ? "|PTRACE_FORK" : "",
58521.126Skamil	    strcmp(fn, "vfork") == 0 ? "|PTRACE_VFORK" : "",
58531.126Skamil	    strcmp(fn, "vforkdone") == 0 ? "|PTRACE_VFORK_DONE" : "", child);
58541.99Skamil	event.pe_set_event = 0;
58551.126Skamil	if (strcmp(fn, "spawn") == 0)
58561.126Skamil		event.pe_set_event |= PTRACE_POSIX_SPAWN;
58571.126Skamil	if (strcmp(fn, "fork") == 0)
58581.99Skamil		event.pe_set_event |= PTRACE_FORK;
58591.126Skamil	if (strcmp(fn, "vfork") == 0)
58601.99Skamil		event.pe_set_event |= PTRACE_VFORK;
58611.126Skamil	if (strcmp(fn, "vforkdone") == 0)
58621.99Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
58631.99Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
58641.1Skamil
58651.99Skamil	DPRINTF("Before resuming the child process where it left off and "
58661.99Skamil	    "without signal to be sent\n");
58671.99Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
58681.1Skamil
58691.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
58701.126Skamil	    strcmp(fn, "vfork") == 0) {
58711.99Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
58721.99Skamil		    child);
58731.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
58741.99Skamil		    child);
58751.1Skamil
58761.99Skamil		validate_status_stopped(status, SIGTRAP);
58771.1Skamil
58781.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
58791.1Skamil
58801.99Skamil		if (masked) {
58811.99Skamil			DPRINTF("kp_sigmask="
58821.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
58831.99Skamil			    PRIx32 "\n",
58841.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
58851.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
58861.1Skamil
58871.99Skamil			DPRINTF("kp.p_sigmask="
58881.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
58891.99Skamil			    PRIx32 "\n",
58901.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
58911.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
58921.1Skamil
58931.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
58941.99Skamil			    sizeof(kp_sigmask)));
58951.99Skamil		}
58961.1Skamil
58971.99Skamil		if (ignored) {
58981.99Skamil			DPRINTF("kp_sigignore="
58991.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
59001.99Skamil			    PRIx32 "\n",
59011.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
59021.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
59031.1Skamil
59041.99Skamil			DPRINTF("kp.p_sigignore="
59051.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
59061.99Skamil			    PRIx32 "\n",
59071.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
59081.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
59091.1Skamil
59101.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
59111.99Skamil			    sizeof(kp_sigignore)));
59121.99Skamil		}
59131.1Skamil
59141.99Skamil		SYSCALL_REQUIRE(
59151.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
59161.126Skamil		if (strcmp(fn, "spawn") == 0) {
59171.126Skamil			ATF_REQUIRE_EQ(
59181.126Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
59191.126Skamil			       PTRACE_POSIX_SPAWN);
59201.126Skamil		}
59211.126Skamil		if (strcmp(fn, "fork") == 0) {
59221.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
59231.99Skamil			       PTRACE_FORK);
59241.99Skamil		}
59251.126Skamil		if (strcmp(fn, "vfork") == 0) {
59261.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
59271.99Skamil			       PTRACE_VFORK);
59281.99Skamil		}
59291.1Skamil
59301.99Skamil		child2 = state.pe_other_pid;
59311.99Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
59321.1Skamil
59331.99Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
59341.99Skamil		    "%d\n", TWAIT_FNAME, child2, child);
59351.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
59361.99Skamil		    child2);
59371.1Skamil
59381.99Skamil		validate_status_stopped(status, SIGTRAP);
59391.1Skamil
59401.99Skamil		name[3] = child2;
59411.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
59421.1Skamil
59431.99Skamil		if (masked) {
59441.99Skamil			DPRINTF("kp_sigmask="
59451.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
59461.99Skamil			    PRIx32 "\n",
59471.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
59481.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
59491.1Skamil
59501.99Skamil			DPRINTF("kp.p_sigmask="
59511.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
59521.99Skamil			    PRIx32 "\n",
59531.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
59541.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
59551.14Schristos
59561.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
59571.99Skamil			    sizeof(kp_sigmask)));
59581.99Skamil		}
59591.1Skamil
59601.99Skamil		if (ignored) {
59611.99Skamil			DPRINTF("kp_sigignore="
59621.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
59631.99Skamil			    PRIx32 "\n",
59641.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
59651.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
59661.1Skamil
59671.99Skamil			DPRINTF("kp.p_sigignore="
59681.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
59691.99Skamil			    PRIx32 "\n",
59701.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
59711.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
59721.1Skamil
59731.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
59741.99Skamil			    sizeof(kp_sigignore)));
59751.99Skamil		}
59761.1Skamil
59771.99Skamil		SYSCALL_REQUIRE(
59781.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
59791.126Skamil		if (strcmp(fn, "spawn") == 0) {
59801.126Skamil			ATF_REQUIRE_EQ(
59811.126Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
59821.126Skamil			       PTRACE_POSIX_SPAWN);
59831.126Skamil		}
59841.126Skamil		if (strcmp(fn, "fork") == 0) {
59851.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
59861.99Skamil			       PTRACE_FORK);
59871.99Skamil		}
59881.126Skamil		if (strcmp(fn, "vfork") == 0) {
59891.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
59901.99Skamil			       PTRACE_VFORK);
59911.99Skamil		}
59921.1Skamil
59931.99Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
59941.1Skamil
59951.99Skamil		DPRINTF("Before resuming the forkee process where it left off "
59961.99Skamil		    "and without signal to be sent\n");
59971.99Skamil		SYSCALL_REQUIRE(
59981.99Skamil		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
59991.1Skamil
60001.99Skamil		DPRINTF("Before resuming the child process where it left off "
60011.99Skamil		    "and without signal to be sent\n");
60021.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
60031.1Skamil	}
60041.1Skamil
60051.126Skamil	if (strcmp(fn, "vforkdone") == 0) {
60061.99Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
60071.99Skamil		    child);
60081.99Skamil		TWAIT_REQUIRE_SUCCESS(
60091.99Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
60101.1Skamil
60111.99Skamil		validate_status_stopped(status, SIGTRAP);
60121.1Skamil
60131.99Skamil		name[3] = child;
60141.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
60151.1Skamil
60161.102Skamil		/*
60171.102Skamil		 * SIGCHLD is now pending in the signal queue and
60181.102Skamil		 * the kernel presents it to userland as a masked signal.
60191.102Skamil		 */
60201.102Skamil		sigdelset((sigset_t *)&kp.p_sigmask, SIGCHLD);
60211.102Skamil
60221.99Skamil		if (masked) {
60231.99Skamil			DPRINTF("kp_sigmask="
60241.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
60251.99Skamil			    PRIx32 "\n",
60261.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
60271.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
60281.1Skamil
60291.99Skamil			DPRINTF("kp.p_sigmask="
60301.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
60311.99Skamil			    PRIx32 "\n",
60321.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
60331.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
60341.1Skamil
60351.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
60361.99Skamil			    sizeof(kp_sigmask)));
60371.99Skamil		}
60381.1Skamil
60391.99Skamil		if (ignored) {
60401.99Skamil			DPRINTF("kp_sigignore="
60411.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
60421.99Skamil			    PRIx32 "\n",
60431.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
60441.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
60451.1Skamil
60461.99Skamil			DPRINTF("kp.p_sigignore="
60471.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
60481.99Skamil			    PRIx32 "\n",
60491.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
60501.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
60511.1Skamil
60521.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
60531.99Skamil			    sizeof(kp_sigignore)));
60541.99Skamil		}
60551.1Skamil
60561.99Skamil		SYSCALL_REQUIRE(
60571.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
60581.99Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
60591.1Skamil
60601.99Skamil		child2 = state.pe_other_pid;
60611.99Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
60621.99Skamil		    child2);
60631.1Skamil
60641.99Skamil		DPRINTF("Before resuming the child process where it left off "
60651.99Skamil		    "and without signal to be sent\n");
60661.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
60671.99Skamil	}
60681.1Skamil
60691.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
60701.126Skamil	    strcmp(fn, "vfork") == 0) {
60711.99Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
60721.99Skamil		    "\n", TWAIT_FNAME);
60731.99Skamil		TWAIT_REQUIRE_SUCCESS(
60741.99Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
60751.1Skamil
60761.99Skamil		validate_status_exited(status, exitval2);
60771.1Skamil
60781.99Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
60791.99Skamil		    "process\n", TWAIT_FNAME);
60801.99Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
60811.99Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
60821.99Skamil	}
60831.1Skamil
60841.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
60851.1Skamil	    "SIGCHLD\n", TWAIT_FNAME);
60861.57Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
60871.1Skamil
60881.1Skamil	validate_status_stopped(status, SIGCHLD);
60891.1Skamil
60901.57Skamil	DPRINTF("Before resuming the child process where it left off and "
60911.1Skamil	    "without signal to be sent\n");
60921.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
60931.1Skamil
60941.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
60951.1Skamil	    TWAIT_FNAME);
60961.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
60971.1Skamil
60981.1Skamil	validate_status_exited(status, exitval);
60991.1Skamil
61001.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
61011.57Skamil	    TWAIT_FNAME);
61021.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
61031.1Skamil}
61041.1Skamil
61051.126Skamil#define FORK2_TEST(name,fn,masked,ignored)				\
61061.99SkamilATF_TC(name);								\
61071.99SkamilATF_TC_HEAD(name, tc)							\
61081.99Skamil{									\
61091.126Skamil	atf_tc_set_md_var(tc, "descr", "Verify that " fn " is caught "	\
61101.99Skamil	    "regardless of signal %s%s", 				\
61111.99Skamil	    masked ? "masked" : "", ignored ? "ignored" : "");		\
61121.99Skamil}									\
61131.99Skamil									\
61141.99SkamilATF_TC_BODY(name, tc)							\
61151.99Skamil{									\
61161.99Skamil									\
61171.126Skamil	fork2_body(fn, masked, ignored);				\
61181.1Skamil}
61191.1Skamil
61201.126SkamilFORK2_TEST(posix_spawn_singalmasked, "spawn", true, false)
61211.126SkamilFORK2_TEST(posix_spawn_singalignored, "spawn", false, true)
61221.126SkamilFORK2_TEST(fork_singalmasked, "fork", true, false)
61231.126SkamilFORK2_TEST(fork_singalignored, "fork", false, true)
61241.110Skamil#if TEST_VFORK_ENABLED
61251.126SkamilFORK2_TEST(vfork_singalmasked, "vfork", true, false)
61261.126SkamilFORK2_TEST(vfork_singalignored, "vfork", false, true)
61271.126SkamilFORK2_TEST(vforkdone_singalmasked, "vforkdone", true, false)
61281.126SkamilFORK2_TEST(vforkdone_singalignored, "vforkdone", false, true)
61291.1Skamil#endif
61301.110Skamil#endif
61311.1Skamil
61321.99Skamil/// ----------------------------------------------------------------------------
61331.1Skamil
61341.83Skamilvolatile lwpid_t the_lwp_id = 0;
61351.83Skamil
61361.83Skamilstatic void
61371.83Skamillwp_main_func(void *arg)
61381.83Skamil{
61391.83Skamil	the_lwp_id = _lwp_self();
61401.83Skamil	_lwp_exit();
61411.83Skamil}
61421.83Skamil
61431.1SkamilATF_TC(signal9);
61441.1SkamilATF_TC_HEAD(signal9, tc)
61451.1Skamil{
61461.1Skamil	atf_tc_set_md_var(tc, "descr",
61471.1Skamil	    "Verify that masking SIGTRAP in tracee does not stop tracer from "
61481.1Skamil	    "catching PTRACE_LWP_CREATE breakpoint");
61491.1Skamil}
61501.1Skamil
61511.1SkamilATF_TC_BODY(signal9, tc)
61521.1Skamil{
61531.1Skamil	const int exitval = 5;
61541.1Skamil	const int sigval = SIGSTOP;
61551.1Skamil	const int sigmasked = SIGTRAP;
61561.1Skamil	pid_t child, wpid;
61571.1Skamil#if defined(TWAIT_HAVE_STATUS)
61581.1Skamil	int status;
61591.1Skamil#endif
61601.1Skamil	sigset_t intmask;
61611.1Skamil	ptrace_state_t state;
61621.1Skamil	const int slen = sizeof(state);
61631.1Skamil	ptrace_event_t event;
61641.1Skamil	const int elen = sizeof(event);
61651.1Skamil	ucontext_t uc;
61661.1Skamil	lwpid_t lid;
61671.1Skamil	static const size_t ssize = 16*1024;
61681.1Skamil	void *stack;
61691.1Skamil
61701.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
61711.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
61721.1Skamil	if (child == 0) {
61731.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
61741.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
61751.1Skamil
61761.1Skamil		sigemptyset(&intmask);
61771.1Skamil		sigaddset(&intmask, sigmasked);
61781.1Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
61791.1Skamil
61801.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
61811.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
61821.1Skamil
61831.13Schristos		DPRINTF("Before allocating memory for stack in child\n");
61841.1Skamil		FORKEE_ASSERT((stack = malloc(ssize)) != NULL);
61851.1Skamil
61861.13Schristos		DPRINTF("Before making context for new lwp in child\n");
61871.1Skamil		_lwp_makecontext(&uc, lwp_main_func, NULL, NULL, stack, ssize);
61881.1Skamil
61891.13Schristos		DPRINTF("Before creating new in child\n");
61901.1Skamil		FORKEE_ASSERT(_lwp_create(&uc, 0, &lid) == 0);
61911.1Skamil
61921.13Schristos		DPRINTF("Before waiting for lwp %d to exit\n", lid);
61931.1Skamil		FORKEE_ASSERT(_lwp_wait(lid, NULL) == 0);
61941.1Skamil
61951.13Schristos		DPRINTF("Before verifying that reported %d and running lid %d "
61961.1Skamil		    "are the same\n", lid, the_lwp_id);
61971.1Skamil		FORKEE_ASSERT_EQ(lid, the_lwp_id);
61981.1Skamil
61991.13Schristos		DPRINTF("Before exiting of the child process\n");
62001.1Skamil		_exit(exitval);
62011.1Skamil	}
62021.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
62031.1Skamil
62041.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
62051.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
62061.1Skamil
62071.1Skamil	validate_status_stopped(status, sigval);
62081.1Skamil
62091.13Schristos	DPRINTF("Set empty EVENT_MASK for the child %d\n", child);
62101.1Skamil	event.pe_set_event = PTRACE_LWP_CREATE;
62111.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
62121.1Skamil
62131.13Schristos	DPRINTF("Before resuming the child process where it left off and "
62141.1Skamil	    "without signal to be sent\n");
62151.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
62161.1Skamil
62171.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
62181.1Skamil	    "SIGTRAP\n", TWAIT_FNAME);
62191.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
62201.1Skamil
62211.1Skamil	validate_status_stopped(status, sigmasked);
62221.1Skamil
62231.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
62241.1Skamil
62251.1Skamil	ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_LWP_CREATE);
62261.1Skamil
62271.1Skamil	lid = state.pe_lwp;
62281.13Schristos	DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
62291.1Skamil
62301.13Schristos	DPRINTF("Before resuming the child process where it left off and "
62311.1Skamil	    "without signal to be sent\n");
62321.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
62331.1Skamil
62341.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
62351.1Skamil	    TWAIT_FNAME);
62361.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
62371.1Skamil
62381.1Skamil	validate_status_exited(status, exitval);
62391.1Skamil
62401.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
62411.1Skamil	    TWAIT_FNAME);
62421.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
62431.1Skamil}
62441.1Skamil
62451.1SkamilATF_TC(signal10);
62461.1SkamilATF_TC_HEAD(signal10, tc)
62471.1Skamil{
62481.1Skamil	atf_tc_set_md_var(tc, "descr",
62491.1Skamil	    "Verify that masking SIGTRAP in tracee does not stop tracer from "
62501.1Skamil	    "catching PTRACE_LWP_EXIT breakpoint");
62511.1Skamil}
62521.1Skamil
62531.1SkamilATF_TC_BODY(signal10, tc)
62541.1Skamil{
62551.1Skamil	const int exitval = 5;
62561.1Skamil	const int sigval = SIGSTOP;
62571.1Skamil	const int sigmasked = SIGTRAP;
62581.1Skamil	pid_t child, wpid;
62591.1Skamil#if defined(TWAIT_HAVE_STATUS)
62601.1Skamil	int status;
62611.1Skamil#endif
62621.1Skamil	sigset_t intmask;
62631.1Skamil	ptrace_state_t state;
62641.1Skamil	const int slen = sizeof(state);
62651.1Skamil	ptrace_event_t event;
62661.1Skamil	const int elen = sizeof(event);
62671.1Skamil	ucontext_t uc;
62681.1Skamil	lwpid_t lid;
62691.1Skamil	static const size_t ssize = 16*1024;
62701.1Skamil	void *stack;
62711.1Skamil
62721.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
62731.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
62741.1Skamil	if (child == 0) {
62751.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
62761.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
62771.1Skamil
62781.1Skamil		sigemptyset(&intmask);
62791.1Skamil		sigaddset(&intmask, sigmasked);
62801.1Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
62811.1Skamil
62821.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
62831.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
62841.1Skamil
62851.13Schristos		DPRINTF("Before allocating memory for stack in child\n");
62861.1Skamil		FORKEE_ASSERT((stack = malloc(ssize)) != NULL);
62871.1Skamil
62881.13Schristos		DPRINTF("Before making context for new lwp in child\n");
62891.1Skamil		_lwp_makecontext(&uc, lwp_main_func, NULL, NULL, stack, ssize);
62901.1Skamil
62911.13Schristos		DPRINTF("Before creating new in child\n");
62921.1Skamil		FORKEE_ASSERT(_lwp_create(&uc, 0, &lid) == 0);
62931.1Skamil
62941.13Schristos		DPRINTF("Before waiting for lwp %d to exit\n", lid);
62951.1Skamil		FORKEE_ASSERT(_lwp_wait(lid, NULL) == 0);
62961.1Skamil
62971.13Schristos		DPRINTF("Before verifying that reported %d and running lid %d "
62981.1Skamil		    "are the same\n", lid, the_lwp_id);
62991.1Skamil		FORKEE_ASSERT_EQ(lid, the_lwp_id);
63001.1Skamil
63011.13Schristos		DPRINTF("Before exiting of the child process\n");
63021.1Skamil		_exit(exitval);
63031.1Skamil	}
63041.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
63051.1Skamil
63061.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
63071.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
63081.1Skamil
63091.1Skamil	validate_status_stopped(status, sigval);
63101.1Skamil
63111.13Schristos	DPRINTF("Set empty EVENT_MASK for the child %d\n", child);
63121.1Skamil	event.pe_set_event = PTRACE_LWP_EXIT;
63131.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
63141.1Skamil
63151.13Schristos	DPRINTF("Before resuming the child process where it left off and "
63161.1Skamil	    "without signal to be sent\n");
63171.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
63181.1Skamil
63191.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
63201.1Skamil	    "SIGTRAP\n", TWAIT_FNAME);
63211.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
63221.1Skamil
63231.1Skamil	validate_status_stopped(status, sigmasked);
63241.1Skamil
63251.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
63261.1Skamil
63271.1Skamil	ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_LWP_EXIT);
63281.1Skamil
63291.1Skamil	lid = state.pe_lwp;
63301.13Schristos	DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
63311.1Skamil
63321.13Schristos	DPRINTF("Before resuming the child process where it left off and "
63331.1Skamil	    "without signal to be sent\n");
63341.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
63351.1Skamil
63361.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
63371.1Skamil	    TWAIT_FNAME);
63381.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
63391.1Skamil
63401.1Skamil	validate_status_exited(status, exitval);
63411.1Skamil
63421.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
63431.1Skamil	    TWAIT_FNAME);
63441.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
63451.1Skamil}
63461.1Skamil
63471.1Skamilstatic void
63481.1Skamillwp_main_stop(void *arg)
63491.1Skamil{
63501.1Skamil	the_lwp_id = _lwp_self();
63511.1Skamil
63521.1Skamil	raise(SIGTRAP);
63531.1Skamil
63541.1Skamil	_lwp_exit();
63551.1Skamil}
63561.1Skamil
63571.1SkamilATF_TC(suspend1);
63581.1SkamilATF_TC_HEAD(suspend1, tc)
63591.1Skamil{
63601.1Skamil	atf_tc_set_md_var(tc, "descr",
63611.1Skamil	    "Verify that a thread can be suspended by a debugger and later "
63621.1Skamil	    "resumed by a tracee");
63631.1Skamil}
63641.1Skamil
63651.1SkamilATF_TC_BODY(suspend1, tc)
63661.1Skamil{
63671.1Skamil	const int exitval = 5;
63681.1Skamil	const int sigval = SIGSTOP;
63691.1Skamil	pid_t child, wpid;
63701.1Skamil#if defined(TWAIT_HAVE_STATUS)
63711.1Skamil	int status;
63721.1Skamil#endif
63731.1Skamil	ucontext_t uc;
63741.1Skamil	lwpid_t lid;
63751.1Skamil	static const size_t ssize = 16*1024;
63761.1Skamil	void *stack;
63771.1Skamil	struct ptrace_lwpinfo pl;
63781.1Skamil	struct ptrace_siginfo psi;
63791.1Skamil	volatile int go = 0;
63801.1Skamil
63811.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
63821.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
63831.1Skamil	if (child == 0) {
63841.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
63851.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
63861.1Skamil
63871.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
63881.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
63891.1Skamil
63901.13Schristos		DPRINTF("Before allocating memory for stack in child\n");
63911.1Skamil		FORKEE_ASSERT((stack = malloc(ssize)) != NULL);
63921.1Skamil
63931.13Schristos		DPRINTF("Before making context for new lwp in child\n");
63941.1Skamil		_lwp_makecontext(&uc, lwp_main_stop, NULL, NULL, stack, ssize);
63951.1Skamil
63961.13Schristos		DPRINTF("Before creating new in child\n");
63971.1Skamil		FORKEE_ASSERT(_lwp_create(&uc, 0, &lid) == 0);
63981.1Skamil
63991.1Skamil		while (go == 0)
64001.1Skamil			continue;
64011.1Skamil
64021.1Skamil		raise(SIGINT);
64031.1Skamil
64041.1Skamil		FORKEE_ASSERT(_lwp_continue(lid) == 0);
64051.1Skamil
64061.13Schristos		DPRINTF("Before waiting for lwp %d to exit\n", lid);
64071.1Skamil		FORKEE_ASSERT(_lwp_wait(lid, NULL) == 0);
64081.1Skamil
64091.13Schristos		DPRINTF("Before verifying that reported %d and running lid %d "
64101.1Skamil		    "are the same\n", lid, the_lwp_id);
64111.1Skamil		FORKEE_ASSERT_EQ(lid, the_lwp_id);
64121.1Skamil
64131.13Schristos		DPRINTF("Before exiting of the child process\n");
64141.1Skamil		_exit(exitval);
64151.1Skamil	}
64161.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
64171.1Skamil
64181.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
64191.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64201.1Skamil
64211.1Skamil	validate_status_stopped(status, sigval);
64221.1Skamil
64231.13Schristos	DPRINTF("Before resuming the child process where it left off and "
64241.1Skamil	    "without signal to be sent\n");
64251.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
64261.1Skamil
64271.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
64281.1Skamil	    "SIGTRAP\n", TWAIT_FNAME);
64291.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64301.1Skamil
64311.1Skamil	validate_status_stopped(status, SIGTRAP);
64321.1Skamil
64331.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
64341.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
64351.1Skamil
64361.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
64371.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
64381.1Skamil
64391.13Schristos        DPRINTF("Write new go to tracee (PID=%d) from tracer (PID=%d)\n",
64401.1Skamil	    child, getpid());
64411.13Schristos	SYSCALL_REQUIRE(ptrace(PT_WRITE_D, child, __UNVOLATILE(&go), 1) != -1);
64421.1Skamil
64431.13Schristos	DPRINTF("Before resuming the child process where it left off and "
64441.1Skamil	    "without signal to be sent\n");
64451.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
64461.1Skamil
64471.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
64481.1Skamil	    "SIGINT\n", TWAIT_FNAME);
64491.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64501.1Skamil
64511.1Skamil	validate_status_stopped(status, SIGINT);
64521.1Skamil
64531.1Skamil	pl.pl_lwpid = 0;
64541.1Skamil
64551.13Schristos	SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &pl, sizeof(pl)) != -1);
64561.1Skamil	while (pl.pl_lwpid != 0) {
64571.1Skamil
64581.13Schristos		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &pl, sizeof(pl)) != -1);
64591.1Skamil		switch (pl.pl_lwpid) {
64601.1Skamil		case 1:
64611.1Skamil			ATF_REQUIRE_EQ(pl.pl_event, PL_EVENT_SIGNAL);
64621.1Skamil			break;
64631.1Skamil		case 2:
64641.1Skamil			ATF_REQUIRE_EQ(pl.pl_event, PL_EVENT_SUSPENDED);
64651.1Skamil			break;
64661.1Skamil		}
64671.1Skamil	}
64681.1Skamil
64691.13Schristos	DPRINTF("Before resuming the child process where it left off and "
64701.1Skamil	    "without signal to be sent\n");
64711.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
64721.1Skamil
64731.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
64741.1Skamil	    TWAIT_FNAME);
64751.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64761.1Skamil
64771.1Skamil	validate_status_exited(status, exitval);
64781.1Skamil
64791.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
64801.1Skamil	    TWAIT_FNAME);
64811.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
64821.1Skamil}
64831.1Skamil
64841.1SkamilATF_TC(suspend2);
64851.1SkamilATF_TC_HEAD(suspend2, tc)
64861.1Skamil{
64871.1Skamil	atf_tc_set_md_var(tc, "descr",
64881.1Skamil	    "Verify that the while the only thread within a process is "
64891.1Skamil	    "suspended, the whole process cannot be unstopped");
64901.1Skamil}
64911.1Skamil
64921.1SkamilATF_TC_BODY(suspend2, tc)
64931.1Skamil{
64941.1Skamil	const int exitval = 5;
64951.1Skamil	const int sigval = SIGSTOP;
64961.1Skamil	pid_t child, wpid;
64971.1Skamil#if defined(TWAIT_HAVE_STATUS)
64981.1Skamil	int status;
64991.1Skamil#endif
65001.1Skamil	struct ptrace_siginfo psi;
65011.1Skamil
65021.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
65031.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
65041.1Skamil	if (child == 0) {
65051.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
65061.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
65071.1Skamil
65081.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
65091.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
65101.1Skamil
65111.13Schristos		DPRINTF("Before exiting of the child process\n");
65121.1Skamil		_exit(exitval);
65131.1Skamil	}
65141.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
65151.1Skamil
65161.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
65171.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
65181.1Skamil
65191.1Skamil	validate_status_stopped(status, sigval);
65201.1Skamil
65211.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
65221.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
65231.1Skamil
65241.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
65251.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
65261.1Skamil
65271.13Schristos	DPRINTF("Before resuming the child process where it left off and "
65281.1Skamil	    "without signal to be sent\n");
65291.1Skamil	ATF_REQUIRE_ERRNO(EDEADLK,
65301.1Skamil	    ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
65311.1Skamil
65321.13Schristos	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
65331.13Schristos	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
65341.1Skamil
65351.13Schristos	DPRINTF("Before resuming the child process where it left off and "
65361.1Skamil	    "without signal to be sent\n");
65371.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
65381.1Skamil
65391.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
65401.1Skamil	    TWAIT_FNAME);
65411.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
65421.1Skamil
65431.1Skamil	validate_status_exited(status, exitval);
65441.1Skamil
65451.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
65461.1Skamil	    TWAIT_FNAME);
65471.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
65481.1Skamil}
65491.1Skamil
65501.1SkamilATF_TC(resume1);
65511.1SkamilATF_TC_HEAD(resume1, tc)
65521.1Skamil{
65531.1Skamil	atf_tc_set_md_var(tc, "descr",
65541.1Skamil	    "Verify that a thread can be suspended by a debugger and later "
65551.1Skamil	    "resumed by the debugger");
65561.1Skamil}
65571.1Skamil
65581.1SkamilATF_TC_BODY(resume1, tc)
65591.1Skamil{
65601.1Skamil	struct msg_fds fds;
65611.1Skamil	const int exitval = 5;
65621.1Skamil	const int sigval = SIGSTOP;
65631.1Skamil	pid_t child, wpid;
65641.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
65651.1Skamil#if defined(TWAIT_HAVE_STATUS)
65661.1Skamil	int status;
65671.1Skamil#endif
65681.1Skamil	ucontext_t uc;
65691.1Skamil	lwpid_t lid;
65701.1Skamil	static const size_t ssize = 16*1024;
65711.1Skamil	void *stack;
65721.1Skamil	struct ptrace_lwpinfo pl;
65731.1Skamil	struct ptrace_siginfo psi;
65741.1Skamil
65751.13Schristos	SYSCALL_REQUIRE(msg_open(&fds) == 0);
65761.1Skamil
65771.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
65781.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
65791.1Skamil	if (child == 0) {
65801.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
65811.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
65821.1Skamil
65831.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
65841.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
65851.1Skamil
65861.13Schristos		DPRINTF("Before allocating memory for stack in child\n");
65871.1Skamil		FORKEE_ASSERT((stack = malloc(ssize)) != NULL);
65881.1Skamil
65891.13Schristos		DPRINTF("Before making context for new lwp in child\n");
65901.1Skamil		_lwp_makecontext(&uc, lwp_main_stop, NULL, NULL, stack, ssize);
65911.1Skamil
65921.13Schristos		DPRINTF("Before creating new in child\n");
65931.1Skamil		FORKEE_ASSERT(_lwp_create(&uc, 0, &lid) == 0);
65941.1Skamil
65951.1Skamil		CHILD_TO_PARENT("Message", fds, msg);
65961.1Skamil
65971.1Skamil		raise(SIGINT);
65981.1Skamil
65991.13Schristos		DPRINTF("Before waiting for lwp %d to exit\n", lid);
66001.1Skamil		FORKEE_ASSERT(_lwp_wait(lid, NULL) == 0);
66011.1Skamil
66021.13Schristos		DPRINTF("Before verifying that reported %d and running lid %d "
66031.1Skamil		    "are the same\n", lid, the_lwp_id);
66041.1Skamil		FORKEE_ASSERT_EQ(lid, the_lwp_id);
66051.1Skamil
66061.13Schristos		DPRINTF("Before exiting of the child process\n");
66071.1Skamil		_exit(exitval);
66081.1Skamil	}
66091.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
66101.1Skamil
66111.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
66121.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66131.1Skamil
66141.1Skamil	validate_status_stopped(status, sigval);
66151.1Skamil
66161.13Schristos	DPRINTF("Before resuming the child process where it left off and "
66171.1Skamil	    "without signal to be sent\n");
66181.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
66191.1Skamil
66201.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
66211.1Skamil	    "SIGTRAP\n", TWAIT_FNAME);
66221.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66231.1Skamil
66241.1Skamil	validate_status_stopped(status, SIGTRAP);
66251.1Skamil
66261.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
66271.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
66281.1Skamil
66291.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
66301.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
66311.1Skamil
66321.1Skamil	PARENT_FROM_CHILD("Message", fds, msg);
66331.1Skamil
66341.13Schristos	DPRINTF("Before resuming the child process where it left off and "
66351.1Skamil	    "without signal to be sent\n");
66361.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
66371.1Skamil
66381.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
66391.1Skamil	    "SIGINT\n", TWAIT_FNAME);
66401.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66411.1Skamil
66421.1Skamil	validate_status_stopped(status, SIGINT);
66431.1Skamil
66441.1Skamil	pl.pl_lwpid = 0;
66451.1Skamil
66461.13Schristos	SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &pl, sizeof(pl)) != -1);
66471.1Skamil	while (pl.pl_lwpid != 0) {
66481.13Schristos		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &pl, sizeof(pl)) != -1);
66491.1Skamil		switch (pl.pl_lwpid) {
66501.1Skamil		case 1:
66511.1Skamil			ATF_REQUIRE_EQ(pl.pl_event, PL_EVENT_SIGNAL);
66521.1Skamil			break;
66531.1Skamil		case 2:
66541.1Skamil			ATF_REQUIRE_EQ(pl.pl_event, PL_EVENT_SUSPENDED);
66551.1Skamil			break;
66561.1Skamil		}
66571.1Skamil	}
66581.1Skamil
66591.13Schristos	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
66601.13Schristos	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
66611.1Skamil
66621.13Schristos	DPRINTF("Before resuming the child process where it left off and "
66631.1Skamil	    "without signal to be sent\n");
66641.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
66651.1Skamil
66661.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
66671.1Skamil	    TWAIT_FNAME);
66681.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66691.1Skamil
66701.1Skamil	validate_status_exited(status, exitval);
66711.1Skamil
66721.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
66731.1Skamil	    TWAIT_FNAME);
66741.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
66751.1Skamil
66761.1Skamil	msg_close(&fds);
66771.1Skamil}
66781.1Skamil
66791.1SkamilATF_TC(syscall1);
66801.1SkamilATF_TC_HEAD(syscall1, tc)
66811.1Skamil{
66821.1Skamil	atf_tc_set_md_var(tc, "descr",
66831.1Skamil	    "Verify that getpid(2) can be traced with PT_SYSCALL");
66841.1Skamil}
66851.1Skamil
66861.1SkamilATF_TC_BODY(syscall1, tc)
66871.1Skamil{
66881.1Skamil	const int exitval = 5;
66891.1Skamil	const int sigval = SIGSTOP;
66901.1Skamil	pid_t child, wpid;
66911.1Skamil#if defined(TWAIT_HAVE_STATUS)
66921.1Skamil	int status;
66931.1Skamil#endif
66941.1Skamil	struct ptrace_siginfo info;
66951.1Skamil	memset(&info, 0, sizeof(info));
66961.1Skamil
66971.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
66981.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
66991.1Skamil	if (child == 0) {
67001.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
67011.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
67021.1Skamil
67031.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
67041.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
67051.1Skamil
67061.1Skamil		syscall(SYS_getpid);
67071.1Skamil
67081.13Schristos		DPRINTF("Before exiting of the child process\n");
67091.1Skamil		_exit(exitval);
67101.1Skamil	}
67111.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
67121.1Skamil
67131.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
67141.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
67151.1Skamil
67161.1Skamil	validate_status_stopped(status, sigval);
67171.1Skamil
67181.13Schristos	DPRINTF("Before resuming the child process where it left off and "
67191.1Skamil	    "without signal to be sent\n");
67201.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
67211.1Skamil
67221.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
67231.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
67241.1Skamil
67251.1Skamil	validate_status_stopped(status, SIGTRAP);
67261.1Skamil
67271.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
67281.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
67291.1Skamil
67301.38Skamil	DPRINTF("Before checking siginfo_t and lwpid\n");
67311.38Skamil	ATF_REQUIRE_EQ(info.psi_lwpid, 1);
67321.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
67331.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_SCE);
67341.1Skamil
67351.13Schristos	DPRINTF("Before resuming the child process where it left off and "
67361.1Skamil	    "without signal to be sent\n");
67371.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
67381.1Skamil
67391.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
67401.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
67411.1Skamil
67421.1Skamil	validate_status_stopped(status, SIGTRAP);
67431.1Skamil
67441.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
67451.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
67461.1Skamil
67471.38Skamil	DPRINTF("Before checking siginfo_t and lwpid\n");
67481.38Skamil	ATF_REQUIRE_EQ(info.psi_lwpid, 1);
67491.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
67501.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_SCX);
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\n", TWAIT_FNAME);
67571.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
67581.1Skamil
67591.1Skamil	validate_status_exited(status, exitval);
67601.1Skamil
67611.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
67621.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
67631.1Skamil}
67641.1Skamil
67651.1SkamilATF_TC(syscallemu1);
67661.1SkamilATF_TC_HEAD(syscallemu1, tc)
67671.1Skamil{
67681.1Skamil	atf_tc_set_md_var(tc, "descr",
67691.1Skamil	    "Verify that exit(2) can be intercepted with PT_SYSCALLEMU");
67701.1Skamil}
67711.1Skamil
67721.1SkamilATF_TC_BODY(syscallemu1, tc)
67731.1Skamil{
67741.1Skamil	const int exitval = 5;
67751.1Skamil	const int sigval = SIGSTOP;
67761.1Skamil	pid_t child, wpid;
67771.1Skamil#if defined(TWAIT_HAVE_STATUS)
67781.1Skamil	int status;
67791.1Skamil#endif
67801.1Skamil
67811.6Skamil#if defined(__sparc__) && !defined(__sparc64__)
67821.6Skamil	/* syscallemu does not work on sparc (32-bit) */
67831.6Skamil	atf_tc_expect_fail("PR kern/52166");
67841.6Skamil#endif
67851.6Skamil
67861.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
67871.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
67881.1Skamil	if (child == 0) {
67891.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
67901.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
67911.1Skamil
67921.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
67931.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
67941.1Skamil
67951.1Skamil		syscall(SYS_exit, 100);
67961.1Skamil
67971.13Schristos		DPRINTF("Before exiting of the child process\n");
67981.1Skamil		_exit(exitval);
67991.1Skamil	}
68001.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
68011.1Skamil
68021.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68031.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68041.1Skamil
68051.1Skamil	validate_status_stopped(status, sigval);
68061.1Skamil
68071.13Schristos	DPRINTF("Before resuming the child process where it left off and "
68081.1Skamil	    "without signal to be sent\n");
68091.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
68101.1Skamil
68111.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68121.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68131.1Skamil
68141.1Skamil	validate_status_stopped(status, SIGTRAP);
68151.1Skamil
68161.13Schristos	DPRINTF("Set SYSCALLEMU for intercepted syscall\n");
68171.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALLEMU, child, (void *)1, 0) != -1);
68181.1Skamil
68191.13Schristos	DPRINTF("Before resuming the child process where it left off and "
68201.1Skamil	    "without signal to be sent\n");
68211.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
68221.1Skamil
68231.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68241.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68251.1Skamil
68261.1Skamil	validate_status_stopped(status, SIGTRAP);
68271.1Skamil
68281.13Schristos	DPRINTF("Before resuming the child process where it left off and "
68291.1Skamil	    "without signal to be sent\n");
68301.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
68311.1Skamil
68321.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68331.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68341.1Skamil
68351.1Skamil	validate_status_exited(status, exitval);
68361.1Skamil
68371.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68381.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
68391.1Skamil}
68401.1Skamil
68411.103Skamil/// ----------------------------------------------------------------------------
68421.103Skamil
68431.106Skamilstatic void
68441.106Skamilclone_body(int flags, bool trackfork, bool trackvfork,
68451.106Skamil    bool trackvforkdone)
68461.106Skamil{
68471.106Skamil	const int exitval = 5;
68481.106Skamil	const int exitval2 = 15;
68491.106Skamil	const int sigval = SIGSTOP;
68501.106Skamil	pid_t child, child2 = 0, wpid;
68511.106Skamil#if defined(TWAIT_HAVE_STATUS)
68521.106Skamil	int status;
68531.106Skamil#endif
68541.106Skamil	ptrace_state_t state;
68551.106Skamil	const int slen = sizeof(state);
68561.106Skamil	ptrace_event_t event;
68571.106Skamil	const int elen = sizeof(event);
68581.106Skamil
68591.106Skamil	const size_t stack_size = 1024 * 1024;
68601.106Skamil	void *stack, *stack_base;
68611.106Skamil
68621.106Skamil	stack = malloc(stack_size);
68631.106Skamil	ATF_REQUIRE(stack != NULL);
68641.106Skamil
68651.106Skamil#ifdef __MACHINE_STACK_GROWS_UP
68661.106Skamil	stack_base = stack;
68671.106Skamil#else
68681.106Skamil	stack_base = (char *)stack + stack_size;
68691.106Skamil#endif
68701.106Skamil
68711.106Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
68721.106Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
68731.106Skamil	if (child == 0) {
68741.106Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
68751.106Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
68761.106Skamil
68771.106Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
68781.106Skamil		FORKEE_ASSERT(raise(sigval) == 0);
68791.106Skamil
68801.106Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
68811.106Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
68821.106Skamil
68831.106Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
68841.106Skamil		    child2);
68851.106Skamil
68861.106Skamil		// XXX WALLSIG?
68871.106Skamil		FORKEE_REQUIRE_SUCCESS
68881.106Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
68891.106Skamil
68901.106Skamil		forkee_status_exited(status, exitval2);
68911.106Skamil
68921.106Skamil		DPRINTF("Before exiting of the child process\n");
68931.106Skamil		_exit(exitval);
68941.106Skamil	}
68951.106Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
68961.106Skamil
68971.106Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68981.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68991.106Skamil
69001.106Skamil	validate_status_stopped(status, sigval);
69011.106Skamil
69021.106Skamil	DPRINTF("Set 0%s%s%s in EVENT_MASK for the child %d\n",
69031.106Skamil	    trackfork ? "|PTRACE_FORK" : "",
69041.106Skamil	    trackvfork ? "|PTRACE_VFORK" : "",
69051.106Skamil	    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", child);
69061.106Skamil	event.pe_set_event = 0;
69071.106Skamil	if (trackfork)
69081.106Skamil		event.pe_set_event |= PTRACE_FORK;
69091.106Skamil	if (trackvfork)
69101.106Skamil		event.pe_set_event |= PTRACE_VFORK;
69111.106Skamil	if (trackvforkdone)
69121.106Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
69131.106Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
69141.106Skamil
69151.106Skamil	DPRINTF("Before resuming the child process where it left off and "
69161.106Skamil	    "without signal to be sent\n");
69171.106Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
69181.106Skamil
69191.106Skamil#if defined(TWAIT_HAVE_PID)
69201.106Skamil	if ((trackfork && !(flags & CLONE_VFORK)) ||
69211.106Skamil	    (trackvfork && (flags & CLONE_VFORK))) {
69221.106Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
69231.106Skamil		    child);
69241.106Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
69251.106Skamil		    child);
69261.106Skamil
69271.106Skamil		validate_status_stopped(status, SIGTRAP);
69281.106Skamil
69291.106Skamil		SYSCALL_REQUIRE(
69301.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
69311.106Skamil		if (trackfork && !(flags & CLONE_VFORK)) {
69321.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
69331.106Skamil			       PTRACE_FORK);
69341.106Skamil		}
69351.106Skamil		if (trackvfork && (flags & CLONE_VFORK)) {
69361.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
69371.106Skamil			       PTRACE_VFORK);
69381.106Skamil		}
69391.106Skamil
69401.106Skamil		child2 = state.pe_other_pid;
69411.106Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
69421.106Skamil
69431.106Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
69441.106Skamil		    "%d\n", TWAIT_FNAME, child2, child);
69451.106Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
69461.106Skamil		    child2);
69471.106Skamil
69481.106Skamil		validate_status_stopped(status, SIGTRAP);
69491.106Skamil
69501.106Skamil		SYSCALL_REQUIRE(
69511.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
69521.106Skamil		if (trackfork && !(flags & CLONE_VFORK)) {
69531.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
69541.106Skamil			       PTRACE_FORK);
69551.106Skamil		}
69561.106Skamil		if (trackvfork && (flags & CLONE_VFORK)) {
69571.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
69581.106Skamil			       PTRACE_VFORK);
69591.106Skamil		}
69601.106Skamil
69611.106Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
69621.106Skamil
69631.106Skamil		DPRINTF("Before resuming the forkee process where it left off "
69641.106Skamil		    "and without signal to be sent\n");
69651.106Skamil		SYSCALL_REQUIRE(
69661.106Skamil		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
69671.106Skamil
69681.106Skamil		DPRINTF("Before resuming the child process where it left off "
69691.106Skamil		    "and without signal to be sent\n");
69701.106Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
69711.106Skamil	}
69721.106Skamil#endif
69731.106Skamil
69741.106Skamil	if (trackvforkdone && (flags & CLONE_VFORK)) {
69751.106Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
69761.106Skamil		    child);
69771.106Skamil		TWAIT_REQUIRE_SUCCESS(
69781.106Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
69791.106Skamil
69801.106Skamil		validate_status_stopped(status, SIGTRAP);
69811.106Skamil
69821.106Skamil		SYSCALL_REQUIRE(
69831.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
69841.106Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
69851.106Skamil
69861.106Skamil		child2 = state.pe_other_pid;
69871.106Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
69881.106Skamil		    child2);
69891.106Skamil
69901.106Skamil		DPRINTF("Before resuming the child process where it left off "
69911.106Skamil		    "and without signal to be sent\n");
69921.106Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
69931.106Skamil	}
69941.106Skamil
69951.103Skamil#if defined(TWAIT_HAVE_PID)
69961.106Skamil	if ((trackfork && !(flags & CLONE_VFORK)) ||
69971.106Skamil	    (trackvfork && (flags & CLONE_VFORK))) {
69981.106Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
69991.106Skamil		    "\n", TWAIT_FNAME);
70001.106Skamil		TWAIT_REQUIRE_SUCCESS(
70011.106Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
70021.106Skamil
70031.106Skamil		validate_status_exited(status, exitval2);
70041.106Skamil
70051.106Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
70061.106Skamil		    "process\n", TWAIT_FNAME);
70071.106Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
70081.106Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
70091.106Skamil	}
70101.106Skamil#endif
70111.106Skamil
70121.106Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
70131.106Skamil	    "SIGCHLD\n", TWAIT_FNAME);
70141.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
70151.106Skamil
70161.106Skamil	validate_status_stopped(status, SIGCHLD);
70171.106Skamil
70181.106Skamil	DPRINTF("Before resuming the child process where it left off and "
70191.106Skamil	    "without signal to be sent\n");
70201.106Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
70211.106Skamil
70221.106Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
70231.106Skamil	    TWAIT_FNAME);
70241.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
70251.106Skamil
70261.106Skamil	validate_status_exited(status, exitval);
70271.103Skamil
70281.106Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
70291.106Skamil	    TWAIT_FNAME);
70301.106Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
70311.106Skamil}
70321.103Skamil
70331.106Skamil#define CLONE_TEST(name,flags,tfork,tvfork,tvforkdone)			\
70341.106SkamilATF_TC(name);								\
70351.106SkamilATF_TC_HEAD(name, tc)							\
70361.106Skamil{									\
70371.106Skamil	atf_tc_set_md_var(tc, "descr", "Verify clone(%s) "		\
70381.106Skamil	    "called with 0%s%s%s in EVENT_MASK",			\
70391.106Skamil	    #flags,							\
70401.106Skamil	    tfork ? "|PTRACE_FORK" : "",				\
70411.106Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
70421.106Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
70431.106Skamil}									\
70441.106Skamil									\
70451.106SkamilATF_TC_BODY(name, tc)							\
70461.106Skamil{									\
70471.106Skamil									\
70481.106Skamil	clone_body(flags, tfork, tvfork, tvforkdone);			\
70491.103Skamil}
70501.103Skamil
70511.106SkamilCLONE_TEST(clone1, 0, false, false, false)
70521.106Skamil#if defined(TWAIT_HAVE_PID)
70531.106SkamilCLONE_TEST(clone2, 0, true, false, false)
70541.106SkamilCLONE_TEST(clone3, 0, false, true, false)
70551.106SkamilCLONE_TEST(clone4, 0, true, true, false)
70561.106Skamil#endif
70571.106SkamilCLONE_TEST(clone5, 0, false, false, true)
70581.106Skamil#if defined(TWAIT_HAVE_PID)
70591.106SkamilCLONE_TEST(clone6, 0, true, false, true)
70601.106SkamilCLONE_TEST(clone7, 0, false, true, true)
70611.106SkamilCLONE_TEST(clone8, 0, true, true, true)
70621.106Skamil#endif
70631.106Skamil
70641.106SkamilCLONE_TEST(clone_vm1, CLONE_VM, false, false, false)
70651.106Skamil#if defined(TWAIT_HAVE_PID)
70661.106SkamilCLONE_TEST(clone_vm2, CLONE_VM, true, false, false)
70671.106SkamilCLONE_TEST(clone_vm3, CLONE_VM, false, true, false)
70681.106SkamilCLONE_TEST(clone_vm4, CLONE_VM, true, true, false)
70691.106Skamil#endif
70701.106SkamilCLONE_TEST(clone_vm5, CLONE_VM, false, false, true)
70711.106Skamil#if defined(TWAIT_HAVE_PID)
70721.106SkamilCLONE_TEST(clone_vm6, CLONE_VM, true, false, true)
70731.106SkamilCLONE_TEST(clone_vm7, CLONE_VM, false, true, true)
70741.106SkamilCLONE_TEST(clone_vm8, CLONE_VM, true, true, true)
70751.106Skamil#endif
70761.106Skamil
70771.106SkamilCLONE_TEST(clone_fs1, CLONE_FS, false, false, false)
70781.106Skamil#if defined(TWAIT_HAVE_PID)
70791.106SkamilCLONE_TEST(clone_fs2, CLONE_FS, true, false, false)
70801.106SkamilCLONE_TEST(clone_fs3, CLONE_FS, false, true, false)
70811.106SkamilCLONE_TEST(clone_fs4, CLONE_FS, true, true, false)
70821.106Skamil#endif
70831.106SkamilCLONE_TEST(clone_fs5, CLONE_FS, false, false, true)
70841.106Skamil#if defined(TWAIT_HAVE_PID)
70851.106SkamilCLONE_TEST(clone_fs6, CLONE_FS, true, false, true)
70861.106SkamilCLONE_TEST(clone_fs7, CLONE_FS, false, true, true)
70871.106SkamilCLONE_TEST(clone_fs8, CLONE_FS, true, true, true)
70881.106Skamil#endif
70891.106Skamil
70901.106SkamilCLONE_TEST(clone_files1, CLONE_FILES, false, false, false)
70911.106Skamil#if defined(TWAIT_HAVE_PID)
70921.106SkamilCLONE_TEST(clone_files2, CLONE_FILES, true, false, false)
70931.106SkamilCLONE_TEST(clone_files3, CLONE_FILES, false, true, false)
70941.106SkamilCLONE_TEST(clone_files4, CLONE_FILES, true, true, false)
70951.106Skamil#endif
70961.106SkamilCLONE_TEST(clone_files5, CLONE_FILES, false, false, true)
70971.106Skamil#if defined(TWAIT_HAVE_PID)
70981.106SkamilCLONE_TEST(clone_files6, CLONE_FILES, true, false, true)
70991.106SkamilCLONE_TEST(clone_files7, CLONE_FILES, false, true, true)
71001.106SkamilCLONE_TEST(clone_files8, CLONE_FILES, true, true, true)
71011.106Skamil#endif
71021.106Skamil
71031.106Skamil//CLONE_TEST(clone_sighand1, CLONE_SIGHAND, false, false, false)
71041.106Skamil#if defined(TWAIT_HAVE_PID)
71051.106Skamil//CLONE_TEST(clone_sighand2, CLONE_SIGHAND, true, false, false)
71061.106Skamil//CLONE_TEST(clone_sighand3, CLONE_SIGHAND, false, true, false)
71071.106Skamil//CLONE_TEST(clone_sighand4, CLONE_SIGHAND, true, true, false)
71081.106Skamil#endif
71091.106Skamil//CLONE_TEST(clone_sighand5, CLONE_SIGHAND, false, false, true)
71101.106Skamil#if defined(TWAIT_HAVE_PID)
71111.106Skamil//CLONE_TEST(clone_sighand6, CLONE_SIGHAND, true, false, true)
71121.106Skamil//CLONE_TEST(clone_sighand7, CLONE_SIGHAND, false, true, true)
71131.106Skamil//CLONE_TEST(clone_sighand8, CLONE_SIGHAND, true, true, true)
71141.106Skamil#endif
71151.106Skamil
71161.110Skamil#if TEST_VFORK_ENABLED
71171.106SkamilCLONE_TEST(clone_vfork1, CLONE_VFORK, false, false, false)
71181.106Skamil#if defined(TWAIT_HAVE_PID)
71191.106SkamilCLONE_TEST(clone_vfork2, CLONE_VFORK, true, false, false)
71201.106SkamilCLONE_TEST(clone_vfork3, CLONE_VFORK, false, true, false)
71211.106SkamilCLONE_TEST(clone_vfork4, CLONE_VFORK, true, true, false)
71221.106Skamil#endif
71231.106SkamilCLONE_TEST(clone_vfork5, CLONE_VFORK, false, false, true)
71241.106Skamil#if defined(TWAIT_HAVE_PID)
71251.106SkamilCLONE_TEST(clone_vfork6, CLONE_VFORK, true, false, true)
71261.106SkamilCLONE_TEST(clone_vfork7, CLONE_VFORK, false, true, true)
71271.106SkamilCLONE_TEST(clone_vfork8, CLONE_VFORK, true, true, true)
71281.106Skamil#endif
71291.110Skamil#endif
71301.106Skamil
71311.106Skamil/// ----------------------------------------------------------------------------
71321.106Skamil
71331.106Skamil#if defined(TWAIT_HAVE_PID)
71341.103Skamilstatic void
71351.106Skamilclone_body2(int flags, bool masked, bool ignored)
71361.103Skamil{
71371.103Skamil	const int exitval = 5;
71381.103Skamil	const int exitval2 = 15;
71391.103Skamil	const int sigval = SIGSTOP;
71401.103Skamil	pid_t child, child2 = 0, wpid;
71411.103Skamil#if defined(TWAIT_HAVE_STATUS)
71421.103Skamil	int status;
71431.103Skamil#endif
71441.103Skamil	ptrace_state_t state;
71451.103Skamil	const int slen = sizeof(state);
71461.103Skamil	ptrace_event_t event;
71471.103Skamil	const int elen = sizeof(event);
71481.103Skamil	struct sigaction sa;
71491.103Skamil	struct ptrace_siginfo info;
71501.103Skamil	sigset_t intmask;
71511.103Skamil	struct kinfo_proc2 kp;
71521.103Skamil	size_t len = sizeof(kp);
71531.103Skamil
71541.103Skamil	int name[6];
71551.103Skamil	const size_t namelen = __arraycount(name);
71561.103Skamil	ki_sigset_t kp_sigmask;
71571.103Skamil	ki_sigset_t kp_sigignore;
71581.103Skamil
71591.103Skamil	const size_t stack_size = 1024 * 1024;
71601.103Skamil	void *stack, *stack_base;
71611.103Skamil
71621.103Skamil	stack = malloc(stack_size);
71631.103Skamil	ATF_REQUIRE(stack != NULL);
71641.103Skamil
71651.103Skamil#ifdef __MACHINE_STACK_GROWS_UP
71661.103Skamil	stack_base = stack;
71671.103Skamil#else
71681.103Skamil	stack_base = (char *)stack + stack_size;
71691.103Skamil#endif
71701.103Skamil
71711.103Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
71721.103Skamil	if (child == 0) {
71731.103Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
71741.103Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
71751.103Skamil
71761.103Skamil		if (masked) {
71771.103Skamil			sigemptyset(&intmask);
71781.103Skamil			sigaddset(&intmask, SIGTRAP);
71791.103Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
71801.103Skamil		}
71811.103Skamil
71821.103Skamil		if (ignored) {
71831.103Skamil			memset(&sa, 0, sizeof(sa));
71841.103Skamil			sa.sa_handler = SIG_IGN;
71851.103Skamil			sigemptyset(&sa.sa_mask);
71861.103Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
71871.103Skamil		}
71881.103Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
71891.103Skamil		FORKEE_ASSERT(raise(sigval) == 0);
71901.103Skamil
71911.103Skamil		DPRINTF("Before forking process PID=%d flags=%#x\n", getpid(),
71921.103Skamil		    flags);
71931.103Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
71941.103Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
71951.103Skamil
71961.103Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
71971.103Skamil		    child2);
71981.103Skamil
71991.103Skamil		// XXX WALLSIG?
72001.103Skamil		FORKEE_REQUIRE_SUCCESS
72011.103Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
72021.103Skamil
72031.103Skamil		forkee_status_exited(status, exitval2);
72041.103Skamil
72051.103Skamil		DPRINTF("Before exiting of the child process\n");
72061.103Skamil		_exit(exitval);
72071.103Skamil	}
72081.103Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
72091.103Skamil
72101.103Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
72111.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
72121.103Skamil
72131.103Skamil	validate_status_stopped(status, sigval);
72141.103Skamil
72151.103Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
72161.103Skamil	SYSCALL_REQUIRE(
72171.103Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
72181.103Skamil
72191.103Skamil	DPRINTF("Before checking siginfo_t\n");
72201.103Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
72211.103Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
72221.103Skamil
72231.103Skamil	name[0] = CTL_KERN,
72241.103Skamil	name[1] = KERN_PROC2,
72251.103Skamil	name[2] = KERN_PROC_PID;
72261.103Skamil	name[3] = child;
72271.103Skamil	name[4] = sizeof(kp);
72281.103Skamil	name[5] = 1;
72291.103Skamil
72301.103Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
72311.103Skamil
72321.103Skamil	if (masked)
72331.103Skamil		kp_sigmask = kp.p_sigmask;
72341.103Skamil
72351.103Skamil	if (ignored)
72361.103Skamil		kp_sigignore = kp.p_sigignore;
72371.103Skamil
72381.103Skamil	DPRINTF("Set PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE in "
72391.103Skamil	    "EVENT_MASK for the child %d\n", child);
72401.103Skamil	event.pe_set_event = PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE;
72411.103Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
72421.103Skamil
72431.103Skamil	DPRINTF("Before resuming the child process where it left off and "
72441.103Skamil	    "without signal to be sent\n");
72451.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
72461.103Skamil
72471.103Skamil	DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
72481.103Skamil	    child);
72491.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
72501.103Skamil	    child);
72511.103Skamil
72521.103Skamil	validate_status_stopped(status, SIGTRAP);
72531.103Skamil
72541.103Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
72551.103Skamil
72561.103Skamil	if (masked) {
72571.103Skamil		DPRINTF("kp_sigmask="
72581.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
72591.103Skamil		    PRIx32 "\n",
72601.103Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
72611.103Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
72621.103Skamil
72631.103Skamil		DPRINTF("kp.p_sigmask="
72641.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
72651.103Skamil		    PRIx32 "\n",
72661.103Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
72671.103Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
72681.103Skamil
72691.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
72701.103Skamil		    sizeof(kp_sigmask)));
72711.103Skamil	}
72721.103Skamil
72731.103Skamil	if (ignored) {
72741.103Skamil		DPRINTF("kp_sigignore="
72751.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
72761.103Skamil		    PRIx32 "\n",
72771.103Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
72781.103Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
72791.103Skamil
72801.103Skamil		DPRINTF("kp.p_sigignore="
72811.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
72821.103Skamil		    PRIx32 "\n",
72831.103Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
72841.103Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
72851.103Skamil
72861.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
72871.103Skamil		    sizeof(kp_sigignore)));
72881.103Skamil	}
72891.103Skamil
72901.103Skamil	SYSCALL_REQUIRE(
72911.103Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
72921.103Skamil	DPRINTF("state.pe_report_event=%#x pid=%d\n", state.pe_report_event,
72931.103Skamil	    child2);
72941.103Skamil	if (!(flags & CLONE_VFORK)) {
72951.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
72961.103Skamil		       PTRACE_FORK);
72971.103Skamil	} else {
72981.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
72991.103Skamil		       PTRACE_VFORK);
73001.103Skamil	}
73011.103Skamil
73021.103Skamil	child2 = state.pe_other_pid;
73031.103Skamil	DPRINTF("Reported ptrace event with forkee %d\n", child2);
73041.103Skamil
73051.103Skamil	DPRINTF("Before calling %s() for the forkee %d of the child "
73061.103Skamil	    "%d\n", TWAIT_FNAME, child2, child);
73071.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
73081.103Skamil	    child2);
73091.103Skamil
73101.103Skamil	validate_status_stopped(status, SIGTRAP);
73111.103Skamil
73121.103Skamil	name[3] = child2;
73131.103Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
73141.103Skamil
73151.103Skamil	if (masked) {
73161.103Skamil		DPRINTF("kp_sigmask="
73171.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73181.103Skamil		    PRIx32 "\n",
73191.103Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
73201.103Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
73211.103Skamil
73221.103Skamil		DPRINTF("kp.p_sigmask="
73231.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73241.103Skamil		    PRIx32 "\n",
73251.103Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
73261.103Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
73271.103Skamil
73281.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
73291.103Skamil		    sizeof(kp_sigmask)));
73301.103Skamil	}
73311.103Skamil
73321.103Skamil	if (ignored) {
73331.103Skamil		DPRINTF("kp_sigignore="
73341.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73351.103Skamil		    PRIx32 "\n",
73361.103Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
73371.103Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
73381.103Skamil
73391.103Skamil		DPRINTF("kp.p_sigignore="
73401.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73411.103Skamil		    PRIx32 "\n",
73421.103Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
73431.103Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
73441.103Skamil
73451.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
73461.103Skamil		    sizeof(kp_sigignore)));
73471.103Skamil	}
73481.103Skamil
73491.103Skamil	SYSCALL_REQUIRE(
73501.103Skamil	    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
73511.103Skamil	if (!(flags & CLONE_VFORK)) {
73521.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
73531.103Skamil		       PTRACE_FORK);
73541.103Skamil	} else {
73551.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
73561.103Skamil		       PTRACE_VFORK);
73571.103Skamil	}
73581.103Skamil
73591.103Skamil	ATF_REQUIRE_EQ(state.pe_other_pid, child);
73601.103Skamil
73611.103Skamil	DPRINTF("Before resuming the forkee process where it left off "
73621.103Skamil	    "and without signal to be sent\n");
73631.103Skamil	SYSCALL_REQUIRE(
73641.103Skamil	    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
73651.103Skamil
73661.103Skamil	DPRINTF("Before resuming the child process where it left off "
73671.103Skamil	    "and without signal to be sent\n");
73681.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
73691.103Skamil
73701.103Skamil	if (flags & CLONE_VFORK) {
73711.103Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
73721.103Skamil		    child);
73731.103Skamil		TWAIT_REQUIRE_SUCCESS(
73741.103Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
73751.103Skamil
73761.103Skamil		validate_status_stopped(status, SIGTRAP);
73771.103Skamil
73781.103Skamil		name[3] = child;
73791.103Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
73801.103Skamil
73811.103Skamil		/*
73821.103Skamil		 * SIGCHLD is now pending in the signal queue and
73831.103Skamil		 * the kernel presents it to userland as a masked signal.
73841.103Skamil		 */
73851.103Skamil		sigdelset((sigset_t *)&kp.p_sigmask, SIGCHLD);
73861.103Skamil
73871.103Skamil		if (masked) {
73881.103Skamil			DPRINTF("kp_sigmask="
73891.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73901.103Skamil			    PRIx32 "\n",
73911.103Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
73921.103Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
73931.103Skamil
73941.103Skamil			DPRINTF("kp.p_sigmask="
73951.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73961.103Skamil			    PRIx32 "\n",
73971.103Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
73981.103Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
73991.103Skamil
74001.103Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
74011.103Skamil			    sizeof(kp_sigmask)));
74021.103Skamil		}
74031.103Skamil
74041.103Skamil		if (ignored) {
74051.103Skamil			DPRINTF("kp_sigignore="
74061.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
74071.103Skamil			    PRIx32 "\n",
74081.103Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
74091.103Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
74101.103Skamil
74111.103Skamil			DPRINTF("kp.p_sigignore="
74121.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
74131.103Skamil			    PRIx32 "\n",
74141.103Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
74151.103Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
74161.103Skamil
74171.103Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
74181.103Skamil			    sizeof(kp_sigignore)));
74191.103Skamil		}
74201.103Skamil
74211.103Skamil		SYSCALL_REQUIRE(
74221.103Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
74231.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
74241.103Skamil
74251.103Skamil		child2 = state.pe_other_pid;
74261.103Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
74271.103Skamil		    child2);
74281.103Skamil
74291.103Skamil		DPRINTF("Before resuming the child process where it left off "
74301.103Skamil		    "and without signal to be sent\n");
74311.103Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
74321.103Skamil	}
74331.103Skamil
74341.103Skamil	DPRINTF("Before calling %s() for the forkee - expected exited"
74351.103Skamil	    "\n", TWAIT_FNAME);
74361.103Skamil	TWAIT_REQUIRE_SUCCESS(
74371.103Skamil	    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
74381.103Skamil
74391.103Skamil	validate_status_exited(status, exitval2);
74401.103Skamil
74411.103Skamil	DPRINTF("Before calling %s() for the forkee - expected no "
74421.103Skamil	    "process\n", TWAIT_FNAME);
74431.103Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
74441.103Skamil	    wpid = TWAIT_GENERIC(child2, &status, 0));
74451.103Skamil
74461.103Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
74471.103Skamil	    "SIGCHLD\n", TWAIT_FNAME);
74481.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74491.103Skamil
74501.103Skamil	validate_status_stopped(status, SIGCHLD);
74511.103Skamil
74521.103Skamil	DPRINTF("Before resuming the child process where it left off and "
74531.103Skamil	    "without signal to be sent\n");
74541.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
74551.103Skamil
74561.103Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
74571.103Skamil	    TWAIT_FNAME);
74581.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74591.103Skamil
74601.103Skamil	validate_status_exited(status, exitval);
74611.103Skamil
74621.103Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
74631.103Skamil	    TWAIT_FNAME);
74641.103Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
74651.103Skamil}
74661.103Skamil
74671.106Skamil#define CLONE_TEST2(name,flags,masked,ignored)				\
74681.103SkamilATF_TC(name);								\
74691.103SkamilATF_TC_HEAD(name, tc)							\
74701.103Skamil{									\
74711.103Skamil	atf_tc_set_md_var(tc, "descr", "Verify that clone(%s) is caught"\
74721.103Skamil	    " regardless of signal %s%s", 				\
74731.103Skamil	    #flags, masked ? "masked" : "", ignored ? "ignored" : "");	\
74741.103Skamil}									\
74751.103Skamil									\
74761.103SkamilATF_TC_BODY(name, tc)							\
74771.103Skamil{									\
74781.103Skamil									\
74791.106Skamil	clone_body2(flags, masked, ignored);				\
74801.103Skamil}
74811.103Skamil
74821.106SkamilCLONE_TEST2(clone_signalignored, 0, true, false)
74831.106SkamilCLONE_TEST2(clone_signalmasked, 0, false, true)
74841.106SkamilCLONE_TEST2(clone_vm_signalignored, CLONE_VM, true, false)
74851.106SkamilCLONE_TEST2(clone_vm_signalmasked, CLONE_VM, false, true)
74861.106SkamilCLONE_TEST2(clone_fs_signalignored, CLONE_FS, true, false)
74871.106SkamilCLONE_TEST2(clone_fs_signalmasked, CLONE_FS, false, true)
74881.106SkamilCLONE_TEST2(clone_files_signalignored, CLONE_FILES, true, false)
74891.106SkamilCLONE_TEST2(clone_files_signalmasked, CLONE_FILES, false, true)
74901.106Skamil//CLONE_TEST2(clone_sighand_signalignored, CLONE_SIGHAND, true, false) // XXX
74911.106Skamil//CLONE_TEST2(clone_sighand_signalmasked, CLONE_SIGHAND, false, true)  // XXX
74921.110Skamil#if TEST_VFORK_ENABLED
74931.106SkamilCLONE_TEST2(clone_vfork_signalignored, CLONE_VFORK, true, false)
74941.106SkamilCLONE_TEST2(clone_vfork_signalmasked, CLONE_VFORK, false, true)
74951.103Skamil#endif
74961.110Skamil#endif
74971.103Skamil
74981.103Skamil/// ----------------------------------------------------------------------------
74991.103Skamil
75001.111Skamil#if TEST_VFORK_ENABLED
75011.107Skamil#if defined(TWAIT_HAVE_PID)
75021.107Skamilstatic void
75031.107Skamiltraceme_vfork_clone_body(int flags)
75041.107Skamil{
75051.107Skamil	const int exitval = 5;
75061.107Skamil	const int exitval2 = 15;
75071.107Skamil	pid_t child, child2 = 0, wpid;
75081.107Skamil#if defined(TWAIT_HAVE_STATUS)
75091.107Skamil	int status;
75101.107Skamil#endif
75111.107Skamil
75121.107Skamil	const size_t stack_size = 1024 * 1024;
75131.107Skamil	void *stack, *stack_base;
75141.107Skamil
75151.107Skamil	stack = malloc(stack_size);
75161.107Skamil	ATF_REQUIRE(stack != NULL);
75171.107Skamil
75181.107Skamil#ifdef __MACHINE_STACK_GROWS_UP
75191.107Skamil	stack_base = stack;
75201.107Skamil#else
75211.107Skamil	stack_base = (char *)stack + stack_size;
75221.107Skamil#endif
75231.107Skamil
75241.107Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
75251.107Skamil	if (child == 0) {
75261.107Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
75271.107Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
75281.107Skamil
75291.107Skamil		DPRINTF("Before forking process PID=%d flags=%#x\n", getpid(),
75301.107Skamil		    flags);
75311.107Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
75321.107Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
75331.107Skamil
75341.107Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
75351.107Skamil		    child2);
75361.107Skamil
75371.107Skamil		// XXX WALLSIG?
75381.107Skamil		FORKEE_REQUIRE_SUCCESS
75391.107Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
75401.107Skamil
75411.107Skamil		forkee_status_exited(status, exitval2);
75421.107Skamil
75431.107Skamil		DPRINTF("Before exiting of the child process\n");
75441.107Skamil		_exit(exitval);
75451.107Skamil	}
75461.107Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
75471.107Skamil
75481.107Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
75491.107Skamil	    TWAIT_FNAME);
75501.107Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
75511.107Skamil
75521.107Skamil	validate_status_exited(status, exitval);
75531.107Skamil
75541.107Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
75551.107Skamil	    TWAIT_FNAME);
75561.107Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
75571.107Skamil}
75581.107Skamil
75591.107Skamil#define TRACEME_VFORK_CLONE_TEST(name,flags)				\
75601.107SkamilATF_TC(name);								\
75611.107SkamilATF_TC_HEAD(name, tc)							\
75621.107Skamil{									\
75631.107Skamil	atf_tc_set_md_var(tc, "descr", "Verify that clone(%s) is "	\
75641.107Skamil	    "handled correctly with vfork(2)ed tracer", 		\
75651.107Skamil	    #flags);							\
75661.107Skamil}									\
75671.107Skamil									\
75681.107SkamilATF_TC_BODY(name, tc)							\
75691.107Skamil{									\
75701.107Skamil									\
75711.107Skamil	traceme_vfork_clone_body(flags);				\
75721.107Skamil}
75731.107Skamil
75741.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone, 0)
75751.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_vm, CLONE_VM)
75761.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_fs, CLONE_FS)
75771.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_files, CLONE_FILES)
75781.107Skamil//TRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_sighand, CLONE_SIGHAND)  // XXX
75791.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_vfork, CLONE_VFORK)
75801.107Skamil#endif
75811.110Skamil#endif
75821.107Skamil
75831.107Skamil/// ----------------------------------------------------------------------------
75841.107Skamil
75851.122Skamilstatic void
75861.122Skamiluser_va0_disable(int operation)
75871.122Skamil{
75881.122Skamil	pid_t child, wpid;
75891.122Skamil#if defined(TWAIT_HAVE_STATUS)
75901.122Skamil	int status;
75911.122Skamil#endif
75921.122Skamil	const int sigval = SIGSTOP;
75931.122Skamil	int rv;
75941.122Skamil
75951.122Skamil	struct ptrace_siginfo info;
75961.122Skamil
75971.122Skamil	if (get_user_va0_disable() == 0)
75981.122Skamil		atf_tc_skip("vm.user_va0_disable is set to 0");
75991.122Skamil
76001.122Skamil	memset(&info, 0, sizeof(info));
76011.122Skamil
76021.122Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
76031.122Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
76041.122Skamil	if (child == 0) {
76051.122Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
76061.122Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
76071.122Skamil
76081.122Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
76091.122Skamil		FORKEE_ASSERT(raise(sigval) == 0);
76101.122Skamil
76111.122Skamil		/* NOTREACHED */
76121.122Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
76131.122Skamil		__unreachable();
76141.122Skamil	}
76151.122Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
76161.122Skamil
76171.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76181.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
76191.122Skamil
76201.122Skamil	validate_status_stopped(status, sigval);
76211.122Skamil
76221.122Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
76231.122Skamil		"child\n");
76241.122Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
76251.122Skamil		sizeof(info)) != -1);
76261.122Skamil
76271.122Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
76281.122Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
76291.122Skamil		"si_errno=%#x\n",
76301.122Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
76311.122Skamil		info.psi_siginfo.si_errno);
76321.122Skamil
76331.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
76341.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
76351.122Skamil
76361.122Skamil	DPRINTF("Before resuming the child process in PC=0x0 "
76371.122Skamil	    "and without signal to be sent\n");
76381.122Skamil	errno = 0;
76391.122Skamil	rv = ptrace(operation, child, (void *)0, 0);
76401.122Skamil	ATF_REQUIRE_EQ(errno, EINVAL);
76411.122Skamil	ATF_REQUIRE_EQ(rv, -1);
76421.122Skamil
76431.122Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
76441.122Skamil
76451.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76461.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
76471.122Skamil	validate_status_signaled(status, SIGKILL, 0);
76481.122Skamil
76491.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76501.122Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
76511.122Skamil}
76521.122Skamil
76531.122Skamil#define USER_VA0_DISABLE(test, operation)				\
76541.122SkamilATF_TC(test);								\
76551.122SkamilATF_TC_HEAD(test, tc)							\
76561.122Skamil{									\
76571.122Skamil	atf_tc_set_md_var(tc, "descr",					\
76581.122Skamil	    "Verify behavior of " #operation " with PC set to 0x0");	\
76591.122Skamil}									\
76601.122Skamil									\
76611.122SkamilATF_TC_BODY(test, tc)							\
76621.122Skamil{									\
76631.122Skamil									\
76641.122Skamil	user_va0_disable(operation);					\
76651.122Skamil}
76661.122Skamil
76671.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_continue, PT_CONTINUE)
76681.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_syscall, PT_SYSCALL)
76691.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_detach, PT_DETACH)
76701.122Skamil
76711.122Skamil/// ----------------------------------------------------------------------------
76721.122Skamil
76731.130Smgorny/*
76741.130Smgorny * Parse the core file and find the requested note.  If the reading or parsing
76751.130Smgorny * fails, the test is failed.  If the note is found, it is read onto buf, up to
76761.130Smgorny * buf_len.  The actual length of the note is returned (which can be greater
76771.130Smgorny * than buf_len, indicating that it has been truncated).  If the note is not
76781.130Smgorny * found, -1 is returned.
76791.130Smgorny */
76801.130Smgornystatic ssize_t core_find_note(const char *core_path,
76811.130Smgorny    const char *note_name, uint64_t note_type, void *buf, size_t buf_len)
76821.130Smgorny{
76831.130Smgorny	int core_fd;
76841.130Smgorny	Elf *core_elf;
76851.130Smgorny	size_t core_numhdr, i;
76861.130Smgorny	ssize_t ret = -1;
76871.130Smgorny	/* note: we assume note name will be null-terminated */
76881.130Smgorny	size_t name_len = strlen(note_name) + 1;
76891.130Smgorny
76901.130Smgorny	SYSCALL_REQUIRE((core_fd = open(core_path, O_RDONLY)) != -1);
76911.130Smgorny	SYSCALL_REQUIRE(elf_version(EV_CURRENT) != EV_NONE);
76921.130Smgorny	SYSCALL_REQUIRE((core_elf = elf_begin(core_fd, ELF_C_READ, NULL)));
76931.130Smgorny
76941.130Smgorny	SYSCALL_REQUIRE(elf_getphnum(core_elf, &core_numhdr) != 0);
76951.130Smgorny	for (i = 0; i < core_numhdr && ret == -1; i++) {
76961.130Smgorny		GElf_Phdr core_hdr;
76971.130Smgorny		size_t offset;
76981.130Smgorny		SYSCALL_REQUIRE(gelf_getphdr(core_elf, i, &core_hdr));
76991.130Smgorny		if (core_hdr.p_type != PT_NOTE)
77001.130Smgorny		    continue;
77011.130Smgorny
77021.130Smgorny		for (offset = core_hdr.p_offset;
77031.130Smgorny		    offset < core_hdr.p_offset + core_hdr.p_filesz;) {
77041.130Smgorny			Elf64_Nhdr note_hdr;
77051.130Smgorny			char name_buf[64];
77061.130Smgorny
77071.130Smgorny			switch (gelf_getclass(core_elf)) {
77081.130Smgorny			case ELFCLASS64:
77091.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &note_hdr,
77101.130Smgorny				    sizeof(note_hdr), offset)
77111.130Smgorny				    == sizeof(note_hdr));
77121.130Smgorny				offset += sizeof(note_hdr);
77131.130Smgorny				break;
77141.130Smgorny			case ELFCLASS32:
77151.130Smgorny				{
77161.130Smgorny				Elf32_Nhdr tmp_hdr;
77171.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &tmp_hdr,
77181.130Smgorny				    sizeof(tmp_hdr), offset)
77191.130Smgorny				    == sizeof(tmp_hdr));
77201.130Smgorny				offset += sizeof(tmp_hdr);
77211.130Smgorny				note_hdr.n_namesz = tmp_hdr.n_namesz;
77221.130Smgorny				note_hdr.n_descsz = tmp_hdr.n_descsz;
77231.130Smgorny				note_hdr.n_type = tmp_hdr.n_type;
77241.130Smgorny				}
77251.130Smgorny				break;
77261.130Smgorny			}
77271.130Smgorny
77281.130Smgorny			/* indicates end of notes */
77291.130Smgorny			if (note_hdr.n_namesz == 0 || note_hdr.n_descsz == 0)
77301.130Smgorny				break;
77311.130Smgorny			if (note_hdr.n_namesz == name_len &&
77321.130Smgorny			    note_hdr.n_namesz <= sizeof(name_buf)) {
77331.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, name_buf,
77341.130Smgorny				    note_hdr.n_namesz, offset)
77351.131Skamil				    == (ssize_t)(size_t)note_hdr.n_namesz);
77361.130Smgorny
77371.130Smgorny				if (!strncmp(note_name, name_buf, name_len) &&
77381.130Smgorny				    note_hdr.n_type == note_type)
77391.130Smgorny					ret = note_hdr.n_descsz;
77401.130Smgorny			}
77411.130Smgorny
77421.130Smgorny			offset += note_hdr.n_namesz;
77431.130Smgorny			/* fix to alignment */
77441.130Smgorny			offset = ((offset + core_hdr.p_align - 1)
77451.130Smgorny			    / core_hdr.p_align) * core_hdr.p_align;
77461.130Smgorny
77471.130Smgorny			/* if name & type matched above */
77481.130Smgorny			if (ret != -1) {
77491.130Smgorny				ssize_t read_len = MIN(buf_len,
77501.130Smgorny				    note_hdr.n_descsz);
77511.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, buf,
77521.130Smgorny				    read_len, offset) == read_len);
77531.130Smgorny				break;
77541.130Smgorny			}
77551.130Smgorny
77561.130Smgorny			offset += note_hdr.n_descsz;
77571.130Smgorny		}
77581.130Smgorny	}
77591.130Smgorny
77601.130Smgorny	elf_end(core_elf);
77611.130Smgorny	close(core_fd);
77621.130Smgorny
77631.130Smgorny	return ret;
77641.130Smgorny}
77651.130Smgorny
77661.130SmgornyATF_TC(core_dump_procinfo);
77671.130SmgornyATF_TC_HEAD(core_dump_procinfo, tc)
77681.130Smgorny{
77691.130Smgorny	atf_tc_set_md_var(tc, "descr",
77701.130Smgorny		"Trigger a core dump and verify its contents.");
77711.130Smgorny}
77721.130Smgorny
77731.130SmgornyATF_TC_BODY(core_dump_procinfo, tc)
77741.130Smgorny{
77751.130Smgorny	const int exitval = 5;
77761.130Smgorny	pid_t child, wpid;
77771.130Smgorny#if defined(TWAIT_HAVE_STATUS)
77781.130Smgorny	const int sigval = SIGTRAP;
77791.130Smgorny	int status;
77801.130Smgorny#endif
77811.130Smgorny	char core_path[] = "/tmp/core.XXXXXX";
77821.130Smgorny	int core_fd;
77831.130Smgorny	struct netbsd_elfcore_procinfo procinfo;
77841.130Smgorny
77851.130Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
77861.130Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
77871.130Smgorny	if (child == 0) {
77881.130Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
77891.130Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
77901.130Smgorny
77911.130Smgorny		DPRINTF("Before triggering SIGTRAP\n");
77921.130Smgorny		trigger_trap();
77931.130Smgorny
77941.130Smgorny		DPRINTF("Before exiting of the child process\n");
77951.130Smgorny		_exit(exitval);
77961.130Smgorny	}
77971.130Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
77981.130Smgorny
77991.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
78001.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
78011.130Smgorny
78021.130Smgorny	validate_status_stopped(status, sigval);
78031.130Smgorny
78041.130Smgorny	SYSCALL_REQUIRE((core_fd = mkstemp(core_path)) != -1);
78051.130Smgorny	close(core_fd);
78061.130Smgorny
78071.130Smgorny	DPRINTF("Call DUMPCORE for the child process\n");
78081.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_DUMPCORE, child, core_path, strlen(core_path))
78091.130Smgorny	    != -1);
78101.130Smgorny
78111.130Smgorny	DPRINTF("Read core file\n");
78121.130Smgorny	ATF_REQUIRE_EQ(core_find_note(core_path, "NetBSD-CORE",
78131.130Smgorny	    ELF_NOTE_NETBSD_CORE_PROCINFO, &procinfo, sizeof(procinfo)),
78141.130Smgorny	    sizeof(procinfo));
78151.130Smgorny
78161.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_version, 1);
78171.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_cpisize, sizeof(procinfo));
78181.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_signo, SIGTRAP);
78191.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pid, child);
78201.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ppid, getpid());
78211.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pgrp, getpgid(child));
78221.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_sid, getsid(child));
78231.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ruid, getuid());
78241.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_euid, geteuid());
78251.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_rgid, getgid());
78261.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_egid, getegid());
78271.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_nlwps, 1);
78281.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_siglwp, 1);
78291.130Smgorny
78301.130Smgorny	unlink(core_path);
78311.130Smgorny
78321.130Smgorny	DPRINTF("Before resuming the child process where it left off and "
78331.130Smgorny	    "without signal to be sent\n");
78341.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
78351.130Smgorny
78361.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
78371.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
78381.130Smgorny
78391.130Smgorny	validate_status_exited(status, exitval);
78401.130Smgorny
78411.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
78421.130Smgorny	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
78431.130Smgorny}
78441.130Smgorny
78451.130Smgorny/// ----------------------------------------------------------------------------
78461.130Smgorny
78471.1Skamil#include "t_ptrace_amd64_wait.h"
78481.1Skamil#include "t_ptrace_i386_wait.h"
78491.1Skamil#include "t_ptrace_x86_wait.h"
78501.1Skamil
78511.1SkamilATF_TP_ADD_TCS(tp)
78521.1Skamil{
78531.1Skamil	setvbuf(stdout, NULL, _IONBF, 0);
78541.1Skamil	setvbuf(stderr, NULL, _IONBF, 0);
78551.33Skamil
78561.36Skamil	ATF_TP_ADD_TC(tp, traceme_raise1);
78571.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise2);
78581.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise3);
78591.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise4);
78601.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise5);
78611.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise6);
78621.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise7);
78631.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise8);
78641.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise9);
78651.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise10);
78661.33Skamil
78671.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored1);
78681.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored2);
78691.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored3);
78701.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored4);
78711.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored5);
78721.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored6);
78731.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored7);
78741.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored8);
78751.87Skamil
78761.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked1);
78771.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked2);
78781.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked3);
78791.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked4);
78801.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked5);
78811.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked6);
78821.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked7);
78831.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked8);
78841.86Skamil
78851.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_trap);
78861.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_segv);
78871.71Skamil	ATF_TP_ADD_TC(tp, traceme_crash_ill);
78881.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_fpe);
78891.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_bus);
78901.59Skamil
78911.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_trap);
78921.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_segv);
78931.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_ill);
78941.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_fpe);
78951.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_bus);
78961.88Skamil
78971.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_trap);
78981.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_segv);
78991.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_ill);
79001.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_fpe);
79011.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_bus);
79021.88Skamil
79031.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle1);
79041.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle2);
79051.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle3);
79061.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle4);
79071.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle5);
79081.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle6);
79091.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle7);
79101.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle8);
79111.50Skamil
79121.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked1);
79131.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked2);
79141.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked3);
79151.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked4);
79161.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked5);
79171.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked6);
79181.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked7);
79191.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked8);
79201.50Skamil
79211.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored1);
79221.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored2);
79231.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored3);
79241.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored4);
79251.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored5);
79261.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored6);
79271.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored7);
79281.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored8);
79291.50Skamil
79301.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple1);
79311.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple2);
79321.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple3);
79331.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple4);
79341.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple5);
79351.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple6);
79361.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple7);
79371.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple8);
79381.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple9);
79391.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple10);
79401.1Skamil
79411.37Skamil	ATF_TP_ADD_TC(tp, traceme_pid1_parent);
79421.37Skamil
79431.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise1);
79441.46Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise2);
79451.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise3);
79461.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise4);
79471.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise5);
79481.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise6);
79491.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise7);
79501.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise8);
79511.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise9);
79521.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise10);
79531.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise11);
79541.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise12);
79551.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise13);
79561.40Skamil
79571.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_trap);
79581.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_segv);
79591.71Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_ill);
79601.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_fpe);
79611.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_bus);
79621.41Skamil
79631.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_trap);
79641.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_segv);
79651.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_ill);
79661.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_fpe);
79671.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_bus);
79681.92Skamil
79691.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_trap);
79701.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_segv);
79711.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_ill);
79721.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_fpe);
79731.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_bus);
79741.92Skamil
79751.43Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_exec);
79761.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_exec);
79771.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_exec);
79781.43Skamil
79791.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_trap);
79801.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_segv);
79811.71Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_ill);
79821.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_fpe);
79831.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_bus);
79841.59Skamil
79851.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79861.94Skamil	    unrelated_tracer_sees_signalmasked_crash_trap);
79871.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79881.94Skamil	    unrelated_tracer_sees_signalmasked_crash_segv);
79891.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79901.94Skamil	    unrelated_tracer_sees_signalmasked_crash_ill);
79911.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79921.94Skamil	    unrelated_tracer_sees_signalmasked_crash_fpe);
79931.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79941.94Skamil	    unrelated_tracer_sees_signalmasked_crash_bus);
79951.94Skamil
79961.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79971.94Skamil	    unrelated_tracer_sees_signalignored_crash_trap);
79981.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79991.94Skamil	    unrelated_tracer_sees_signalignored_crash_segv);
80001.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
80011.94Skamil	    unrelated_tracer_sees_signalignored_crash_ill);
80021.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
80031.94Skamil	    unrelated_tracer_sees_signalignored_crash_fpe);
80041.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
80051.94Skamil	    unrelated_tracer_sees_signalignored_crash_bus);
80061.94Skamil
80071.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sees_terminaton_before_the_parent);
80081.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sysctl_lookup_without_duplicates);
80091.61Skre	ATF_TP_ADD_TC_HAVE_PID(tp,
80101.61Skre		unrelated_tracer_sees_terminaton_before_the_parent);
80111.67Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_attach_to_unrelated_stopped_process);
80121.51Skamil
80131.51Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_child);
80141.66Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_stopped_child);
80151.51Skamil
80161.51Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_parent);
80171.65Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_stopped_parent);
80181.51Skamil
80191.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
80201.51Skamil		tracee_sees_its_original_parent_getppid);
80211.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
80221.51Skamil		tracee_sees_its_original_parent_sysctl_kinfo_proc2);
80231.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
80241.51Skamil		tracee_sees_its_original_parent_procfs_status);
80251.1Skamil
80261.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_empty);
80271.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_fork);
80281.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork);
80291.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork_done);
80301.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_create);
80311.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_exit);
80321.125Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_posix_spawn);
80331.1Skamil
80341.31Skamil	ATF_TP_ADD_TC(tp, fork1);
80351.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork2);
80361.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork3);
80371.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork4);
80381.31Skamil	ATF_TP_ADD_TC(tp, fork5);
80391.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork6);
80401.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork7);
80411.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork8);
80421.125Skamil	ATF_TP_ADD_TC(tp, fork9);
80431.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork10);
80441.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork11);
80451.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork12);
80461.125Skamil	ATF_TP_ADD_TC(tp, fork13);
80471.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork14);
80481.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork15);
80491.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork16);
80501.31Skamil
80511.109Skamil#if TEST_VFORK_ENABLED
80521.31Skamil	ATF_TP_ADD_TC(tp, vfork1);
80531.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork2);
80541.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork3);
80551.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork4);
80561.31Skamil	ATF_TP_ADD_TC(tp, vfork5);
80571.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork6);
80581.104Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork7);
80591.104Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork8);
80601.125Skamil	ATF_TP_ADD_TC(tp, vfork9);
80611.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork10);
80621.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork11);
80631.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork12);
80641.125Skamil	ATF_TP_ADD_TC(tp, vfork13);
80651.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork14);
80661.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork15);
80671.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork16);
80681.116Skamil#endif
80691.1Skamil
80701.124Skamil	ATF_TP_ADD_TC(tp, posix_spawn1);
80711.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn2);
80721.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn3);
80731.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn4);
80741.124Skamil	ATF_TP_ADD_TC(tp, posix_spawn5);
80751.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn6);
80761.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn7);
80771.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn8);
80781.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn9);
80791.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn10);
80801.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn11);
80811.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn12);
80821.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn13);
80831.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn14);
80841.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn15);
80851.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn16);
80861.124Skamil
80871.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_detach_spawner);
80881.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_detach_forker);
80891.116Skamil#if TEST_VFORK_ENABLED
80901.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_detach_vforker);
80911.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_detach_vforkerdone);
80921.116Skamil#endif
80931.126Skamil
80941.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_kill_spawner);
80951.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_kill_forker);
80961.116Skamil#if TEST_VFORK_ENABLED
80971.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_kill_vforker);
80981.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_kill_vforkerdone);
80991.116Skamil#endif
81001.116Skamil
81011.116Skamil#if TEST_VFORK_ENABLED
81021.108Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_fork);
81031.108Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_vfork);
81041.109Skamil#endif
81051.108Skamil
81061.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8);
81071.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16);
81081.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32);
81091.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64);
81101.54Skamil
81111.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8);
81121.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16);
81131.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32);
81141.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64);
81151.54Skamil
81161.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8);
81171.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16);
81181.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32);
81191.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64);
81201.54Skamil
81211.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8);
81221.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16);
81231.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32);
81241.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64);
81251.54Skamil
81261.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d);
81271.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i);
81281.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d);
81291.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i);
81301.54Skamil
81311.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8_text);
81321.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16_text);
81331.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32_text);
81341.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64_text);
81351.54Skamil
81361.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8_text);
81371.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16_text);
81381.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32_text);
81391.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64_text);
81401.54Skamil
81411.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8_text);
81421.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16_text);
81431.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32_text);
81441.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64_text);
81451.54Skamil
81461.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8_text);
81471.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16_text);
81481.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32_text);
81491.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64_text);
81501.54Skamil
81511.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d_text);
81521.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i_text);
81531.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d_text);
81541.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i_text);
81551.1Skamil
81561.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_auxv);
81571.1Skamil
81581.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_i);
81591.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_d);
81601.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_i);
81611.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_d);
81621.101Skamil
81631.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_i);
81641.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_d);
81651.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_i);
81661.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_d);
81671.101Skamil
81681.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_auxv);
81691.101Skamil
81701.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_i);
81711.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_d);
81721.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_i);
81731.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_d);
81741.115Skamil
81751.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_i);
81761.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_d);
81771.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_i);
81781.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_d);
81791.115Skamil
81801.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs1);
81811.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs2);
81821.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs3);
81831.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs4);
81841.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs5);
81851.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs6);
81861.1Skamil
81871.72Skamil	ATF_TP_ADD_TC_HAVE_FPREGS(tp, access_fpregs1);
81881.72Skamil	ATF_TP_ADD_TC_HAVE_FPREGS(tp, access_fpregs2);
81891.1Skamil
81901.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step1);
81911.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step2);
81921.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step3);
81931.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step4);
81941.1Skamil
81951.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep1);
81961.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep2);
81971.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep3);
81981.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep4);
81991.2Skamil
82001.95Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step_signalmasked);
82011.95Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step_signalignored);
82021.95Skamil
82031.1Skamil	ATF_TP_ADD_TC(tp, kill1);
82041.1Skamil	ATF_TP_ADD_TC(tp, kill2);
82051.75Skamil	ATF_TP_ADD_TC(tp, kill3);
82061.1Skamil
82071.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0);
82081.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1);
82091.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2);
82101.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3);
82111.77Skamil
82121.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo0);
82131.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo1);
82141.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo2);
82151.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo3);
82161.1Skamil
82171.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_unmodified);
82181.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_faked);
82191.79Skamil
82201.82Skamil	ATF_TP_ADD_TC(tp, traceme_exec);
82211.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_exec);
82221.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_exec);
82231.1Skamil
82241.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_nolwpevents);
82251.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit);
82261.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate);
82271.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit);
82281.1Skamil
82291.84Skamil	ATF_TP_ADD_TC(tp, signal_mask_unrelated);
82301.84Skamil
82311.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_singalmasked);
82321.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_singalignored);
82331.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_singalmasked);
82341.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_singalignored);
82351.109Skamil#if TEST_VFORK_ENABLED
82361.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_singalmasked);
82371.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_singalignored);
82381.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vforkdone_singalmasked);
82391.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vforkdone_singalignored);
82401.109Skamil#endif
82411.99Skamil
82421.1Skamil	ATF_TP_ADD_TC(tp, signal9);
82431.1Skamil	ATF_TP_ADD_TC(tp, signal10);
82441.1Skamil
82451.1Skamil	ATF_TP_ADD_TC(tp, suspend1);
82461.1Skamil	ATF_TP_ADD_TC(tp, suspend2);
82471.1Skamil
82481.1Skamil	ATF_TP_ADD_TC(tp, resume1);
82491.1Skamil
82501.1Skamil	ATF_TP_ADD_TC(tp, syscall1);
82511.1Skamil
82521.1Skamil	ATF_TP_ADD_TC(tp, syscallemu1);
82531.1Skamil
82541.106Skamil	ATF_TP_ADD_TC(tp, clone1);
82551.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone2);
82561.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone3);
82571.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone4);
82581.106Skamil	ATF_TP_ADD_TC(tp, clone5);
82591.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone6);
82601.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone7);
82611.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone8);
82621.106Skamil
82631.106Skamil	ATF_TP_ADD_TC(tp, clone_vm1);
82641.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm2);
82651.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm3);
82661.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm4);
82671.106Skamil	ATF_TP_ADD_TC(tp, clone_vm5);
82681.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm6);
82691.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm7);
82701.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm8);
82711.106Skamil
82721.106Skamil	ATF_TP_ADD_TC(tp, clone_fs1);
82731.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs2);
82741.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs3);
82751.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs4);
82761.106Skamil	ATF_TP_ADD_TC(tp, clone_fs5);
82771.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs6);
82781.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs7);
82791.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs8);
82801.106Skamil
82811.106Skamil	ATF_TP_ADD_TC(tp, clone_files1);
82821.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files2);
82831.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files3);
82841.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files4);
82851.106Skamil	ATF_TP_ADD_TC(tp, clone_files5);
82861.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files6);
82871.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files7);
82881.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files8);
82891.106Skamil
82901.106Skamil//	ATF_TP_ADD_TC(tp, clone_sighand1); // XXX
82911.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand2); // XXX
82921.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand3); // XXX
82931.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand4); // XXX
82941.106Skamil//	ATF_TP_ADD_TC(tp, clone_sighand5); // XXX
82951.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand6); // XXX
82961.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand7); // XXX
82971.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand8); // XXX
82981.106Skamil
82991.109Skamil#if TEST_VFORK_ENABLED
83001.106Skamil	ATF_TP_ADD_TC(tp, clone_vfork1);
83011.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork2);
83021.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork3);
83031.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork4);
83041.106Skamil	ATF_TP_ADD_TC(tp, clone_vfork5);
83051.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork6);
83061.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork7);
83071.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork8);
83081.109Skamil#endif
83091.106Skamil
83101.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_signalignored);
83111.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_signalmasked);
83121.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm_signalignored);
83131.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm_signalmasked);
83141.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs_signalignored);
83151.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs_signalmasked);
83161.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files_signalignored);
83171.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files_signalmasked);
83181.103Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand_signalignored); // XXX
83191.103Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand_signalmasked); // XXX
83201.109Skamil#if TEST_VFORK_ENABLED
83211.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork_signalignored);
83221.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork_signalmasked);
83231.109Skamil#endif
83241.103Skamil
83251.109Skamil#if TEST_VFORK_ENABLED
83261.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone);
83271.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_vm);
83281.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_fs);
83291.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_files);
83301.107Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_sighand); // XXX
83311.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_vfork);
83321.109Skamil#endif
83331.107Skamil
83341.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_continue);
83351.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall);
83361.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach);
83371.122Skamil
83381.130Smgorny	ATF_TP_ADD_TC(tp, core_dump_procinfo);
83391.130Smgorny
83401.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
83411.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_I386();
83421.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_X86();
83431.1Skamil
83441.1Skamil	return atf_no_error();
83451.1Skamil}
8346