t_ptrace_wait.c revision 1.132
11.132Skamil/*	$NetBSD: t_ptrace_wait.c,v 1.132 2019/10/01 21:13:30 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.132Skamil__RCSID("$NetBSD: t_ptrace_wait.c,v 1.132 2019/10/01 21:13:30 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.45Skamil	struct ptrace_siginfo info;
1441.45Skamil	memset(&info, 0, sizeof(info));
1451.45Skamil
1461.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
1471.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
1481.1Skamil	if (child == 0) {
1491.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1501.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
1511.1Skamil
1521.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
1531.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
1541.1Skamil
1551.36Skamil		switch (sigval) {
1561.36Skamil		case SIGKILL:
1571.36Skamil			/* NOTREACHED */
1581.36Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
1591.70Smrg			__unreachable();
1601.36Skamil		default:
1611.36Skamil			DPRINTF("Before exiting of the child process\n");
1621.36Skamil			_exit(exitval);
1631.36Skamil		}
1641.1Skamil	}
1651.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
1661.1Skamil
1671.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1681.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
1691.1Skamil
1701.36Skamil	switch (sigval) {
1711.36Skamil	case SIGKILL:
1721.36Skamil		validate_status_signaled(status, sigval, 0);
1731.36Skamil		break;
1741.36Skamil	default:
1751.36Skamil		validate_status_stopped(status, sigval);
1761.1Skamil
1771.45Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
1781.61Skre			"child\n");
1791.45Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
1801.61Skre			sizeof(info)) != -1);
1811.45Skamil
1821.45Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
1831.45Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
1841.61Skre			"si_errno=%#x\n",
1851.61Skre			info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
1861.61Skre			info.psi_siginfo.si_errno);
1871.45Skamil
1881.45Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
1891.45Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
1901.45Skamil
1911.36Skamil		DPRINTF("Before resuming the child process where it left off "
1921.36Skamil		    "and without signal to be sent\n");
1931.36Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
1941.1Skamil
1951.36Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1961.36Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
1971.61Skre		    child);
1981.36Skamil		break;
1991.36Skamil	}
2001.1Skamil
2011.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2021.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
2031.1Skamil}
2041.1Skamil
2051.61Skre#define TRACEME_RAISE(test, sig)					\
2061.61SkreATF_TC(test);								\
2071.61SkreATF_TC_HEAD(test, tc)							\
2081.61Skre{									\
2091.61Skre	atf_tc_set_md_var(tc, "descr",					\
2101.61Skre	    "Verify " #sig " followed by _exit(2) in a child");		\
2111.61Skre}									\
2121.61Skre									\
2131.61SkreATF_TC_BODY(test, tc)							\
2141.61Skre{									\
2151.61Skre									\
2161.61Skre	traceme_raise(sig);						\
2171.33Skamil}
2181.33Skamil
2191.36SkamilTRACEME_RAISE(traceme_raise1, SIGKILL) /* non-maskable */
2201.33SkamilTRACEME_RAISE(traceme_raise2, SIGSTOP) /* non-maskable */
2211.33SkamilTRACEME_RAISE(traceme_raise3, SIGABRT) /* regular abort trap */
2221.33SkamilTRACEME_RAISE(traceme_raise4, SIGHUP)  /* hangup */
2231.33SkamilTRACEME_RAISE(traceme_raise5, SIGCONT) /* continued? */
2241.85SkamilTRACEME_RAISE(traceme_raise6, SIGTRAP) /* crash signal */
2251.85SkamilTRACEME_RAISE(traceme_raise7, SIGBUS) /* crash signal */
2261.85SkamilTRACEME_RAISE(traceme_raise8, SIGILL) /* crash signal */
2271.85SkamilTRACEME_RAISE(traceme_raise9, SIGFPE) /* crash signal */
2281.85SkamilTRACEME_RAISE(traceme_raise10, SIGSEGV) /* crash signal */
2291.33Skamil
2301.34Skamil/// ----------------------------------------------------------------------------
2311.1Skamil
2321.1Skamilstatic void
2331.87Skamiltraceme_raisesignal_ignored(int sigignored)
2341.87Skamil{
2351.87Skamil	const int exitval = 5;
2361.87Skamil	const int sigval = SIGSTOP;
2371.87Skamil	pid_t child, wpid;
2381.87Skamil	struct sigaction sa;
2391.87Skamil#if defined(TWAIT_HAVE_STATUS)
2401.87Skamil	int status;
2411.87Skamil#endif
2421.87Skamil	struct ptrace_siginfo info;
2431.87Skamil
2441.87Skamil	memset(&info, 0, sizeof(info));
2451.87Skamil
2461.87Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
2471.87Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
2481.87Skamil	if (child == 0) {
2491.87Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
2501.87Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
2511.87Skamil
2521.87Skamil		memset(&sa, 0, sizeof(sa));
2531.87Skamil		sa.sa_handler = SIG_IGN;
2541.87Skamil		sigemptyset(&sa.sa_mask);
2551.87Skamil		FORKEE_ASSERT(sigaction(sigignored, &sa, NULL) != -1);
2561.87Skamil
2571.87Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
2581.87Skamil		FORKEE_ASSERT(raise(sigval) == 0);
2591.87Skamil
2601.87Skamil		DPRINTF("Before raising %s from child\n",
2611.87Skamil		    strsignal(sigignored));
2621.87Skamil		FORKEE_ASSERT(raise(sigignored) == 0);
2631.87Skamil
2641.87Skamil		DPRINTF("Before exiting of the child process\n");
2651.87Skamil		_exit(exitval);
2661.87Skamil	}
2671.87Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
2681.87Skamil
2691.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2701.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2711.87Skamil
2721.87Skamil	validate_status_stopped(status, sigval);
2731.87Skamil
2741.87Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
2751.87Skamil	SYSCALL_REQUIRE(
2761.87Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
2771.87Skamil
2781.87Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
2791.87Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
2801.87Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
2811.87Skamil	    info.psi_siginfo.si_errno);
2821.87Skamil
2831.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
2841.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
2851.87Skamil
2861.87Skamil	DPRINTF("Before resuming the child process where it left off and "
2871.87Skamil	    "without signal to be sent\n");
2881.87Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
2891.87Skamil
2901.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2911.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2921.87Skamil
2931.87Skamil	validate_status_stopped(status, sigignored);
2941.87Skamil
2951.87Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
2961.87Skamil	SYSCALL_REQUIRE(
2971.87Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
2981.87Skamil
2991.87Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
3001.87Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
3011.87Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
3021.87Skamil	    info.psi_siginfo.si_errno);
3031.87Skamil
3041.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigignored);
3051.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
3061.87Skamil
3071.87Skamil	DPRINTF("Before resuming the child process where it left off and "
3081.87Skamil	    "without signal to be sent\n");
3091.87Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
3101.87Skamil
3111.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3121.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
3131.87Skamil
3141.87Skamil	validate_status_exited(status, exitval);
3151.87Skamil
3161.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3171.87Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
3181.87Skamil}
3191.87Skamil
3201.87Skamil#define TRACEME_RAISESIGNAL_IGNORED(test, sig)				\
3211.87SkamilATF_TC(test);								\
3221.87SkamilATF_TC_HEAD(test, tc)							\
3231.87Skamil{									\
3241.87Skamil	atf_tc_set_md_var(tc, "descr",					\
3251.87Skamil	    "Verify that ignoring (with SIG_IGN) " #sig " in tracee "	\
3261.87Skamil	    "does not stop tracer from catching this raised signal");	\
3271.87Skamil}									\
3281.87Skamil									\
3291.87SkamilATF_TC_BODY(test, tc)							\
3301.87Skamil{									\
3311.87Skamil									\
3321.87Skamil	traceme_raisesignal_ignored(sig);				\
3331.87Skamil}
3341.87Skamil
3351.87Skamil// A signal handler for SIGKILL and SIGSTOP cannot be ignored.
3361.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored1, SIGABRT) /* abort */
3371.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored2, SIGHUP)  /* hangup */
3381.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored3, SIGCONT) /* cont. */
3391.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored4, SIGTRAP) /* crash */
3401.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored5, SIGBUS) /* crash */
3411.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored6, SIGILL) /* crash */
3421.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored7, SIGFPE) /* crash */
3431.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored8, SIGSEGV) /* crash */
3441.87Skamil
3451.87Skamil/// ----------------------------------------------------------------------------
3461.87Skamil
3471.87Skamilstatic void
3481.86Skamiltraceme_raisesignal_masked(int sigmasked)
3491.86Skamil{
3501.86Skamil	const int exitval = 5;
3511.86Skamil	const int sigval = SIGSTOP;
3521.86Skamil	pid_t child, wpid;
3531.86Skamil#if defined(TWAIT_HAVE_STATUS)
3541.86Skamil	int status;
3551.86Skamil#endif
3561.86Skamil	sigset_t intmask;
3571.86Skamil	struct ptrace_siginfo info;
3581.86Skamil
3591.86Skamil	memset(&info, 0, sizeof(info));
3601.86Skamil
3611.86Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
3621.86Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
3631.86Skamil	if (child == 0) {
3641.86Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
3651.86Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
3661.86Skamil
3671.86Skamil		sigemptyset(&intmask);
3681.86Skamil		sigaddset(&intmask, sigmasked);
3691.86Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
3701.86Skamil
3711.86Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
3721.86Skamil		FORKEE_ASSERT(raise(sigval) == 0);
3731.86Skamil
3741.86Skamil		DPRINTF("Before raising %s breakpoint from child\n",
3751.86Skamil		    strsignal(sigmasked));
3761.86Skamil		FORKEE_ASSERT(raise(sigmasked) == 0);
3771.86Skamil
3781.86Skamil		DPRINTF("Before exiting of the child process\n");
3791.86Skamil		_exit(exitval);
3801.86Skamil	}
3811.86Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
3821.86Skamil
3831.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3841.86Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
3851.86Skamil
3861.86Skamil	validate_status_stopped(status, sigval);
3871.86Skamil
3881.86Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
3891.86Skamil	SYSCALL_REQUIRE(
3901.86Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
3911.86Skamil
3921.86Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
3931.86Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
3941.86Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
3951.86Skamil	    info.psi_siginfo.si_errno);
3961.86Skamil
3971.86Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
3981.86Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
3991.86Skamil
4001.86Skamil	DPRINTF("Before resuming the child process where it left off and "
4011.86Skamil	    "without signal to be sent\n");
4021.86Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
4031.86Skamil
4041.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
4051.86Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
4061.86Skamil
4071.86Skamil	validate_status_exited(status, exitval);
4081.86Skamil
4091.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
4101.86Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
4111.86Skamil}
4121.86Skamil
4131.86Skamil#define TRACEME_RAISESIGNAL_MASKED(test, sig)				\
4141.86SkamilATF_TC(test);								\
4151.86SkamilATF_TC_HEAD(test, tc)							\
4161.86Skamil{									\
4171.86Skamil	atf_tc_set_md_var(tc, "descr",					\
4181.86Skamil	    "Verify that masking (with SIG_BLOCK) " #sig " in tracee "	\
4191.86Skamil	    "stops tracer from catching this raised signal");		\
4201.86Skamil}									\
4211.86Skamil									\
4221.86SkamilATF_TC_BODY(test, tc)							\
4231.86Skamil{									\
4241.86Skamil									\
4251.86Skamil	traceme_raisesignal_masked(sig);				\
4261.86Skamil}
4271.86Skamil
4281.86Skamil// A signal handler for SIGKILL and SIGSTOP cannot be masked.
4291.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked1, SIGABRT) /* abort trap */
4301.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked2, SIGHUP)  /* hangup */
4311.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked3, SIGCONT) /* continued? */
4321.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked4, SIGTRAP) /* crash sig. */
4331.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked5, SIGBUS) /* crash sig. */
4341.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked6, SIGILL) /* crash sig. */
4351.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked7, SIGFPE) /* crash sig. */
4361.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked8, SIGSEGV) /* crash sig. */
4371.86Skamil
4381.86Skamil/// ----------------------------------------------------------------------------
4391.86Skamil
4401.86Skamilstatic void
4411.59Skamiltraceme_crash(int sig)
4421.59Skamil{
4431.59Skamil	pid_t child, wpid;
4441.59Skamil#if defined(TWAIT_HAVE_STATUS)
4451.59Skamil	int status;
4461.59Skamil#endif
4471.59Skamil	struct ptrace_siginfo info;
4481.61Skre
4491.71Skamil#ifndef PTRACE_ILLEGAL_ASM
4501.71Skamil	if (sig == SIGILL)
4511.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
4521.71Skamil#endif
4531.71Skamil
4541.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
4551.114Skamil		atf_tc_skip("FP exceptions are not supported");
4561.114Skamil
4571.59Skamil	memset(&info, 0, sizeof(info));
4581.59Skamil
4591.59Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
4601.59Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
4611.59Skamil	if (child == 0) {
4621.59Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
4631.59Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
4641.59Skamil
4651.59Skamil		DPRINTF("Before executing a trap\n");
4661.59Skamil		switch (sig) {
4671.59Skamil		case SIGTRAP:
4681.59Skamil			trigger_trap();
4691.59Skamil			break;
4701.59Skamil		case SIGSEGV:
4711.59Skamil			trigger_segv();
4721.59Skamil			break;
4731.59Skamil		case SIGILL:
4741.59Skamil			trigger_ill();
4751.59Skamil			break;
4761.59Skamil		case SIGFPE:
4771.59Skamil			trigger_fpe();
4781.59Skamil			break;
4791.59Skamil		case SIGBUS:
4801.59Skamil			trigger_bus();
4811.59Skamil			break;
4821.59Skamil		default:
4831.59Skamil			/* NOTREACHED */
4841.59Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
4851.59Skamil		}
4861.59Skamil
4871.59Skamil		/* NOTREACHED */
4881.59Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
4891.59Skamil	}
4901.59Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
4911.59Skamil
4921.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
4931.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
4941.59Skamil
4951.59Skamil	validate_status_stopped(status, sig);
4961.59Skamil
4971.59Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
4981.61Skre	SYSCALL_REQUIRE(
4991.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
5001.59Skamil
5011.59Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
5021.59Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
5031.61Skre	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
5041.61Skre	    info.psi_siginfo.si_errno);
5051.59Skamil
5061.59Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
5071.59Skamil	switch (sig) {
5081.59Skamil	case SIGTRAP:
5091.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
5101.59Skamil		break;
5111.59Skamil	case SIGSEGV:
5121.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
5131.59Skamil		break;
5141.71Skamil	case SIGILL:
5151.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
5161.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
5171.71Skamil		break;
5181.59Skamil	case SIGFPE:
5191.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
5201.59Skamil		break;
5211.59Skamil	case SIGBUS:
5221.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
5231.59Skamil		break;
5241.59Skamil	}
5251.59Skamil
5261.59Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
5271.59Skamil
5281.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5291.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
5301.59Skamil
5311.59Skamil	validate_status_signaled(status, SIGKILL, 0);
5321.59Skamil
5331.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5341.59Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
5351.59Skamil}
5361.59Skamil
5371.61Skre#define TRACEME_CRASH(test, sig)					\
5381.61SkreATF_TC(test);								\
5391.61SkreATF_TC_HEAD(test, tc)							\
5401.61Skre{									\
5411.61Skre	atf_tc_set_md_var(tc, "descr",					\
5421.61Skre	    "Verify crash signal " #sig " in a child after PT_TRACE_ME"); \
5431.61Skre}									\
5441.61Skre									\
5451.61SkreATF_TC_BODY(test, tc)							\
5461.61Skre{									\
5471.61Skre									\
5481.61Skre	traceme_crash(sig);						\
5491.59Skamil}
5501.59Skamil
5511.59SkamilTRACEME_CRASH(traceme_crash_trap, SIGTRAP)
5521.59SkamilTRACEME_CRASH(traceme_crash_segv, SIGSEGV)
5531.71SkamilTRACEME_CRASH(traceme_crash_ill, SIGILL)
5541.59SkamilTRACEME_CRASH(traceme_crash_fpe, SIGFPE)
5551.59SkamilTRACEME_CRASH(traceme_crash_bus, SIGBUS)
5561.59Skamil
5571.59Skamil/// ----------------------------------------------------------------------------
5581.59Skamil
5591.59Skamilstatic void
5601.88Skamiltraceme_signalmasked_crash(int sig)
5611.88Skamil{
5621.89Skamil	const int sigval = SIGSTOP;
5631.88Skamil	pid_t child, wpid;
5641.88Skamil#if defined(TWAIT_HAVE_STATUS)
5651.88Skamil	int status;
5661.88Skamil#endif
5671.88Skamil	struct ptrace_siginfo info;
5681.88Skamil	sigset_t intmask;
5691.89Skamil	struct kinfo_proc2 kp;
5701.89Skamil	size_t len = sizeof(kp);
5711.89Skamil
5721.89Skamil	int name[6];
5731.89Skamil	const size_t namelen = __arraycount(name);
5741.89Skamil	ki_sigset_t kp_sigmask;
5751.88Skamil
5761.88Skamil#ifndef PTRACE_ILLEGAL_ASM
5771.88Skamil	if (sig == SIGILL)
5781.88Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
5791.88Skamil#endif
5801.88Skamil
5811.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
5821.114Skamil		atf_tc_skip("FP exceptions are not supported");
5831.114Skamil
5841.88Skamil	memset(&info, 0, sizeof(info));
5851.88Skamil
5861.88Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
5871.88Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
5881.88Skamil	if (child == 0) {
5891.88Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
5901.88Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
5911.88Skamil
5921.88Skamil		sigemptyset(&intmask);
5931.88Skamil		sigaddset(&intmask, sig);
5941.88Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
5951.88Skamil
5961.89Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
5971.89Skamil		FORKEE_ASSERT(raise(sigval) == 0);
5981.89Skamil
5991.88Skamil		DPRINTF("Before executing a trap\n");
6001.88Skamil		switch (sig) {
6011.88Skamil		case SIGTRAP:
6021.88Skamil			trigger_trap();
6031.88Skamil			break;
6041.88Skamil		case SIGSEGV:
6051.88Skamil			trigger_segv();
6061.88Skamil			break;
6071.88Skamil		case SIGILL:
6081.88Skamil			trigger_ill();
6091.88Skamil			break;
6101.88Skamil		case SIGFPE:
6111.88Skamil			trigger_fpe();
6121.88Skamil			break;
6131.88Skamil		case SIGBUS:
6141.88Skamil			trigger_bus();
6151.88Skamil			break;
6161.88Skamil		default:
6171.88Skamil			/* NOTREACHED */
6181.88Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
6191.88Skamil		}
6201.88Skamil
6211.88Skamil		/* NOTREACHED */
6221.88Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
6231.88Skamil	}
6241.88Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
6251.88Skamil
6261.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6271.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
6281.88Skamil
6291.89Skamil	validate_status_stopped(status, sigval);
6301.89Skamil
6311.89Skamil	name[0] = CTL_KERN,
6321.89Skamil	name[1] = KERN_PROC2,
6331.89Skamil	name[2] = KERN_PROC_PID;
6341.89Skamil	name[3] = child;
6351.89Skamil	name[4] = sizeof(kp);
6361.89Skamil	name[5] = 1;
6371.89Skamil
6381.89Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
6391.89Skamil
6401.89Skamil	kp_sigmask = kp.p_sigmask;
6411.89Skamil
6421.89Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
6431.89Skamil	SYSCALL_REQUIRE(
6441.89Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
6451.89Skamil
6461.89Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
6471.89Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
6481.89Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
6491.89Skamil	    info.psi_siginfo.si_errno);
6501.89Skamil
6511.89Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
6521.89Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
6531.89Skamil
6541.89Skamil	DPRINTF("Before resuming the child process where it left off and "
6551.89Skamil	    "without signal to be sent\n");
6561.89Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
6571.89Skamil
6581.89Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6591.89Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
6601.89Skamil
6611.88Skamil	validate_status_stopped(status, sig);
6621.88Skamil
6631.88Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
6641.88Skamil	SYSCALL_REQUIRE(
6651.88Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
6661.88Skamil
6671.88Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
6681.88Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
6691.88Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
6701.88Skamil	    info.psi_siginfo.si_errno);
6711.88Skamil
6721.89Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
6731.89Skamil
6741.89Skamil	DPRINTF("kp_sigmask="
6751.89Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
6761.89Skamil	    kp_sigmask.__bits[0], kp_sigmask.__bits[1], kp_sigmask.__bits[2],
6771.89Skamil	    kp_sigmask.__bits[3]);
6781.89Skamil
6791.89Skamil	DPRINTF("kp.p_sigmask="
6801.89Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
6811.89Skamil	    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
6821.89Skamil	    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
6831.89Skamil
6841.89Skamil	ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask, sizeof(kp_sigmask)));
6851.89Skamil
6861.88Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
6871.88Skamil	switch (sig) {
6881.88Skamil	case SIGTRAP:
6891.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
6901.88Skamil		break;
6911.88Skamil	case SIGSEGV:
6921.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
6931.88Skamil		break;
6941.88Skamil	case SIGILL:
6951.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
6961.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
6971.88Skamil		break;
6981.88Skamil	case SIGFPE:
6991.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
7001.88Skamil		break;
7011.88Skamil	case SIGBUS:
7021.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
7031.88Skamil		break;
7041.88Skamil	}
7051.88Skamil
7061.88Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
7071.88Skamil
7081.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
7091.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
7101.88Skamil
7111.88Skamil	validate_status_signaled(status, SIGKILL, 0);
7121.88Skamil
7131.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
7141.88Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
7151.88Skamil}
7161.88Skamil
7171.88Skamil#define TRACEME_SIGNALMASKED_CRASH(test, sig)				\
7181.88SkamilATF_TC(test);								\
7191.88SkamilATF_TC_HEAD(test, tc)							\
7201.88Skamil{									\
7211.88Skamil	atf_tc_set_md_var(tc, "descr",					\
7221.88Skamil	    "Verify masked crash signal " #sig " in a child after "	\
7231.88Skamil	    "PT_TRACE_ME is delivered to its tracer");			\
7241.88Skamil}									\
7251.88Skamil									\
7261.88SkamilATF_TC_BODY(test, tc)							\
7271.88Skamil{									\
7281.88Skamil									\
7291.88Skamil	traceme_signalmasked_crash(sig);				\
7301.88Skamil}
7311.88Skamil
7321.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_trap, SIGTRAP)
7331.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_segv, SIGSEGV)
7341.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_ill, SIGILL)
7351.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_fpe, SIGFPE)
7361.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_bus, SIGBUS)
7371.88Skamil
7381.88Skamil/// ----------------------------------------------------------------------------
7391.88Skamil
7401.88Skamilstatic void
7411.88Skamiltraceme_signalignored_crash(int sig)
7421.88Skamil{
7431.90Skamil	const int sigval = SIGSTOP;
7441.88Skamil	pid_t child, wpid;
7451.88Skamil#if defined(TWAIT_HAVE_STATUS)
7461.88Skamil	int status;
7471.88Skamil#endif
7481.88Skamil	struct sigaction sa;
7491.88Skamil	struct ptrace_siginfo info;
7501.90Skamil	struct kinfo_proc2 kp;
7511.90Skamil	size_t len = sizeof(kp);
7521.90Skamil
7531.90Skamil	int name[6];
7541.90Skamil	const size_t namelen = __arraycount(name);
7551.90Skamil	ki_sigset_t kp_sigignore;
7561.88Skamil
7571.88Skamil#ifndef PTRACE_ILLEGAL_ASM
7581.88Skamil	if (sig == SIGILL)
7591.88Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
7601.88Skamil#endif
7611.88Skamil
7621.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
7631.114Skamil		atf_tc_skip("FP exceptions are not supported");
7641.114Skamil
7651.88Skamil	memset(&info, 0, sizeof(info));
7661.88Skamil
7671.88Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
7681.88Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
7691.88Skamil	if (child == 0) {
7701.88Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
7711.88Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
7721.88Skamil
7731.88Skamil		memset(&sa, 0, sizeof(sa));
7741.88Skamil		sa.sa_handler = SIG_IGN;
7751.88Skamil		sigemptyset(&sa.sa_mask);
7761.88Skamil
7771.88Skamil		FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
7781.88Skamil
7791.90Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
7801.90Skamil		FORKEE_ASSERT(raise(sigval) == 0);
7811.90Skamil
7821.88Skamil		DPRINTF("Before executing a trap\n");
7831.88Skamil		switch (sig) {
7841.88Skamil		case SIGTRAP:
7851.88Skamil			trigger_trap();
7861.88Skamil			break;
7871.88Skamil		case SIGSEGV:
7881.88Skamil			trigger_segv();
7891.88Skamil			break;
7901.88Skamil		case SIGILL:
7911.88Skamil			trigger_ill();
7921.88Skamil			break;
7931.88Skamil		case SIGFPE:
7941.88Skamil			trigger_fpe();
7951.88Skamil			break;
7961.88Skamil		case SIGBUS:
7971.88Skamil			trigger_bus();
7981.88Skamil			break;
7991.88Skamil		default:
8001.88Skamil			/* NOTREACHED */
8011.88Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
8021.88Skamil		}
8031.88Skamil
8041.88Skamil		/* NOTREACHED */
8051.88Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
8061.88Skamil	}
8071.88Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
8081.88Skamil
8091.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8101.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8111.88Skamil
8121.90Skamil	validate_status_stopped(status, sigval);
8131.90Skamil
8141.90Skamil	name[0] = CTL_KERN,
8151.90Skamil	name[1] = KERN_PROC2,
8161.90Skamil	name[2] = KERN_PROC_PID;
8171.90Skamil	name[3] = child;
8181.90Skamil	name[4] = sizeof(kp);
8191.90Skamil	name[5] = 1;
8201.90Skamil
8211.90Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
8221.90Skamil
8231.90Skamil	kp_sigignore = kp.p_sigignore;
8241.90Skamil
8251.90Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
8261.90Skamil	SYSCALL_REQUIRE(
8271.90Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
8281.90Skamil
8291.90Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
8301.90Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
8311.90Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
8321.90Skamil	    info.psi_siginfo.si_errno);
8331.90Skamil
8341.90Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
8351.90Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
8361.90Skamil
8371.90Skamil	DPRINTF("Before resuming the child process where it left off and "
8381.90Skamil	    "without signal to be sent\n");
8391.90Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
8401.90Skamil
8411.90Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8421.90Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8431.90Skamil
8441.88Skamil	validate_status_stopped(status, sig);
8451.88Skamil
8461.88Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
8471.88Skamil	SYSCALL_REQUIRE(
8481.88Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
8491.88Skamil
8501.88Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
8511.88Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
8521.88Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
8531.88Skamil	    info.psi_siginfo.si_errno);
8541.88Skamil
8551.90Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
8561.90Skamil
8571.90Skamil	DPRINTF("kp_sigignore="
8581.90Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
8591.90Skamil	    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
8601.90Skamil	    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
8611.90Skamil
8621.90Skamil	DPRINTF("kp.p_sigignore="
8631.90Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
8641.90Skamil	    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
8651.90Skamil	    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
8661.90Skamil
8671.90Skamil	ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore, sizeof(kp_sigignore)));
8681.90Skamil
8691.88Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
8701.88Skamil	switch (sig) {
8711.88Skamil	case SIGTRAP:
8721.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
8731.88Skamil		break;
8741.88Skamil	case SIGSEGV:
8751.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
8761.88Skamil		break;
8771.88Skamil	case SIGILL:
8781.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
8791.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
8801.88Skamil		break;
8811.88Skamil	case SIGFPE:
8821.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
8831.88Skamil		break;
8841.88Skamil	case SIGBUS:
8851.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
8861.88Skamil		break;
8871.88Skamil	}
8881.88Skamil
8891.88Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
8901.88Skamil
8911.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8921.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8931.88Skamil
8941.88Skamil	validate_status_signaled(status, SIGKILL, 0);
8951.88Skamil
8961.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8971.88Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
8981.88Skamil}
8991.88Skamil
9001.88Skamil#define TRACEME_SIGNALIGNORED_CRASH(test, sig)				\
9011.88SkamilATF_TC(test);								\
9021.88SkamilATF_TC_HEAD(test, tc)							\
9031.88Skamil{									\
9041.88Skamil	atf_tc_set_md_var(tc, "descr",					\
9051.88Skamil	    "Verify ignored crash signal " #sig " in a child after "	\
9061.88Skamil	    "PT_TRACE_ME is delivered to its tracer"); 			\
9071.88Skamil}									\
9081.88Skamil									\
9091.88SkamilATF_TC_BODY(test, tc)							\
9101.88Skamil{									\
9111.88Skamil									\
9121.88Skamil	traceme_signalignored_crash(sig);				\
9131.88Skamil}
9141.88Skamil
9151.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_trap, SIGTRAP)
9161.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_segv, SIGSEGV)
9171.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_ill, SIGILL)
9181.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_fpe, SIGFPE)
9191.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_bus, SIGBUS)
9201.88Skamil
9211.88Skamil/// ----------------------------------------------------------------------------
9221.88Skamil
9231.88Skamilstatic void
9241.50Skamiltraceme_sendsignal_handle(int sigsent, void (*sah)(int a), int *traceme_caught)
9251.1Skamil{
9261.1Skamil	const int exitval = 5;
9271.34Skamil	const int sigval = SIGSTOP;
9281.1Skamil	pid_t child, wpid;
9291.1Skamil	struct sigaction sa;
9301.1Skamil#if defined(TWAIT_HAVE_STATUS)
9311.1Skamil	int status;
9321.1Skamil#endif
9331.61Skre	struct ptrace_siginfo info;
9341.1Skamil
9351.45Skamil	memset(&info, 0, sizeof(info));
9361.45Skamil
9371.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
9381.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
9391.1Skamil	if (child == 0) {
9401.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
9411.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
9421.1Skamil
9431.34Skamil		sa.sa_handler = sah;
9441.1Skamil		sa.sa_flags = SA_SIGINFO;
9451.1Skamil		sigemptyset(&sa.sa_mask);
9461.1Skamil
9471.1Skamil		FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
9481.1Skamil
9491.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
9501.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
9511.1Skamil
9521.34Skamil		FORKEE_ASSERT_EQ(*traceme_caught, 1);
9531.1Skamil
9541.13Schristos		DPRINTF("Before exiting of the child process\n");
9551.1Skamil		_exit(exitval);
9561.1Skamil	}
9571.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
9581.1Skamil
9591.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9601.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9611.1Skamil
9621.1Skamil	validate_status_stopped(status, sigval);
9631.1Skamil
9641.45Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
9651.61Skre	SYSCALL_REQUIRE(
9661.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
9671.45Skamil
9681.45Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
9691.45Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
9701.45Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
9711.45Skamil	    info.psi_siginfo.si_errno);
9721.45Skamil
9731.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
9741.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
9751.45Skamil
9761.13Schristos	DPRINTF("Before resuming the child process where it left off and with "
9771.1Skamil	    "signal %s to be sent\n", strsignal(sigsent));
9781.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
9791.1Skamil
9801.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9811.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9821.1Skamil
9831.1Skamil	validate_status_exited(status, exitval);
9841.1Skamil
9851.13Schristos	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
9861.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
9871.1Skamil}
9881.1Skamil
9891.61Skre#define TRACEME_SENDSIGNAL_HANDLE(test, sig)				\
9901.61SkreATF_TC(test);								\
9911.61SkreATF_TC_HEAD(test, tc)							\
9921.61Skre{									\
9931.61Skre	atf_tc_set_md_var(tc, "descr",					\
9941.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
9951.61Skre	    "handled correctly and caught by a signal handler");	\
9961.61Skre}									\
9971.61Skre									\
9981.61Skrestatic int test##_caught = 0;						\
9991.61Skre									\
10001.61Skrestatic void								\
10011.61Skretest##_sighandler(int arg)						\
10021.61Skre{									\
10031.61Skre	FORKEE_ASSERT_EQ(arg, sig);					\
10041.61Skre									\
10051.61Skre	++ test##_caught;						\
10061.61Skre}									\
10071.61Skre									\
10081.61SkreATF_TC_BODY(test, tc)							\
10091.61Skre{									\
10101.61Skre									\
10111.61Skre	traceme_sendsignal_handle(sig, test##_sighandler, & test##_caught); \
10121.34Skamil}
10131.34Skamil
10141.34Skamil// A signal handler for SIGKILL and SIGSTOP cannot be registered.
10151.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle1, SIGABRT) /* abort trap */
10161.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle2, SIGHUP)  /* hangup */
10171.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle3, SIGCONT) /* continued? */
10181.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle4, SIGTRAP) /* crash sig. */
10191.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle5, SIGBUS) /* crash sig. */
10201.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle6, SIGILL) /* crash sig. */
10211.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle7, SIGFPE) /* crash sig. */
10221.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle8, SIGSEGV) /* crash sig. */
10231.34Skamil
10241.34Skamil/// ----------------------------------------------------------------------------
10251.34Skamil
10261.35Skamilstatic void
10271.50Skamiltraceme_sendsignal_masked(int sigsent)
10281.50Skamil{
10291.50Skamil	const int exitval = 5;
10301.50Skamil	const int sigval = SIGSTOP;
10311.50Skamil	pid_t child, wpid;
10321.50Skamil	sigset_t set;
10331.50Skamil#if defined(TWAIT_HAVE_STATUS)
10341.50Skamil	int status;
10351.50Skamil#endif
10361.61Skre	struct ptrace_siginfo info;
10371.50Skamil
10381.50Skamil	memset(&info, 0, sizeof(info));
10391.50Skamil
10401.50Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
10411.50Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
10421.50Skamil	if (child == 0) {
10431.50Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
10441.50Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
10451.50Skamil
10461.50Skamil		sigemptyset(&set);
10471.50Skamil		sigaddset(&set, sigsent);
10481.50Skamil		FORKEE_ASSERT(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
10491.50Skamil
10501.50Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
10511.50Skamil		FORKEE_ASSERT(raise(sigval) == 0);
10521.50Skamil
10531.50Skamil		_exit(exitval);
10541.50Skamil	}
10551.50Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
10561.50Skamil
10571.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10581.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
10591.50Skamil
10601.50Skamil	validate_status_stopped(status, sigval);
10611.50Skamil
10621.50Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
10631.61Skre	SYSCALL_REQUIRE(
10641.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
10651.50Skamil
10661.50Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
10671.50Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
10681.50Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
10691.50Skamil	    info.psi_siginfo.si_errno);
10701.50Skamil
10711.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
10721.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
10731.50Skamil
10741.50Skamil	DPRINTF("Before resuming the child process where it left off and with "
10751.50Skamil	    "signal %s to be sent\n", strsignal(sigsent));
10761.50Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
10771.50Skamil
10781.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10791.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
10801.50Skamil
10811.50Skamil	validate_status_exited(status, exitval);
10821.50Skamil
10831.50Skamil	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
10841.50Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
10851.50Skamil}
10861.50Skamil
10871.61Skre#define TRACEME_SENDSIGNAL_MASKED(test, sig)				\
10881.61SkreATF_TC(test);								\
10891.61SkreATF_TC_HEAD(test, tc)							\
10901.61Skre{									\
10911.61Skre	atf_tc_set_md_var(tc, "descr",					\
10921.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
10931.61Skre	    "handled correctly and the signal is masked by SIG_BLOCK");	\
10941.61Skre}									\
10951.61Skre									\
10961.61SkreATF_TC_BODY(test, tc)							\
10971.61Skre{									\
10981.61Skre									\
10991.61Skre	traceme_sendsignal_masked(sig);					\
11001.50Skamil}
11011.50Skamil
11021.50Skamil// A signal handler for SIGKILL and SIGSTOP cannot be masked.
11031.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked1, SIGABRT) /* abort trap */
11041.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked2, SIGHUP)  /* hangup */
11051.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked3, SIGCONT) /* continued? */
11061.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked4, SIGTRAP) /* crash sig. */
11071.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked5, SIGBUS) /* crash sig. */
11081.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked6, SIGILL) /* crash sig. */
11091.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked7, SIGFPE) /* crash sig. */
11101.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked8, SIGSEGV) /* crash sig. */
11111.50Skamil
11121.50Skamil/// ----------------------------------------------------------------------------
11131.50Skamil
11141.50Skamilstatic void
11151.50Skamiltraceme_sendsignal_ignored(int sigsent)
11161.50Skamil{
11171.50Skamil	const int exitval = 5;
11181.50Skamil	const int sigval = SIGSTOP;
11191.50Skamil	pid_t child, wpid;
11201.50Skamil	struct sigaction sa;
11211.50Skamil#if defined(TWAIT_HAVE_STATUS)
11221.50Skamil	int status;
11231.50Skamil#endif
11241.61Skre	struct ptrace_siginfo info;
11251.50Skamil
11261.50Skamil	memset(&info, 0, sizeof(info));
11271.50Skamil
11281.50Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
11291.50Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
11301.50Skamil	if (child == 0) {
11311.50Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
11321.61Skre
11331.50Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
11341.50Skamil
11351.50Skamil		memset(&sa, 0, sizeof(sa));
11361.50Skamil		sa.sa_handler = SIG_IGN;
11371.50Skamil		sigemptyset(&sa.sa_mask);
11381.50Skamil		FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
11391.50Skamil
11401.50Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
11411.50Skamil		FORKEE_ASSERT(raise(sigval) == 0);
11421.50Skamil
11431.50Skamil		_exit(exitval);
11441.50Skamil	}
11451.50Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
11461.50Skamil
11471.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11481.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11491.50Skamil
11501.50Skamil	validate_status_stopped(status, sigval);
11511.50Skamil
11521.50Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
11531.61Skre	SYSCALL_REQUIRE(
11541.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
11551.50Skamil
11561.50Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
11571.50Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
11581.50Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
11591.50Skamil	    info.psi_siginfo.si_errno);
11601.50Skamil
11611.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
11621.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
11631.50Skamil
11641.50Skamil	DPRINTF("Before resuming the child process where it left off and with "
11651.50Skamil	    "signal %s to be sent\n", strsignal(sigsent));
11661.50Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
11671.50Skamil
11681.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11691.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11701.50Skamil
11711.50Skamil	validate_status_exited(status, exitval);
11721.50Skamil
11731.50Skamil	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
11741.50Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
11751.50Skamil}
11761.50Skamil
11771.61Skre#define TRACEME_SENDSIGNAL_IGNORED(test, sig)				\
11781.61SkreATF_TC(test);								\
11791.61SkreATF_TC_HEAD(test, tc)							\
11801.61Skre{									\
11811.61Skre	atf_tc_set_md_var(tc, "descr",					\
11821.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
11831.61Skre	    "handled correctly and the signal is masked by SIG_IGN");	\
11841.61Skre}									\
11851.61Skre									\
11861.61SkreATF_TC_BODY(test, tc)							\
11871.61Skre{									\
11881.61Skre									\
11891.61Skre	traceme_sendsignal_ignored(sig);				\
11901.50Skamil}
11911.50Skamil
11921.50Skamil// A signal handler for SIGKILL and SIGSTOP cannot be ignored.
11931.61SkreTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored1, SIGABRT) /* abort */
11941.50SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored2, SIGHUP)  /* hangup */
11951.61SkreTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored3, SIGCONT) /* continued */
11961.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored4, SIGTRAP) /* crash s. */
11971.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored5, SIGBUS) /* crash s. */
11981.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored6, SIGILL) /* crash s. */
11991.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored7, SIGFPE) /* crash s. */
12001.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored8, SIGSEGV) /* crash s. */
12011.50Skamil
12021.50Skamil/// ----------------------------------------------------------------------------
12031.50Skamil
12041.50Skamilstatic void
12051.50Skamiltraceme_sendsignal_simple(int sigsent)
12061.1Skamil{
12071.35Skamil	const int sigval = SIGSTOP;
12081.35Skamil	int exitval = 0;
12091.1Skamil	pid_t child, wpid;
12101.1Skamil#if defined(TWAIT_HAVE_STATUS)
12111.1Skamil	int status;
12121.85Skamil	int expect_core;
12131.85Skamil
12141.85Skamil	switch (sigsent) {
12151.85Skamil	case SIGABRT:
12161.85Skamil	case SIGTRAP:
12171.85Skamil	case SIGBUS:
12181.85Skamil	case SIGILL:
12191.85Skamil	case SIGFPE:
12201.85Skamil	case SIGSEGV:
12211.85Skamil		expect_core = 1;
12221.85Skamil		break;
12231.85Skamil	default:
12241.85Skamil		expect_core = 0;
12251.85Skamil		break;
12261.85Skamil	}
12271.1Skamil#endif
12281.61Skre	struct ptrace_siginfo info;
12291.1Skamil
12301.45Skamil	memset(&info, 0, sizeof(info));
12311.45Skamil
12321.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
12331.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
12341.1Skamil	if (child == 0) {
12351.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
12361.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
12371.1Skamil
12381.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
12391.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
12401.1Skamil
12411.35Skamil		switch (sigsent) {
12421.35Skamil		case SIGCONT:
12431.48Skamil		case SIGSTOP:
12441.35Skamil			_exit(exitval);
12451.35Skamil		default:
12461.35Skamil			/* NOTREACHED */
12471.35Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
12481.35Skamil		}
12491.1Skamil	}
12501.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
12511.1Skamil
12521.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12531.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
12541.1Skamil
12551.1Skamil	validate_status_stopped(status, sigval);
12561.1Skamil
12571.45Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
12581.61Skre	SYSCALL_REQUIRE(
12591.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
12601.45Skamil
12611.45Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12621.45Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
12631.45Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12641.45Skamil	    info.psi_siginfo.si_errno);
12651.45Skamil
12661.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
12671.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
12681.45Skamil
12691.13Schristos	DPRINTF("Before resuming the child process where it left off and with "
12701.1Skamil	    "signal %s to be sent\n", strsignal(sigsent));
12711.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
12721.1Skamil
12731.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12741.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
12751.1Skamil
12761.35Skamil	switch (sigsent) {
12771.48Skamil	case SIGSTOP:
12781.48Skamil		validate_status_stopped(status, sigsent);
12791.48Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
12801.61Skre		    "child\n");
12811.48Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
12821.61Skre		    sizeof(info)) != -1);
12831.48Skamil
12841.48Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12851.48Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
12861.61Skre		    "si_errno=%#x\n",
12871.61Skre		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12881.61Skre		    info.psi_siginfo.si_errno);
12891.48Skamil
12901.48Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
12911.48Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
12921.48Skamil
12931.48Skamil		DPRINTF("Before resuming the child process where it left off "
12941.61Skre		    "and with signal %s to be sent\n", strsignal(sigsent));
12951.48Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
12961.48Skamil
12971.48Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12981.48Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
12991.61Skre		    child);
13001.48Skamil		/* FALLTHROUGH */
13011.35Skamil	case SIGCONT:
13021.35Skamil		validate_status_exited(status, exitval);
13031.35Skamil		break;
13041.35Skamil	default:
13051.35Skamil		validate_status_signaled(status, sigsent, expect_core);
13061.35Skamil		break;
13071.35Skamil	}
13081.1Skamil
13091.13Schristos	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
13101.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
13111.1Skamil}
13121.1Skamil
13131.61Skre#define TRACEME_SENDSIGNAL_SIMPLE(test, sig)				\
13141.61SkreATF_TC(test);								\
13151.61SkreATF_TC_HEAD(test, tc)							\
13161.61Skre{									\
13171.61Skre	atf_tc_set_md_var(tc, "descr",					\
13181.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
13191.61Skre	    "handled correctly in a child without a signal handler");	\
13201.61Skre}									\
13211.61Skre									\
13221.61SkreATF_TC_BODY(test, tc)							\
13231.61Skre{									\
13241.61Skre									\
13251.61Skre	traceme_sendsignal_simple(sig);					\
13261.35Skamil}
13271.35Skamil
13281.61SkreTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple1, SIGKILL) /* non-maskable*/
13291.61SkreTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple2, SIGSTOP) /* non-maskable*/
13301.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple3, SIGABRT) /* abort trap */
13311.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple4, SIGHUP)  /* hangup */
13321.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple5, SIGCONT) /* continued? */
13331.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple6, SIGTRAP) /* crash sig. */
13341.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple7, SIGBUS) /* crash sig. */
13351.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple8, SIGILL) /* crash sig. */
13361.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple9, SIGFPE) /* crash sig. */
13371.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple10, SIGSEGV) /* crash sig. */
13381.35Skamil
13391.35Skamil/// ----------------------------------------------------------------------------
13401.35Skamil
13411.37SkamilATF_TC(traceme_pid1_parent);
13421.37SkamilATF_TC_HEAD(traceme_pid1_parent, tc)
13431.37Skamil{
13441.37Skamil	atf_tc_set_md_var(tc, "descr",
13451.37Skamil	    "Verify that PT_TRACE_ME is not allowed when our parent is PID1");
13461.37Skamil}
13471.37Skamil
13481.37SkamilATF_TC_BODY(traceme_pid1_parent, tc)
13491.37Skamil{
13501.37Skamil	struct msg_fds parent_child;
13511.37Skamil	int exitval_child1 = 1, exitval_child2 = 2;
13521.37Skamil	pid_t child1, child2, wpid;
13531.37Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
13541.37Skamil#if defined(TWAIT_HAVE_STATUS)
13551.37Skamil	int status;
13561.37Skamil#endif
13571.37Skamil
13581.37Skamil	SYSCALL_REQUIRE(msg_open(&parent_child) == 0);
13591.37Skamil
13601.37Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
13611.37Skamil	SYSCALL_REQUIRE((child1 = fork()) != -1);
13621.37Skamil	if (child1 == 0) {
13631.37Skamil		DPRINTF("Before forking process PID=%d\n", getpid());
13641.37Skamil		SYSCALL_REQUIRE((child2 = fork()) != -1);
13651.37Skamil		if (child2 != 0) {
13661.37Skamil			DPRINTF("Parent process PID=%d, child2's PID=%d\n",
13671.61Skre			    getpid(), child2);
13681.37Skamil			_exit(exitval_child1);
13691.37Skamil		}
13701.37Skamil		CHILD_FROM_PARENT("exit child1", parent_child, msg);
13711.37Skamil
13721.37Skamil		DPRINTF("Assert that our parent is PID1 (initproc)\n");
13731.37Skamil		FORKEE_ASSERT_EQ(getppid(), 1);
13741.37Skamil
13751.37Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
13761.37Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) == -1);
13771.37Skamil		SYSCALL_REQUIRE_ERRNO(errno, EPERM);
13781.37Skamil
13791.37Skamil		CHILD_TO_PARENT("child2 exiting", parent_child, msg);
13801.37Skamil
13811.37Skamil		_exit(exitval_child2);
13821.37Skamil	}
13831.37Skamil	DPRINTF("Parent process PID=%d, child1's PID=%d\n", getpid(), child1);
13841.37Skamil
13851.37Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
13861.61Skre	TWAIT_REQUIRE_SUCCESS(
13871.61Skre	    wpid = TWAIT_GENERIC(child1, &status, WEXITED), child1);
13881.37Skamil
13891.37Skamil	validate_status_exited(status, exitval_child1);
13901.37Skamil
13911.37Skamil	DPRINTF("Notify that child1 is dead\n");
13921.37Skamil	PARENT_TO_CHILD("exit child1", parent_child, msg);
13931.37Skamil
13941.37Skamil	DPRINTF("Wait for exiting of child2\n");
13951.37Skamil	PARENT_FROM_CHILD("child2 exiting", parent_child, msg);
13961.37Skamil}
13971.37Skamil
13981.37Skamil/// ----------------------------------------------------------------------------
13991.37Skamil
14001.40Skamilstatic void
14011.40Skamiltraceme_vfork_raise(int sigval)
14021.40Skamil{
14031.46Skamil	const int exitval = 5, exitval_watcher = 10;
14041.46Skamil	pid_t child, parent, watcher, wpid;
14051.46Skamil	int rv;
14061.40Skamil#if defined(TWAIT_HAVE_STATUS)
14071.40Skamil	int status;
14081.85Skamil
14091.85Skamil	/* volatile workarounds GCC -Werror=clobbered */
14101.85Skamil	volatile int expect_core;
14111.85Skamil
14121.85Skamil	switch (sigval) {
14131.85Skamil	case SIGABRT:
14141.85Skamil	case SIGTRAP:
14151.85Skamil	case SIGBUS:
14161.85Skamil	case SIGILL:
14171.85Skamil	case SIGFPE:
14181.85Skamil	case SIGSEGV:
14191.85Skamil		expect_core = 1;
14201.85Skamil		break;
14211.85Skamil	default:
14221.85Skamil		expect_core = 0;
14231.85Skamil		break;
14241.85Skamil	}
14251.40Skamil#endif
14261.40Skamil
14271.46Skamil	/*
14281.46Skamil	 * Spawn a dedicated thread to watch for a stopped child and emit
14291.46Skamil	 * the SIGKILL signal to it.
14301.46Skamil	 *
14311.46Skamil	 * vfork(2) might clobber watcher, this means that it's safer and
14321.46Skamil	 * simpler to reparent this process to initproc and forget about it.
14331.46Skamil	 */
14341.46Skamil	if (sigval == SIGSTOP) {
14351.46Skamil		parent = getpid();
14361.46Skamil
14371.46Skamil		watcher = fork();
14381.46Skamil		ATF_REQUIRE(watcher != 1);
14391.46Skamil		if (watcher == 0) {
14401.46Skamil			/* Double fork(2) trick to reparent to initproc */
14411.46Skamil			watcher = fork();
14421.46Skamil			FORKEE_ASSERT_NEQ(watcher, -1);
14431.46Skamil			if (watcher != 0)
14441.46Skamil				_exit(exitval_watcher);
14451.46Skamil
14461.46Skamil			child = await_stopped_child(parent);
14471.46Skamil
14481.46Skamil			errno = 0;
14491.46Skamil			rv = kill(child, SIGKILL);
14501.46Skamil			FORKEE_ASSERT_EQ(rv, 0);
14511.46Skamil			FORKEE_ASSERT_EQ(errno, 0);
14521.46Skamil
14531.46Skamil			/* This exit value will be collected by initproc */
14541.46Skamil			_exit(0);
14551.46Skamil		}
14561.46Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14571.46Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(watcher, &status, 0),
14581.61Skre		    watcher);
14591.46Skamil
14601.46Skamil		validate_status_exited(status, exitval_watcher);
14611.46Skamil
14621.46Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14631.61Skre		TWAIT_REQUIRE_FAILURE(ECHILD,
14641.61Skre		    wpid = TWAIT_GENERIC(watcher, &status, 0));
14651.46Skamil	}
14661.46Skamil
14671.40Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
14681.40Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
14691.40Skamil	if (child == 0) {
14701.40Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
14711.40Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
14721.40Skamil
14731.40Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
14741.40Skamil		FORKEE_ASSERT(raise(sigval) == 0);
14751.40Skamil
14761.40Skamil		switch (sigval) {
14771.46Skamil		case SIGSTOP:
14781.40Skamil		case SIGKILL:
14791.40Skamil		case SIGABRT:
14801.40Skamil		case SIGHUP:
14811.85Skamil		case SIGTRAP:
14821.85Skamil		case SIGBUS:
14831.85Skamil		case SIGILL:
14841.85Skamil		case SIGFPE:
14851.85Skamil		case SIGSEGV:
14861.40Skamil			/* NOTREACHED */
14871.40Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
14881.70Smrg			__unreachable();
14891.40Skamil		default:
14901.40Skamil			DPRINTF("Before exiting of the child process\n");
14911.40Skamil			_exit(exitval);
14921.40Skamil		}
14931.40Skamil	}
14941.40Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
14951.40Skamil
14961.40Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14971.40Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
14981.40Skamil
14991.40Skamil	switch (sigval) {
15001.40Skamil	case SIGKILL:
15011.40Skamil	case SIGABRT:
15021.40Skamil	case SIGHUP:
15031.85Skamil	case SIGTRAP:
15041.85Skamil	case SIGBUS:
15051.85Skamil	case SIGILL:
15061.85Skamil	case SIGFPE:
15071.85Skamil	case SIGSEGV:
15081.40Skamil		validate_status_signaled(status, sigval, expect_core);
15091.40Skamil		break;
15101.40Skamil	case SIGSTOP:
15111.46Skamil		validate_status_signaled(status, SIGKILL, 0);
15121.46Skamil		break;
15131.40Skamil	case SIGCONT:
15141.47Skamil	case SIGTSTP:
15151.47Skamil	case SIGTTIN:
15161.47Skamil	case SIGTTOU:
15171.40Skamil		validate_status_exited(status, exitval);
15181.40Skamil		break;
15191.40Skamil	default:
15201.40Skamil		/* NOTREACHED */
15211.40Skamil		ATF_REQUIRE(0 && "NOT IMPLEMENTED");
15221.40Skamil		break;
15231.40Skamil	}
15241.40Skamil
15251.40Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15261.40Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
15271.40Skamil}
15281.40Skamil
15291.61Skre#define TRACEME_VFORK_RAISE(test, sig)					\
15301.61SkreATF_TC(test);								\
15311.61SkreATF_TC_HEAD(test, tc)							\
15321.61Skre{									\
15331.61Skre	atf_tc_set_md_var(tc, "descr",					\
15341.61Skre	    "Verify PT_TRACE_ME followed by raise of " #sig " in a "	\
15351.61Skre	    "vfork(2)ed child");					\
15361.61Skre}									\
15371.61Skre									\
15381.61SkreATF_TC_BODY(test, tc)							\
15391.61Skre{									\
15401.61Skre									\
15411.61Skre	traceme_vfork_raise(sig);					\
15421.40Skamil}
15431.40Skamil
15441.40SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise1, SIGKILL) /* non-maskable */
15451.46SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise2, SIGSTOP) /* non-maskable */
15461.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise3, SIGTSTP) /* ignored in vfork(2) */
15471.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise4, SIGTTIN) /* ignored in vfork(2) */
15481.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise5, SIGTTOU) /* ignored in vfork(2) */
15491.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise6, SIGABRT) /* regular abort trap */
15501.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise7, SIGHUP)  /* hangup */
15511.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise8, SIGCONT) /* continued? */
15521.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise9, SIGTRAP) /* crash signal */
15531.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise10, SIGBUS) /* crash signal */
15541.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise11, SIGILL) /* crash signal */
15551.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise12, SIGFPE) /* crash signal */
15561.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise13, SIGSEGV) /* crash signal */
15571.40Skamil
15581.40Skamil/// ----------------------------------------------------------------------------
15591.40Skamil
15601.52Skamilstatic void
15611.52Skamiltraceme_vfork_crash(int sig)
15621.41Skamil{
15631.41Skamil	pid_t child, wpid;
15641.41Skamil#if defined(TWAIT_HAVE_STATUS)
15651.41Skamil	int status;
15661.41Skamil#endif
15671.41Skamil
15681.71Skamil#ifndef PTRACE_ILLEGAL_ASM
15691.71Skamil	if (sig == SIGILL)
15701.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
15711.71Skamil#endif
15721.71Skamil
15731.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
15741.114Skamil		atf_tc_skip("FP exceptions are not supported");
15751.114Skamil
15761.41Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
15771.41Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
15781.41Skamil	if (child == 0) {
15791.41Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
15801.41Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
15811.41Skamil
15821.52Skamil		DPRINTF("Before executing a trap\n");
15831.52Skamil		switch (sig) {
15841.52Skamil		case SIGTRAP:
15851.52Skamil			trigger_trap();
15861.52Skamil			break;
15871.52Skamil		case SIGSEGV:
15881.52Skamil			trigger_segv();
15891.52Skamil			break;
15901.52Skamil		case SIGILL:
15911.52Skamil			trigger_ill();
15921.52Skamil			break;
15931.52Skamil		case SIGFPE:
15941.52Skamil			trigger_fpe();
15951.52Skamil			break;
15961.52Skamil		case SIGBUS:
15971.52Skamil			trigger_bus();
15981.52Skamil			break;
15991.52Skamil		default:
16001.52Skamil			/* NOTREACHED */
16011.52Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
16021.52Skamil		}
16031.41Skamil
16041.41Skamil		/* NOTREACHED */
16051.41Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
16061.41Skamil	}
16071.41Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
16081.41Skamil
16091.41Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16101.41Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
16111.41Skamil
16121.52Skamil	validate_status_signaled(status, sig, 1);
16131.41Skamil
16141.41Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16151.41Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
16161.41Skamil}
16171.41Skamil
16181.61Skre#define TRACEME_VFORK_CRASH(test, sig)					\
16191.61SkreATF_TC(test);								\
16201.61SkreATF_TC_HEAD(test, tc)							\
16211.61Skre{									\
16221.61Skre	atf_tc_set_md_var(tc, "descr",					\
16231.61Skre	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
16241.61Skre	    "vfork(2)ed child");					\
16251.61Skre}									\
16261.61Skre									\
16271.61SkreATF_TC_BODY(test, tc)							\
16281.61Skre{									\
16291.61Skre									\
16301.61Skre	traceme_vfork_crash(sig);					\
16311.52Skamil}
16321.52Skamil
16331.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_trap, SIGTRAP)
16341.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_segv, SIGSEGV)
16351.71SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_ill, SIGILL)
16361.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_fpe, SIGFPE)
16371.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_bus, SIGBUS)
16381.52Skamil
16391.41Skamil/// ----------------------------------------------------------------------------
16401.41Skamil
16411.92Skamilstatic void
16421.92Skamiltraceme_vfork_signalmasked_crash(int sig)
16431.92Skamil{
16441.92Skamil	pid_t child, wpid;
16451.92Skamil#if defined(TWAIT_HAVE_STATUS)
16461.92Skamil	int status;
16471.92Skamil#endif
16481.92Skamil	sigset_t intmask;
16491.92Skamil
16501.92Skamil#ifndef PTRACE_ILLEGAL_ASM
16511.92Skamil	if (sig == SIGILL)
16521.92Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
16531.92Skamil#endif
16541.92Skamil
16551.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
16561.114Skamil		atf_tc_skip("FP exceptions are not supported");
16571.114Skamil
16581.92Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
16591.92Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
16601.92Skamil	if (child == 0) {
16611.92Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
16621.92Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
16631.92Skamil
16641.92Skamil		sigemptyset(&intmask);
16651.92Skamil		sigaddset(&intmask, sig);
16661.92Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
16671.92Skamil
16681.92Skamil		DPRINTF("Before executing a trap\n");
16691.92Skamil		switch (sig) {
16701.92Skamil		case SIGTRAP:
16711.92Skamil			trigger_trap();
16721.92Skamil			break;
16731.92Skamil		case SIGSEGV:
16741.92Skamil			trigger_segv();
16751.92Skamil			break;
16761.92Skamil		case SIGILL:
16771.92Skamil			trigger_ill();
16781.92Skamil			break;
16791.92Skamil		case SIGFPE:
16801.92Skamil			trigger_fpe();
16811.92Skamil			break;
16821.92Skamil		case SIGBUS:
16831.92Skamil			trigger_bus();
16841.92Skamil			break;
16851.92Skamil		default:
16861.92Skamil			/* NOTREACHED */
16871.92Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
16881.92Skamil		}
16891.92Skamil
16901.92Skamil		/* NOTREACHED */
16911.92Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
16921.92Skamil	}
16931.92Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
16941.92Skamil
16951.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16961.92Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
16971.92Skamil
16981.92Skamil	validate_status_signaled(status, sig, 1);
16991.92Skamil
17001.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17011.92Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
17021.92Skamil}
17031.92Skamil
17041.92Skamil#define TRACEME_VFORK_SIGNALMASKED_CRASH(test, sig)			\
17051.92SkamilATF_TC(test);								\
17061.92SkamilATF_TC_HEAD(test, tc)							\
17071.92Skamil{									\
17081.92Skamil	atf_tc_set_md_var(tc, "descr",					\
17091.92Skamil	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
17101.92Skamil	    "vfork(2)ed child with a masked signal");			\
17111.92Skamil}									\
17121.92Skamil									\
17131.92SkamilATF_TC_BODY(test, tc)							\
17141.92Skamil{									\
17151.92Skamil									\
17161.92Skamil	traceme_vfork_signalmasked_crash(sig);				\
17171.92Skamil}
17181.92Skamil
17191.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_trap, SIGTRAP)
17201.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_segv, SIGSEGV)
17211.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_ill, SIGILL)
17221.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_fpe, SIGFPE)
17231.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_bus, SIGBUS)
17241.92Skamil
17251.92Skamil/// ----------------------------------------------------------------------------
17261.92Skamil
17271.92Skamilstatic void
17281.92Skamiltraceme_vfork_signalignored_crash(int sig)
17291.92Skamil{
17301.92Skamil	pid_t child, wpid;
17311.92Skamil#if defined(TWAIT_HAVE_STATUS)
17321.92Skamil	int status;
17331.92Skamil#endif
17341.92Skamil	struct sigaction sa;
17351.92Skamil
17361.92Skamil#ifndef PTRACE_ILLEGAL_ASM
17371.92Skamil	if (sig == SIGILL)
17381.92Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
17391.92Skamil#endif
17401.92Skamil
17411.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
17421.114Skamil		atf_tc_skip("FP exceptions are not supported");
17431.114Skamil
17441.92Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
17451.92Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
17461.92Skamil	if (child == 0) {
17471.92Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
17481.92Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
17491.92Skamil
17501.92Skamil		memset(&sa, 0, sizeof(sa));
17511.92Skamil		sa.sa_handler = SIG_IGN;
17521.92Skamil		sigemptyset(&sa.sa_mask);
17531.92Skamil
17541.92Skamil		FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
17551.92Skamil
17561.92Skamil		DPRINTF("Before executing a trap\n");
17571.92Skamil		switch (sig) {
17581.92Skamil		case SIGTRAP:
17591.92Skamil			trigger_trap();
17601.92Skamil			break;
17611.92Skamil		case SIGSEGV:
17621.92Skamil			trigger_segv();
17631.92Skamil			break;
17641.92Skamil		case SIGILL:
17651.92Skamil			trigger_ill();
17661.92Skamil			break;
17671.92Skamil		case SIGFPE:
17681.92Skamil			trigger_fpe();
17691.92Skamil			break;
17701.92Skamil		case SIGBUS:
17711.92Skamil			trigger_bus();
17721.92Skamil			break;
17731.92Skamil		default:
17741.92Skamil			/* NOTREACHED */
17751.92Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
17761.92Skamil		}
17771.92Skamil
17781.92Skamil		/* NOTREACHED */
17791.92Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
17801.92Skamil	}
17811.92Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
17821.92Skamil
17831.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17841.92Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17851.92Skamil
17861.92Skamil	validate_status_signaled(status, sig, 1);
17871.92Skamil
17881.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17891.92Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
17901.92Skamil}
17911.92Skamil
17921.92Skamil#define TRACEME_VFORK_SIGNALIGNORED_CRASH(test, sig)			\
17931.92SkamilATF_TC(test);								\
17941.92SkamilATF_TC_HEAD(test, tc)							\
17951.92Skamil{									\
17961.92Skamil	atf_tc_set_md_var(tc, "descr",					\
17971.92Skamil	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
17981.92Skamil	    "vfork(2)ed child with ignored signal");			\
17991.92Skamil}									\
18001.92Skamil									\
18011.92SkamilATF_TC_BODY(test, tc)							\
18021.92Skamil{									\
18031.92Skamil									\
18041.92Skamil	traceme_vfork_signalignored_crash(sig);				\
18051.92Skamil}
18061.92Skamil
18071.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_trap,
18081.92Skamil    SIGTRAP)
18091.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_segv,
18101.92Skamil    SIGSEGV)
18111.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_ill,
18121.92Skamil    SIGILL)
18131.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_fpe,
18141.92Skamil    SIGFPE)
18151.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_bus,
18161.92Skamil    SIGBUS)
18171.92Skamil
18181.92Skamil/// ----------------------------------------------------------------------------
18191.92Skamil
18201.96Skamilstatic void
18211.96Skamiltraceme_vfork_exec(bool masked, bool ignored)
18221.43Skamil{
18231.43Skamil	const int sigval = SIGTRAP;
18241.43Skamil	pid_t child, wpid;
18251.43Skamil#if defined(TWAIT_HAVE_STATUS)
18261.43Skamil	int status;
18271.43Skamil#endif
18281.96Skamil	struct sigaction sa;
18291.61Skre	struct ptrace_siginfo info;
18301.96Skamil	sigset_t intmask;
18311.96Skamil	struct kinfo_proc2 kp;
18321.96Skamil	size_t len = sizeof(kp);
18331.96Skamil
18341.96Skamil	int name[6];
18351.96Skamil	const size_t namelen = __arraycount(name);
18361.96Skamil	ki_sigset_t kp_sigmask;
18371.96Skamil	ki_sigset_t kp_sigignore;
18381.43Skamil
18391.43Skamil	memset(&info, 0, sizeof(info));
18401.43Skamil
18411.43Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
18421.43Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
18431.43Skamil	if (child == 0) {
18441.43Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
18451.43Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
18461.43Skamil
18471.96Skamil		if (masked) {
18481.96Skamil			sigemptyset(&intmask);
18491.96Skamil			sigaddset(&intmask, sigval);
18501.96Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
18511.96Skamil		}
18521.96Skamil
18531.96Skamil		if (ignored) {
18541.96Skamil			memset(&sa, 0, sizeof(sa));
18551.96Skamil			sa.sa_handler = SIG_IGN;
18561.96Skamil			sigemptyset(&sa.sa_mask);
18571.96Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
18581.96Skamil		}
18591.96Skamil
18601.43Skamil		DPRINTF("Before calling execve(2) from child\n");
18611.43Skamil		execlp("/bin/echo", "/bin/echo", NULL);
18621.43Skamil
18631.43Skamil		/* NOTREACHED */
18641.43Skamil		FORKEE_ASSERTX(0 && "Not reached");
18651.43Skamil	}
18661.43Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
18671.43Skamil
18681.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18691.43Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
18701.43Skamil
18711.43Skamil	validate_status_stopped(status, sigval);
18721.43Skamil
18731.96Skamil	name[0] = CTL_KERN,
18741.96Skamil	name[1] = KERN_PROC2,
18751.96Skamil	name[2] = KERN_PROC_PID;
18761.96Skamil	name[3] = getpid();
18771.96Skamil	name[4] = sizeof(kp);
18781.96Skamil	name[5] = 1;
18791.96Skamil
18801.96Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
18811.96Skamil
18821.96Skamil	if (masked)
18831.96Skamil		kp_sigmask = kp.p_sigmask;
18841.96Skamil
18851.96Skamil	if (ignored)
18861.96Skamil		kp_sigignore = kp.p_sigignore;
18871.96Skamil
18881.96Skamil	name[3] = getpid();
18891.96Skamil
18901.96Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
18911.96Skamil
18921.96Skamil	if (masked) {
18931.96Skamil		DPRINTF("kp_sigmask="
18941.96Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
18951.96Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
18961.96Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
18971.96Skamil
18981.96Skamil	        DPRINTF("kp.p_sigmask="
18991.96Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19001.96Skamil	            kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
19011.96Skamil	            kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
19021.96Skamil
19031.96Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
19041.96Skamil		    sizeof(kp_sigmask)));
19051.96Skamil	}
19061.96Skamil
19071.96Skamil	if (ignored) {
19081.96Skamil		DPRINTF("kp_sigignore="
19091.96Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19101.96Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
19111.96Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
19121.96Skamil
19131.96Skamil	        DPRINTF("kp.p_sigignore="
19141.96Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
19151.96Skamil	            kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
19161.96Skamil	            kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
19171.96Skamil
19181.96Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
19191.96Skamil		    sizeof(kp_sigignore)));
19201.96Skamil	}
19211.96Skamil
19221.43Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
19231.61Skre	SYSCALL_REQUIRE(
19241.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
19251.43Skamil
19261.43Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
19271.43Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
19281.43Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
19291.43Skamil	    info.psi_siginfo.si_errno);
19301.43Skamil
19311.43Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
19321.43Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
19331.43Skamil
19341.43Skamil	DPRINTF("Before resuming the child process where it left off and "
19351.43Skamil	    "without signal to be sent\n");
19361.43Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
19371.43Skamil
19381.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
19391.43Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
19401.43Skamil
19411.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
19421.43Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
19431.43Skamil}
19441.43Skamil
19451.96Skamil#define TRACEME_VFORK_EXEC(test, masked, ignored)			\
19461.96SkamilATF_TC(test);								\
19471.96SkamilATF_TC_HEAD(test, tc)							\
19481.96Skamil{									\
19491.96Skamil	atf_tc_set_md_var(tc, "descr",					\
19501.96Skamil	    "Verify PT_TRACE_ME followed by exec(3) in a vfork(2)ed "	\
19511.96Skamil	    "child%s%s", masked ? " with masked signal" : "",		\
19521.96Skamil	    masked ? " with ignored signal" : "");			\
19531.96Skamil}									\
19541.96Skamil									\
19551.96SkamilATF_TC_BODY(test, tc)							\
19561.96Skamil{									\
19571.96Skamil									\
19581.96Skamil	traceme_vfork_exec(masked, ignored);				\
19591.96Skamil}
19601.96Skamil
19611.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_exec, false, false)
19621.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalmasked_exec, true, false)
19631.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalignored_exec, false, true)
19641.96Skamil
19651.43Skamil/// ----------------------------------------------------------------------------
19661.43Skamil
19671.1Skamil#if defined(TWAIT_HAVE_PID)
19681.51Skamilstatic void
19691.94Skamilunrelated_tracer_sees_crash(int sig, bool masked, bool ignored)
19701.59Skamil{
19711.94Skamil	const int sigval = SIGSTOP;
19721.59Skamil	struct msg_fds parent_tracee, parent_tracer;
19731.59Skamil	const int exitval = 10;
19741.59Skamil	pid_t tracee, tracer, wpid;
19751.59Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
19761.59Skamil#if defined(TWAIT_HAVE_STATUS)
19771.59Skamil	int status;
19781.59Skamil#endif
19791.94Skamil	struct sigaction sa;
19801.59Skamil	struct ptrace_siginfo info;
19811.94Skamil	sigset_t intmask;
19821.94Skamil	struct kinfo_proc2 kp;
19831.94Skamil	size_t len = sizeof(kp);
19841.94Skamil
19851.94Skamil	int name[6];
19861.94Skamil	const size_t namelen = __arraycount(name);
19871.94Skamil	ki_sigset_t kp_sigmask;
19881.94Skamil	ki_sigset_t kp_sigignore;
19891.61Skre
19901.71Skamil#ifndef PTRACE_ILLEGAL_ASM
19911.71Skamil	if (sig == SIGILL)
19921.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
19931.71Skamil#endif
19941.71Skamil
19951.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
19961.114Skamil		atf_tc_skip("FP exceptions are not supported");
19971.114Skamil
19981.59Skamil	memset(&info, 0, sizeof(info));
19991.59Skamil
20001.59Skamil	DPRINTF("Spawn tracee\n");
20011.59Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
20021.59Skamil	tracee = atf_utils_fork();
20031.59Skamil	if (tracee == 0) {
20041.59Skamil		// Wait for parent to let us crash
20051.59Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
20061.61Skre
20071.94Skamil		if (masked) {
20081.94Skamil			sigemptyset(&intmask);
20091.94Skamil			sigaddset(&intmask, sig);
20101.94Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
20111.94Skamil		}
20121.94Skamil
20131.94Skamil		if (ignored) {
20141.94Skamil			memset(&sa, 0, sizeof(sa));
20151.94Skamil			sa.sa_handler = SIG_IGN;
20161.94Skamil			sigemptyset(&sa.sa_mask);
20171.94Skamil			FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
20181.94Skamil		}
20191.94Skamil
20201.94Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
20211.94Skamil		FORKEE_ASSERT(raise(sigval) == 0);
20221.94Skamil
20231.59Skamil		DPRINTF("Before executing a trap\n");
20241.59Skamil		switch (sig) {
20251.59Skamil		case SIGTRAP:
20261.59Skamil			trigger_trap();
20271.59Skamil			break;
20281.59Skamil		case SIGSEGV:
20291.59Skamil			trigger_segv();
20301.59Skamil			break;
20311.59Skamil		case SIGILL:
20321.59Skamil			trigger_ill();
20331.59Skamil			break;
20341.59Skamil		case SIGFPE:
20351.59Skamil			trigger_fpe();
20361.59Skamil			break;
20371.59Skamil		case SIGBUS:
20381.59Skamil			trigger_bus();
20391.59Skamil			break;
20401.59Skamil		default:
20411.59Skamil			/* NOTREACHED */
20421.59Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
20431.59Skamil		}
20441.59Skamil
20451.59Skamil		/* NOTREACHED */
20461.59Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
20471.59Skamil	}
20481.59Skamil
20491.59Skamil	DPRINTF("Spawn debugger\n");
20501.59Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
20511.59Skamil	tracer = atf_utils_fork();
20521.59Skamil	if (tracer == 0) {
20531.59Skamil		/* Fork again and drop parent to reattach to PID 1 */
20541.59Skamil		tracer = atf_utils_fork();
20551.59Skamil		if (tracer != 0)
20561.61Skre			_exit(exitval);
20571.59Skamil
20581.59Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
20591.59Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
20601.59Skamil
20611.59Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
20621.59Skamil		FORKEE_REQUIRE_SUCCESS(
20631.59Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
20641.59Skamil
20651.59Skamil		forkee_status_stopped(status, SIGSTOP);
20661.59Skamil
20671.94Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
20681.94Skamil		    "traced process\n");
20691.94Skamil		SYSCALL_REQUIRE(
20701.94Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
20711.94Skamil
20721.94Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
20731.94Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
20741.94Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
20751.94Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
20761.94Skamil
20771.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
20781.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
20791.94Skamil
20801.59Skamil		/* Resume tracee with PT_CONTINUE */
20811.59Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
20821.59Skamil
20831.59Skamil		/* Inform parent that tracer has attached to tracee */
20841.59Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
20851.59Skamil
20861.59Skamil		/* Wait for parent to tell use that tracee should have exited */
20871.59Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
20881.59Skamil
20891.59Skamil		/* Wait for tracee and assert that it exited */
20901.59Skamil		FORKEE_REQUIRE_SUCCESS(
20911.59Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
20921.59Skamil
20931.94Skamil		forkee_status_stopped(status, sigval);
20941.94Skamil
20951.94Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
20961.94Skamil		    "traced process\n");
20971.94Skamil		SYSCALL_REQUIRE(
20981.94Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
20991.94Skamil
21001.94Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
21011.94Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
21021.94Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
21031.94Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
21041.94Skamil
21051.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
21061.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
21071.94Skamil
21081.94Skamil		name[0] = CTL_KERN,
21091.94Skamil		name[1] = KERN_PROC2,
21101.94Skamil		name[2] = KERN_PROC_PID;
21111.94Skamil		name[3] = tracee;
21121.94Skamil		name[4] = sizeof(kp);
21131.94Skamil		name[5] = 1;
21141.94Skamil
21151.94Skamil		FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
21161.94Skamil
21171.94Skamil		if (masked)
21181.94Skamil			kp_sigmask = kp.p_sigmask;
21191.94Skamil
21201.94Skamil		if (ignored)
21211.94Skamil			kp_sigignore = kp.p_sigignore;
21221.94Skamil
21231.94Skamil		/* Resume tracee with PT_CONTINUE */
21241.94Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
21251.94Skamil
21261.94Skamil		/* Wait for tracee and assert that it exited */
21271.94Skamil		FORKEE_REQUIRE_SUCCESS(
21281.94Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
21291.94Skamil
21301.93Skamil		forkee_status_stopped(status, sig);
21311.59Skamil
21321.59Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
21331.61Skre		    "traced process\n");
21341.61Skre		SYSCALL_REQUIRE(
21351.61Skre		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
21361.59Skamil
21371.59Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
21381.59Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
21391.61Skre		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
21401.61Skre		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
21411.59Skamil
21421.93Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sig);
21431.94Skamil
21441.94Skamil		FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
21451.94Skamil
21461.94Skamil		if (masked) {
21471.94Skamil			DPRINTF("kp_sigmask="
21481.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21491.94Skamil			    PRIx32 "\n",
21501.94Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
21511.94Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
21521.94Skamil
21531.94Skamil			DPRINTF("kp.p_sigmask="
21541.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21551.94Skamil			    PRIx32 "\n",
21561.94Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
21571.94Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
21581.94Skamil
21591.94Skamil			FORKEE_ASSERTX(!memcmp(&kp_sigmask, &kp.p_sigmask,
21601.94Skamil			    sizeof(kp_sigmask)));
21611.94Skamil		}
21621.94Skamil
21631.94Skamil		if (ignored) {
21641.94Skamil			DPRINTF("kp_sigignore="
21651.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21661.94Skamil			    PRIx32 "\n",
21671.94Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
21681.94Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
21691.94Skamil
21701.94Skamil			DPRINTF("kp.p_sigignore="
21711.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21721.94Skamil			    PRIx32 "\n",
21731.94Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
21741.94Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
21751.94Skamil
21761.94Skamil			FORKEE_ASSERTX(!memcmp(&kp_sigignore, &kp.p_sigignore,
21771.94Skamil			    sizeof(kp_sigignore)));
21781.94Skamil		}
21791.94Skamil
21801.59Skamil		switch (sig) {
21811.59Skamil		case SIGTRAP:
21821.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
21831.59Skamil			break;
21841.59Skamil		case SIGSEGV:
21851.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
21861.59Skamil			break;
21871.71Skamil		case SIGILL:
21881.113Skamil			FORKEE_ASSERT(info.psi_siginfo.si_code >= ILL_ILLOPC &&
21891.112Skamil			            info.psi_siginfo.si_code <= ILL_BADSTK);
21901.71Skamil			break;
21911.59Skamil		case SIGFPE:
21921.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
21931.59Skamil			break;
21941.59Skamil		case SIGBUS:
21951.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
21961.59Skamil			break;
21971.59Skamil		}
21981.59Skamil
21991.59Skamil		FORKEE_ASSERT(ptrace(PT_KILL, tracee, NULL, 0) != -1);
22001.59Skamil		DPRINTF("Before calling %s() for the tracee\n", TWAIT_FNAME);
22011.93Skamil		FORKEE_REQUIRE_SUCCESS(
22021.61Skre		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
22031.59Skamil
22041.93Skamil		forkee_status_signaled(status, SIGKILL, 0);
22051.59Skamil
22061.71Skamil		/* Inform parent that tracer is exiting normally */
22071.71Skamil		CHILD_TO_PARENT("tracer done", parent_tracer, msg);
22081.71Skamil
22091.59Skamil		DPRINTF("Before exiting of the tracer process\n");
22101.59Skamil		_exit(0 /* collect by initproc */);
22111.59Skamil	}
22121.59Skamil
22131.59Skamil	DPRINTF("Wait for the tracer process (direct child) to exit "
22141.59Skamil	    "calling %s()\n", TWAIT_FNAME);
22151.59Skamil	TWAIT_REQUIRE_SUCCESS(
22161.59Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
22171.59Skamil
22181.59Skamil	validate_status_exited(status, exitval);
22191.59Skamil
22201.59Skamil	DPRINTF("Wait for the non-exited tracee process with %s()\n",
22211.59Skamil	    TWAIT_FNAME);
22221.59Skamil	TWAIT_REQUIRE_SUCCESS(
22231.59Skamil	    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
22241.59Skamil
22251.59Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
22261.59Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
22271.59Skamil
22281.59Skamil	DPRINTF("Resume the tracee and let it crash\n");
22291.59Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
22301.59Skamil
22311.59Skamil	DPRINTF("Resume the tracer and let it detect crashed tracee\n");
22321.59Skamil	PARENT_TO_CHILD("Message 2", parent_tracer, msg);
22331.59Skamil
22341.59Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
22351.59Skamil	    TWAIT_FNAME);
22361.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
22371.59Skamil
22381.59Skamil	validate_status_signaled(status, SIGKILL, 0);
22391.59Skamil
22401.71Skamil	DPRINTF("Await normal exit of tracer\n");
22411.71Skamil	PARENT_FROM_CHILD("tracer done", parent_tracer, msg);
22421.71Skamil
22431.59Skamil	msg_close(&parent_tracer);
22441.59Skamil	msg_close(&parent_tracee);
22451.59Skamil}
22461.59Skamil
22471.61Skre#define UNRELATED_TRACER_SEES_CRASH(test, sig)				\
22481.61SkreATF_TC(test);								\
22491.61SkreATF_TC_HEAD(test, tc)							\
22501.61Skre{									\
22511.61Skre	atf_tc_set_md_var(tc, "descr",					\
22521.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
22531.94Skamil	    "the debuggee");						\
22541.61Skre}									\
22551.61Skre									\
22561.61SkreATF_TC_BODY(test, tc)							\
22571.61Skre{									\
22581.61Skre									\
22591.94Skamil	unrelated_tracer_sees_crash(sig, false, false);			\
22601.59Skamil}
22611.59Skamil
22621.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_trap, SIGTRAP)
22631.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_segv, SIGSEGV)
22641.71SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_ill, SIGILL)
22651.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_fpe, SIGFPE)
22661.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_bus, SIGBUS)
22671.94Skamil
22681.94Skamil#define UNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(test, sig)		\
22691.94SkamilATF_TC(test);								\
22701.94SkamilATF_TC_HEAD(test, tc)							\
22711.94Skamil{									\
22721.94Skamil	atf_tc_set_md_var(tc, "descr",					\
22731.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
22741.94Skamil	    "the debuggee with masked signal");				\
22751.94Skamil}									\
22761.94Skamil									\
22771.94SkamilATF_TC_BODY(test, tc)							\
22781.94Skamil{									\
22791.94Skamil									\
22801.94Skamil	unrelated_tracer_sees_crash(sig, true, false);			\
22811.94Skamil}
22821.94Skamil
22831.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22841.94Skamil    unrelated_tracer_sees_signalmasked_crash_trap, SIGTRAP)
22851.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22861.94Skamil    unrelated_tracer_sees_signalmasked_crash_segv, SIGSEGV)
22871.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22881.94Skamil    unrelated_tracer_sees_signalmasked_crash_ill, SIGILL)
22891.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22901.94Skamil    unrelated_tracer_sees_signalmasked_crash_fpe, SIGFPE)
22911.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22921.94Skamil    unrelated_tracer_sees_signalmasked_crash_bus, SIGBUS)
22931.94Skamil
22941.94Skamil#define UNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(test, sig)		\
22951.94SkamilATF_TC(test);								\
22961.94SkamilATF_TC_HEAD(test, tc)							\
22971.94Skamil{									\
22981.94Skamil	atf_tc_set_md_var(tc, "descr",					\
22991.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
23001.94Skamil	    "the debuggee with signal ignored");			\
23011.94Skamil}									\
23021.94Skamil									\
23031.94SkamilATF_TC_BODY(test, tc)							\
23041.94Skamil{									\
23051.94Skamil									\
23061.94Skamil	unrelated_tracer_sees_crash(sig, false, true);			\
23071.94Skamil}
23081.94Skamil
23091.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23101.94Skamil    unrelated_tracer_sees_signalignored_crash_trap, SIGTRAP)
23111.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23121.94Skamil    unrelated_tracer_sees_signalignored_crash_segv, SIGSEGV)
23131.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23141.94Skamil    unrelated_tracer_sees_signalignored_crash_ill, SIGILL)
23151.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23161.94Skamil    unrelated_tracer_sees_signalignored_crash_fpe, SIGFPE)
23171.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23181.94Skamil    unrelated_tracer_sees_signalignored_crash_bus, SIGBUS)
23191.59Skamil#endif
23201.59Skamil
23211.59Skamil/// ----------------------------------------------------------------------------
23221.59Skamil
23231.59Skamil#if defined(TWAIT_HAVE_PID)
23241.59Skamilstatic void
23251.67Skamiltracer_sees_terminaton_before_the_parent_raw(bool notimeout, bool unrelated,
23261.67Skamil                                             bool stopped)
23271.1Skamil{
23281.51Skamil	/*
23291.51Skamil	 * notimeout - disable timeout in await zombie function
23301.51Skamil	 * unrelated - attach from unrelated tracer reparented to initproc
23311.67Skamil	 * stopped - attach to a stopped process
23321.51Skamil	 */
23331.1Skamil
23341.1Skamil	struct msg_fds parent_tracee, parent_tracer;
23351.1Skamil	const int exitval_tracee = 5;
23361.1Skamil	const int exitval_tracer = 10;
23371.1Skamil	pid_t tracee, tracer, wpid;
23381.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
23391.1Skamil#if defined(TWAIT_HAVE_STATUS)
23401.1Skamil	int status;
23411.1Skamil#endif
23421.1Skamil
23431.67Skamil	/*
23441.67Skamil	 * Only a subset of options are supported.
23451.67Skamil	 */
23461.67Skamil	ATF_REQUIRE((!notimeout && !unrelated && !stopped) ||
23471.67Skamil	            (!notimeout && unrelated && !stopped) ||
23481.67Skamil	            (notimeout && !unrelated && !stopped) ||
23491.67Skamil	            (!notimeout && unrelated && stopped));
23501.67Skamil
23511.13Schristos	DPRINTF("Spawn tracee\n");
23521.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
23531.1Skamil	tracee = atf_utils_fork();
23541.1Skamil	if (tracee == 0) {
23551.67Skamil		if (stopped) {
23561.67Skamil			DPRINTF("Stop self PID %d\n", getpid());
23571.67Skamil			raise(SIGSTOP);
23581.67Skamil		}
23591.67Skamil
23601.1Skamil		// Wait for parent to let us exit
23611.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
23621.1Skamil		_exit(exitval_tracee);
23631.1Skamil	}
23641.1Skamil
23651.13Schristos	DPRINTF("Spawn debugger\n");
23661.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
23671.1Skamil	tracer = atf_utils_fork();
23681.1Skamil	if (tracer == 0) {
23691.51Skamil		if(unrelated) {
23701.51Skamil			/* Fork again and drop parent to reattach to PID 1 */
23711.51Skamil			tracer = atf_utils_fork();
23721.51Skamil			if (tracer != 0)
23731.51Skamil				_exit(exitval_tracer);
23741.51Skamil		}
23751.51Skamil
23761.67Skamil		if (stopped) {
23771.67Skamil			DPRINTF("Await for a stopped parent PID %d\n", tracee);
23781.67Skamil			await_stopped(tracee);
23791.67Skamil		}
23801.67Skamil
23811.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
23821.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
23831.1Skamil
23841.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
23851.1Skamil		FORKEE_REQUIRE_SUCCESS(
23861.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
23871.1Skamil
23881.1Skamil		forkee_status_stopped(status, SIGSTOP);
23891.1Skamil
23901.1Skamil		/* Resume tracee with PT_CONTINUE */
23911.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
23921.1Skamil
23931.1Skamil		/* Inform parent that tracer has attached to tracee */
23941.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
23951.1Skamil
23961.1Skamil		/* Wait for parent to tell use that tracee should have exited */
23971.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
23981.1Skamil
23991.1Skamil		/* Wait for tracee and assert that it exited */
24001.1Skamil		FORKEE_REQUIRE_SUCCESS(
24011.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
24021.1Skamil
24031.1Skamil		forkee_status_exited(status, exitval_tracee);
24041.13Schristos		DPRINTF("Tracee %d exited with %d\n", tracee, exitval_tracee);
24051.1Skamil
24061.13Schristos		DPRINTF("Before exiting of the tracer process\n");
24071.51Skamil		_exit(unrelated ? 0 /* collect by initproc */ : exitval_tracer);
24081.51Skamil	}
24091.51Skamil
24101.51Skamil	if (unrelated) {
24111.51Skamil		DPRINTF("Wait for the tracer process (direct child) to exit "
24121.51Skamil		    "calling %s()\n", TWAIT_FNAME);
24131.51Skamil		TWAIT_REQUIRE_SUCCESS(
24141.51Skamil		    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
24151.51Skamil
24161.51Skamil		validate_status_exited(status, exitval_tracer);
24171.51Skamil
24181.51Skamil		DPRINTF("Wait for the non-exited tracee process with %s()\n",
24191.51Skamil		    TWAIT_FNAME);
24201.51Skamil		TWAIT_REQUIRE_SUCCESS(
24211.51Skamil		    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
24221.1Skamil	}
24231.1Skamil
24241.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
24251.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
24261.1Skamil
24271.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
24281.1Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
24291.1Skamil
24301.13Schristos	DPRINTF("Detect that tracee is zombie\n");
24311.51Skamil	if (notimeout)
24321.26Skamil		await_zombie_raw(tracee, 0);
24331.26Skamil	else
24341.26Skamil		await_zombie(tracee);
24351.1Skamil
24361.13Schristos	DPRINTF("Assert that there is no status about tracee %d - "
24371.1Skamil	    "Tracer must detect zombie first - calling %s()\n", tracee,
24381.1Skamil	    TWAIT_FNAME);
24391.1Skamil	TWAIT_REQUIRE_SUCCESS(
24401.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
24411.1Skamil
24421.51Skamil	if (unrelated) {
24431.51Skamil		DPRINTF("Resume the tracer and let it detect exited tracee\n");
24441.51Skamil		PARENT_TO_CHILD("Message 2", parent_tracer, msg);
24451.51Skamil	} else {
24461.51Skamil		DPRINTF("Tell the tracer child should have exited\n");
24471.51Skamil		PARENT_TO_CHILD("wait for tracee exit", parent_tracer,  msg);
24481.51Skamil		DPRINTF("Wait for tracer to finish its job and exit - calling "
24491.59Skamil			"%s()\n", TWAIT_FNAME);
24501.51Skamil
24511.51Skamil		DPRINTF("Wait from tracer child to complete waiting for "
24521.59Skamil			"tracee\n");
24531.51Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
24541.51Skamil		    tracer);
24551.1Skamil
24561.51Skamil		validate_status_exited(status, exitval_tracer);
24571.51Skamil	}
24581.1Skamil
24591.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
24601.1Skamil	    TWAIT_FNAME);
24611.51Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
24621.1Skamil
24631.1Skamil	validate_status_exited(status, exitval_tracee);
24641.1Skamil
24651.1Skamil	msg_close(&parent_tracer);
24661.1Skamil	msg_close(&parent_tracee);
24671.1Skamil}
24681.26Skamil
24691.51SkamilATF_TC(tracer_sees_terminaton_before_the_parent);
24701.51SkamilATF_TC_HEAD(tracer_sees_terminaton_before_the_parent, tc)
24711.51Skamil{
24721.51Skamil	atf_tc_set_md_var(tc, "descr",
24731.51Skamil	    "Assert that tracer sees process termination before the parent");
24741.51Skamil}
24751.51Skamil
24761.51SkamilATF_TC_BODY(tracer_sees_terminaton_before_the_parent, tc)
24771.26Skamil{
24781.26Skamil
24791.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, false, false);
24801.26Skamil}
24811.26Skamil
24821.51SkamilATF_TC(tracer_sysctl_lookup_without_duplicates);
24831.51SkamilATF_TC_HEAD(tracer_sysctl_lookup_without_duplicates, tc)
24841.1Skamil{
24851.1Skamil	atf_tc_set_md_var(tc, "descr",
24861.51Skamil	    "Assert that await_zombie() in attach1 always finds a single "
24871.51Skamil	    "process and no other error is reported");
24881.1Skamil}
24891.1Skamil
24901.51SkamilATF_TC_BODY(tracer_sysctl_lookup_without_duplicates, tc)
24911.1Skamil{
24921.51Skamil	time_t start, end;
24931.51Skamil	double diff;
24941.51Skamil	unsigned long N = 0;
24951.1Skamil
24961.51Skamil	/*
24971.51Skamil	 * Reuse this test with tracer_sees_terminaton_before_the_parent_raw().
24981.51Skamil	 * This test body isn't specific to this race, however it's just good
24991.51Skamil	 * enough for this purposes, no need to invent a dedicated code flow.
25001.51Skamil	 */
25011.1Skamil
25021.51Skamil	start = time(NULL);
25031.51Skamil	while (true) {
25041.51Skamil		DPRINTF("Step: %lu\n", N);
25051.67Skamil		tracer_sees_terminaton_before_the_parent_raw(true, false,
25061.67Skamil		                                             false);
25071.51Skamil		end = time(NULL);
25081.51Skamil		diff = difftime(end, start);
25091.51Skamil		if (diff >= 5.0)
25101.51Skamil			break;
25111.51Skamil		++N;
25121.1Skamil	}
25131.51Skamil	DPRINTF("Iterations: %lu\n", N);
25141.51Skamil}
25151.1Skamil
25161.51SkamilATF_TC(unrelated_tracer_sees_terminaton_before_the_parent);
25171.51SkamilATF_TC_HEAD(unrelated_tracer_sees_terminaton_before_the_parent, tc)
25181.51Skamil{
25191.51Skamil	atf_tc_set_md_var(tc, "descr",
25201.51Skamil	    "Assert that tracer sees process termination before the parent");
25211.51Skamil}
25221.1Skamil
25231.51SkamilATF_TC_BODY(unrelated_tracer_sees_terminaton_before_the_parent, tc)
25241.51Skamil{
25251.1Skamil
25261.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, false);
25271.67Skamil}
25281.67Skamil
25291.67SkamilATF_TC(tracer_attach_to_unrelated_stopped_process);
25301.67SkamilATF_TC_HEAD(tracer_attach_to_unrelated_stopped_process, tc)
25311.67Skamil{
25321.67Skamil	atf_tc_set_md_var(tc, "descr",
25331.67Skamil	    "Assert that tracer can attach to an unrelated stopped process");
25341.67Skamil}
25351.67Skamil
25361.67SkamilATF_TC_BODY(tracer_attach_to_unrelated_stopped_process, tc)
25371.67Skamil{
25381.67Skamil
25391.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, true);
25401.1Skamil}
25411.1Skamil#endif
25421.1Skamil
25431.51Skamil/// ----------------------------------------------------------------------------
25441.51Skamil
25451.66Skamilstatic void
25461.66Skamilparent_attach_to_its_child(bool stopped)
25471.1Skamil{
25481.1Skamil	struct msg_fds parent_tracee;
25491.1Skamil	const int exitval_tracee = 5;
25501.1Skamil	pid_t tracee, wpid;
25511.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
25521.1Skamil#if defined(TWAIT_HAVE_STATUS)
25531.1Skamil	int status;
25541.1Skamil#endif
25551.1Skamil
25561.13Schristos	DPRINTF("Spawn tracee\n");
25571.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
25581.1Skamil	tracee = atf_utils_fork();
25591.1Skamil	if (tracee == 0) {
25601.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
25611.13Schristos		DPRINTF("Parent should now attach to tracee\n");
25621.1Skamil
25631.66Skamil		if (stopped) {
25641.66Skamil			DPRINTF("Stop self PID %d\n", getpid());
25651.66Skamil			SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
25661.66Skamil		}
25671.66Skamil
25681.1Skamil		CHILD_FROM_PARENT("Message 2", parent_tracee, msg);
25691.1Skamil		/* Wait for message from the parent */
25701.1Skamil		_exit(exitval_tracee);
25711.1Skamil	}
25721.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
25731.57Skamil
25741.66Skamil	if (stopped) {
25751.66Skamil		DPRINTF("Await for a stopped tracee PID %d\n", tracee);
25761.66Skamil		await_stopped(tracee);
25771.66Skamil	}
25781.66Skamil
25791.13Schristos	DPRINTF("Before calling PT_ATTACH for tracee %d\n", tracee);
25801.13Schristos	SYSCALL_REQUIRE(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
25811.1Skamil
25821.13Schristos	DPRINTF("Wait for the stopped tracee process with %s()\n",
25831.1Skamil	    TWAIT_FNAME);
25841.1Skamil	TWAIT_REQUIRE_SUCCESS(
25851.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
25861.1Skamil
25871.1Skamil	validate_status_stopped(status, SIGSTOP);
25881.1Skamil
25891.13Schristos	DPRINTF("Resume tracee with PT_CONTINUE\n");
25901.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
25911.1Skamil
25921.13Schristos	DPRINTF("Let the tracee exit now\n");
25931.1Skamil	PARENT_TO_CHILD("Message 2", parent_tracee, msg);
25941.1Skamil
25951.13Schristos	DPRINTF("Wait for tracee to exit with %s()\n", TWAIT_FNAME);
25961.1Skamil	TWAIT_REQUIRE_SUCCESS(
25971.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
25981.1Skamil
25991.1Skamil	validate_status_exited(status, exitval_tracee);
26001.1Skamil
26011.13Schristos	DPRINTF("Before calling %s() for tracee\n", TWAIT_FNAME);
26021.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
26031.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0));
26041.1Skamil
26051.1Skamil	msg_close(&parent_tracee);
26061.1Skamil}
26071.1Skamil
26081.66SkamilATF_TC(parent_attach_to_its_child);
26091.66SkamilATF_TC_HEAD(parent_attach_to_its_child, tc)
26101.66Skamil{
26111.66Skamil	atf_tc_set_md_var(tc, "descr",
26121.66Skamil	    "Assert that tracer parent can PT_ATTACH to its child");
26131.66Skamil}
26141.66Skamil
26151.66SkamilATF_TC_BODY(parent_attach_to_its_child, tc)
26161.66Skamil{
26171.66Skamil
26181.66Skamil	parent_attach_to_its_child(false);
26191.66Skamil}
26201.66Skamil
26211.66SkamilATF_TC(parent_attach_to_its_stopped_child);
26221.66SkamilATF_TC_HEAD(parent_attach_to_its_stopped_child, tc)
26231.66Skamil{
26241.66Skamil	atf_tc_set_md_var(tc, "descr",
26251.66Skamil	    "Assert that tracer parent can PT_ATTACH to its stopped child");
26261.66Skamil}
26271.66Skamil
26281.66SkamilATF_TC_BODY(parent_attach_to_its_stopped_child, tc)
26291.66Skamil{
26301.66Skamil
26311.66Skamil	parent_attach_to_its_child(true);
26321.66Skamil}
26331.66Skamil
26341.51Skamil/// ----------------------------------------------------------------------------
26351.51Skamil
26361.65Skamilstatic void
26371.65Skamilchild_attach_to_its_parent(bool stopped)
26381.1Skamil{
26391.1Skamil	struct msg_fds parent_tracee;
26401.1Skamil	const int exitval_tracer = 5;
26411.1Skamil	pid_t tracer, wpid;
26421.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
26431.1Skamil#if defined(TWAIT_HAVE_STATUS)
26441.1Skamil	int status;
26451.1Skamil#endif
26461.1Skamil
26471.13Schristos	DPRINTF("Spawn tracer\n");
26481.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
26491.1Skamil	tracer = atf_utils_fork();
26501.1Skamil	if (tracer == 0) {
26511.1Skamil		/* Wait for message from the parent */
26521.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
26531.1Skamil
26541.65Skamil		if (stopped) {
26551.65Skamil			DPRINTF("Await for a stopped parent PID %d\n",
26561.65Skamil			        getppid());
26571.65Skamil			await_stopped(getppid());
26581.65Skamil		}
26591.65Skamil
26601.13Schristos		DPRINTF("Attach to parent PID %d with PT_ATTACH from child\n",
26611.1Skamil		    getppid());
26621.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, getppid(), NULL, 0) != -1);
26631.1Skamil
26641.13Schristos		DPRINTF("Wait for the stopped parent process with %s()\n",
26651.1Skamil		    TWAIT_FNAME);
26661.1Skamil		FORKEE_REQUIRE_SUCCESS(
26671.1Skamil		    wpid = TWAIT_GENERIC(getppid(), &status, 0), getppid());
26681.1Skamil
26691.1Skamil		forkee_status_stopped(status, SIGSTOP);
26701.1Skamil
26711.13Schristos		DPRINTF("Resume parent with PT_DETACH\n");
26721.1Skamil		FORKEE_ASSERT(ptrace(PT_DETACH, getppid(), (void *)1, 0)
26731.1Skamil		    != -1);
26741.1Skamil
26751.1Skamil		/* Tell parent we are ready */
26761.1Skamil		CHILD_TO_PARENT("Message 1", parent_tracee, msg);
26771.1Skamil
26781.1Skamil		_exit(exitval_tracer);
26791.1Skamil	}
26801.1Skamil
26811.13Schristos	DPRINTF("Wait for the tracer to become ready\n");
26821.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
26831.65Skamil
26841.65Skamil	if (stopped) {
26851.65Skamil		DPRINTF("Stop self PID %d\n", getpid());
26861.65Skamil		SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
26871.65Skamil	}
26881.65Skamil
26891.13Schristos	DPRINTF("Allow the tracer to exit now\n");
26901.1Skamil	PARENT_FROM_CHILD("Message 1", parent_tracee, msg);
26911.1Skamil
26921.13Schristos	DPRINTF("Wait for tracer to exit with %s()\n", TWAIT_FNAME);
26931.1Skamil	TWAIT_REQUIRE_SUCCESS(
26941.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
26951.1Skamil
26961.1Skamil	validate_status_exited(status, exitval_tracer);
26971.1Skamil
26981.13Schristos	DPRINTF("Before calling %s() for tracer\n", TWAIT_FNAME);
26991.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
27001.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0));
27011.1Skamil
27021.1Skamil	msg_close(&parent_tracee);
27031.1Skamil}
27041.1Skamil
27051.65SkamilATF_TC(child_attach_to_its_parent);
27061.65SkamilATF_TC_HEAD(child_attach_to_its_parent, tc)
27071.65Skamil{
27081.65Skamil	atf_tc_set_md_var(tc, "descr",
27091.65Skamil	    "Assert that tracer child can PT_ATTACH to its parent");
27101.65Skamil}
27111.65Skamil
27121.65SkamilATF_TC_BODY(child_attach_to_its_parent, tc)
27131.65Skamil{
27141.65Skamil
27151.65Skamil	child_attach_to_its_parent(false);
27161.65Skamil}
27171.65Skamil
27181.65SkamilATF_TC(child_attach_to_its_stopped_parent);
27191.65SkamilATF_TC_HEAD(child_attach_to_its_stopped_parent, tc)
27201.65Skamil{
27211.65Skamil	atf_tc_set_md_var(tc, "descr",
27221.65Skamil	    "Assert that tracer child can PT_ATTACH to its stopped parent");
27231.65Skamil}
27241.65Skamil
27251.65SkamilATF_TC_BODY(child_attach_to_its_stopped_parent, tc)
27261.65Skamil{
27271.65Skamil	/*
27281.65Skamil	 * The ATF framework (atf-run) does not tolerate raise(SIGSTOP), as
27291.65Skamil	 * this causes a pipe (established from atf-run) to be broken.
27301.65Skamil	 * atf-run uses this mechanism to monitor whether a test is alive.
27311.65Skamil	 *
27321.65Skamil	 * As a workaround spawn this test as a subprocess.
27331.65Skamil	 */
27341.65Skamil
27351.65Skamil	const int exitval = 15;
27361.65Skamil	pid_t child, wpid;
27371.65Skamil#if defined(TWAIT_HAVE_STATUS)
27381.65Skamil	int status;
27391.65Skamil#endif
27401.65Skamil
27411.65Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
27421.65Skamil	if (child == 0) {
27431.65Skamil		child_attach_to_its_parent(true);
27441.65Skamil		_exit(exitval);
27451.65Skamil	} else {
27461.65Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
27471.65Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
27481.65Skamil
27491.65Skamil		validate_status_exited(status, exitval);
27501.65Skamil
27511.65Skamil		DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
27521.65Skamil		TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
27531.65Skamil	}
27541.65Skamil}
27551.65Skamil
27561.51Skamil/// ----------------------------------------------------------------------------
27571.51Skamil
27581.1Skamil#if defined(TWAIT_HAVE_PID)
27591.1Skamil
27601.51Skamilenum tracee_sees_its_original_parent_type {
27611.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
27621.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
27631.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS
27641.51Skamil};
27651.51Skamil
27661.51Skamilstatic void
27671.51Skamiltracee_sees_its_original_parent(enum tracee_sees_its_original_parent_type type)
27681.1Skamil{
27691.1Skamil	struct msg_fds parent_tracer, parent_tracee;
27701.1Skamil	const int exitval_tracee = 5;
27711.1Skamil	const int exitval_tracer = 10;
27721.1Skamil	pid_t parent, tracee, tracer, wpid;
27731.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
27741.1Skamil#if defined(TWAIT_HAVE_STATUS)
27751.1Skamil	int status;
27761.1Skamil#endif
27771.51Skamil	/* sysctl(3) - kinfo_proc2 */
27781.51Skamil	int name[CTL_MAXNAME];
27791.51Skamil	struct kinfo_proc2 kp;
27801.51Skamil	size_t len = sizeof(kp);
27811.51Skamil	unsigned int namelen;
27821.51Skamil
27831.51Skamil	/* procfs - status  */
27841.51Skamil	FILE *fp;
27851.51Skamil	struct stat st;
27861.51Skamil	const char *fname = "/proc/curproc/status";
27871.51Skamil	char s_executable[MAXPATHLEN];
27881.51Skamil	int s_pid, s_ppid;
27891.51Skamil	int rv;
27901.51Skamil
27911.51Skamil	if (type == TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS) {
27921.61Skre		SYSCALL_REQUIRE(
27931.61Skre		    (rv = stat(fname, &st)) == 0 || (errno == ENOENT));
27941.61Skre		if (rv != 0)
27951.51Skamil			atf_tc_skip("/proc/curproc/status not found");
27961.51Skamil	}
27971.1Skamil
27981.13Schristos	DPRINTF("Spawn tracee\n");
27991.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
28001.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
28011.1Skamil	tracee = atf_utils_fork();
28021.1Skamil	if (tracee == 0) {
28031.1Skamil		parent = getppid();
28041.1Skamil
28051.1Skamil		/* Emit message to the parent */
28061.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
28071.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
28081.1Skamil
28091.51Skamil		switch (type) {
28101.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID:
28111.51Skamil			FORKEE_ASSERT_EQ(parent, getppid());
28121.51Skamil			break;
28131.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2:
28141.51Skamil			namelen = 0;
28151.51Skamil			name[namelen++] = CTL_KERN;
28161.51Skamil			name[namelen++] = KERN_PROC2;
28171.51Skamil			name[namelen++] = KERN_PROC_PID;
28181.51Skamil			name[namelen++] = getpid();
28191.51Skamil			name[namelen++] = len;
28201.51Skamil			name[namelen++] = 1;
28211.51Skamil
28221.61Skre			FORKEE_ASSERT_EQ(
28231.61Skre			    sysctl(name, namelen, &kp, &len, NULL, 0), 0);
28241.51Skamil			FORKEE_ASSERT_EQ(parent, kp.p_ppid);
28251.51Skamil			break;
28261.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS:
28271.51Skamil			/*
28281.51Skamil			 * Format:
28291.51Skamil			 *  EXECUTABLE PID PPID ...
28301.51Skamil			 */
28311.51Skamil			FORKEE_ASSERT((fp = fopen(fname, "r")) != NULL);
28321.51Skamil			fscanf(fp, "%s %d %d", s_executable, &s_pid, &s_ppid);
28331.51Skamil			FORKEE_ASSERT_EQ(fclose(fp), 0);
28341.51Skamil			FORKEE_ASSERT_EQ(parent, s_ppid);
28351.51Skamil			break;
28361.51Skamil		}
28371.1Skamil
28381.1Skamil		_exit(exitval_tracee);
28391.1Skamil	}
28401.13Schristos	DPRINTF("Wait for child to record its parent identifier (pid)\n");
28411.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
28421.1Skamil
28431.13Schristos	DPRINTF("Spawn debugger\n");
28441.1Skamil	tracer = atf_utils_fork();
28451.1Skamil	if (tracer == 0) {
28461.1Skamil		/* No IPC to communicate with the child */
28471.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
28481.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
28491.1Skamil
28501.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
28511.1Skamil		FORKEE_REQUIRE_SUCCESS(
28521.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
28531.1Skamil
28541.1Skamil		forkee_status_stopped(status, SIGSTOP);
28551.1Skamil
28561.1Skamil		/* Resume tracee with PT_CONTINUE */
28571.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
28581.1Skamil
28591.1Skamil		/* Inform parent that tracer has attached to tracee */
28601.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
28611.1Skamil
28621.1Skamil		/* Wait for parent to tell use that tracee should have exited */
28631.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
28641.1Skamil
28651.1Skamil		/* Wait for tracee and assert that it exited */
28661.1Skamil		FORKEE_REQUIRE_SUCCESS(
28671.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
28681.1Skamil
28691.1Skamil		forkee_status_exited(status, exitval_tracee);
28701.1Skamil
28711.13Schristos		DPRINTF("Before exiting of the tracer process\n");
28721.1Skamil		_exit(exitval_tracer);
28731.1Skamil	}
28741.1Skamil
28751.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
28761.1Skamil	PARENT_FROM_CHILD("tracer ready",  parent_tracer, msg);
28771.1Skamil
28781.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
28791.1Skamil	PARENT_TO_CHILD("exit tracee",  parent_tracee, msg);
28801.1Skamil
28811.13Schristos	DPRINTF("Detect that tracee is zombie\n");
28821.1Skamil	await_zombie(tracee);
28831.1Skamil
28841.13Schristos	DPRINTF("Assert that there is no status about tracee - "
28851.1Skamil	    "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
28861.1Skamil	TWAIT_REQUIRE_SUCCESS(
28871.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
28881.1Skamil
28891.13Schristos	DPRINTF("Tell the tracer child should have exited\n");
28901.1Skamil	PARENT_TO_CHILD("wait for tracee exit",  parent_tracer, msg);
28911.1Skamil
28921.13Schristos	DPRINTF("Wait from tracer child to complete waiting for tracee\n");
28931.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
28941.1Skamil	    tracer);
28951.1Skamil
28961.1Skamil	validate_status_exited(status, exitval_tracer);
28971.1Skamil
28981.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
28991.1Skamil	    TWAIT_FNAME);
29001.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
29011.1Skamil	    tracee);
29021.1Skamil
29031.1Skamil	validate_status_exited(status, exitval_tracee);
29041.1Skamil
29051.1Skamil	msg_close(&parent_tracer);
29061.1Skamil	msg_close(&parent_tracee);
29071.1Skamil}
29081.1Skamil
29091.61Skre#define TRACEE_SEES_ITS_ORIGINAL_PARENT(test, type, descr)		\
29101.61SkreATF_TC(test);								\
29111.61SkreATF_TC_HEAD(test, tc)							\
29121.61Skre{									\
29131.61Skre	atf_tc_set_md_var(tc, "descr",					\
29141.61Skre	    "Assert that tracee sees its original parent when being traced " \
29151.61Skre	    "(check " descr ")");					\
29161.61Skre}									\
29171.61Skre									\
29181.61SkreATF_TC_BODY(test, tc)							\
29191.61Skre{									\
29201.61Skre									\
29211.61Skre	tracee_sees_its_original_parent(type);				\
29221.1Skamil}
29231.1Skamil
29241.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29251.51Skamil	tracee_sees_its_original_parent_getppid,
29261.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
29271.51Skamil	"getppid(2)");
29281.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29291.51Skamil	tracee_sees_its_original_parent_sysctl_kinfo_proc2,
29301.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
29311.51Skamil	"sysctl(3) and kinfo_proc2");
29321.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29331.51Skamil	tracee_sees_its_original_parent_procfs_status,
29341.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS,
29351.51Skamil	"the status file in procfs");
29361.1Skamil#endif
29371.1Skamil
29381.51Skamil/// ----------------------------------------------------------------------------
29391.1Skamil
29401.53Skamilstatic void
29411.53Skamileventmask_preserved(int event)
29421.1Skamil{
29431.1Skamil	const int exitval = 5;
29441.1Skamil	const int sigval = SIGSTOP;
29451.1Skamil	pid_t child, wpid;
29461.1Skamil#if defined(TWAIT_HAVE_STATUS)
29471.1Skamil	int status;
29481.1Skamil#endif
29491.1Skamil	ptrace_event_t set_event, get_event;
29501.1Skamil	const int len = sizeof(ptrace_event_t);
29511.1Skamil
29521.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
29531.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
29541.1Skamil	if (child == 0) {
29551.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
29561.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
29571.1Skamil
29581.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
29591.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
29601.1Skamil
29611.13Schristos		DPRINTF("Before exiting of the child process\n");
29621.1Skamil		_exit(exitval);
29631.1Skamil	}
29641.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
29651.1Skamil
29661.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29671.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
29681.1Skamil
29691.1Skamil	validate_status_stopped(status, sigval);
29701.1Skamil
29711.53Skamil	set_event.pe_set_event = event;
29721.61Skre	SYSCALL_REQUIRE(
29731.61Skre	    ptrace(PT_SET_EVENT_MASK, child, &set_event, len) != -1);
29741.61Skre	SYSCALL_REQUIRE(
29751.61Skre	    ptrace(PT_GET_EVENT_MASK, child, &get_event, len) != -1);
29761.125Skamil	DPRINTF("set_event=%#x get_event=%#x\n", set_event.pe_set_event,
29771.125Skamil	    get_event.pe_set_event);
29781.1Skamil	ATF_REQUIRE(memcmp(&set_event, &get_event, len) == 0);
29791.1Skamil
29801.13Schristos	DPRINTF("Before resuming the child process where it left off and "
29811.1Skamil	    "without signal to be sent\n");
29821.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
29831.1Skamil
29841.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29851.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
29861.1Skamil
29871.1Skamil	validate_status_exited(status, exitval);
29881.1Skamil
29891.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29901.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
29911.1Skamil}
29921.1Skamil
29931.61Skre#define EVENTMASK_PRESERVED(test, event)				\
29941.61SkreATF_TC(test);								\
29951.61SkreATF_TC_HEAD(test, tc)							\
29961.61Skre{									\
29971.61Skre	atf_tc_set_md_var(tc, "descr",					\
29981.61Skre	    "Verify that eventmask " #event " is preserved");		\
29991.61Skre}									\
30001.61Skre									\
30011.61SkreATF_TC_BODY(test, tc)							\
30021.61Skre{									\
30031.61Skre									\
30041.61Skre	eventmask_preserved(event);					\
30051.1Skamil}
30061.1Skamil
30071.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_empty, 0)
30081.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_fork, PTRACE_FORK)
30091.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_vfork, PTRACE_VFORK)
30101.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_vfork_done, PTRACE_VFORK_DONE)
30111.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_lwp_create, PTRACE_LWP_CREATE)
30121.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_lwp_exit, PTRACE_LWP_EXIT)
30131.125SkamilEVENTMASK_PRESERVED(eventmask_preserved_posix_spawn, PTRACE_POSIX_SPAWN)
30141.1Skamil
30151.53Skamil/// ----------------------------------------------------------------------------
30161.1Skamil
30171.28Skamilstatic void
30181.125Skamilfork_body(const char *fn, bool trackspawn, bool trackfork, bool trackvfork,
30191.105Skamil    bool trackvforkdone)
30201.1Skamil{
30211.1Skamil	const int exitval = 5;
30221.125Skamil	const int exitval2 = 0; /* This matched exit status from /bin/echo */
30231.1Skamil	const int sigval = SIGSTOP;
30241.31Skamil	pid_t child, child2 = 0, wpid;
30251.1Skamil#if defined(TWAIT_HAVE_STATUS)
30261.1Skamil	int status;
30271.1Skamil#endif
30281.1Skamil	ptrace_state_t state;
30291.1Skamil	const int slen = sizeof(state);
30301.1Skamil	ptrace_event_t event;
30311.1Skamil	const int elen = sizeof(event);
30321.1Skamil
30331.124Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
30341.124Skamil
30351.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
30361.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
30371.1Skamil	if (child == 0) {
30381.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
30391.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
30401.1Skamil
30411.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
30421.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
30431.1Skamil
30441.125Skamil		if (strcmp(fn, "spawn") == 0) {
30451.124Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
30461.124Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
30471.125Skamil		} else {
30481.125Skamil			if (strcmp(fn, "fork") == 0) {
30491.125Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
30501.125Skamil			} else if (strcmp(fn, "vfork") == 0) {
30511.125Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
30521.125Skamil			}
30531.1Skamil
30541.124Skamil			if (child2 == 0)
30551.124Skamil				_exit(exitval2);
30561.124Skamil		}
30571.1Skamil		FORKEE_REQUIRE_SUCCESS
30581.1Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
30591.1Skamil
30601.1Skamil		forkee_status_exited(status, exitval2);
30611.1Skamil
30621.13Schristos		DPRINTF("Before exiting of the child process\n");
30631.1Skamil		_exit(exitval);
30641.1Skamil	}
30651.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
30661.1Skamil
30671.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
30681.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
30691.1Skamil
30701.1Skamil	validate_status_stopped(status, sigval);
30711.1Skamil
30721.125Skamil	DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
30731.125Skamil	    trackspawn ? "|PTRACE_POSIX_SPAWN" : "",
30741.61Skre	    trackfork ? "|PTRACE_FORK" : "",
30751.61Skre	    trackvfork ? "|PTRACE_VFORK" : "",
30761.61Skre	    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", child);
30771.30Skamil	event.pe_set_event = 0;
30781.125Skamil	if (trackspawn)
30791.125Skamil		event.pe_set_event |= PTRACE_POSIX_SPAWN;
30801.30Skamil	if (trackfork)
30811.30Skamil		event.pe_set_event |= PTRACE_FORK;
30821.30Skamil	if (trackvfork)
30831.30Skamil		event.pe_set_event |= PTRACE_VFORK;
30841.30Skamil	if (trackvforkdone)
30851.30Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
30861.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
30871.1Skamil
30881.13Schristos	DPRINTF("Before resuming the child process where it left off and "
30891.1Skamil	    "without signal to be sent\n");
30901.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
30911.1Skamil
30921.29Skamil#if defined(TWAIT_HAVE_PID)
30931.125Skamil	if ((trackspawn && strcmp(fn, "spawn") == 0) ||
30941.125Skamil	    (trackfork && strcmp(fn, "fork") == 0) ||
30951.125Skamil	    (trackvfork && strcmp(fn, "vfork") == 0)) {
30961.29Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
30971.61Skre		    child);
30981.29Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
30991.61Skre		    child);
31001.1Skamil
31011.29Skamil		validate_status_stopped(status, SIGTRAP);
31021.1Skamil
31031.61Skre		SYSCALL_REQUIRE(
31041.61Skre		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
31051.125Skamil		if (trackspawn && strcmp(fn, "spawn") == 0) {
31061.125Skamil			ATF_REQUIRE_EQ(
31071.125Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
31081.125Skamil			       PTRACE_POSIX_SPAWN);
31091.125Skamil		}
31101.125Skamil		if (trackfork && strcmp(fn, "fork") == 0) {
31111.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
31121.30Skamil			       PTRACE_FORK);
31131.30Skamil		}
31141.125Skamil		if (trackvfork && strcmp(fn, "vfork") == 0) {
31151.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
31161.30Skamil			       PTRACE_VFORK);
31171.30Skamil		}
31181.29Skamil
31191.29Skamil		child2 = state.pe_other_pid;
31201.30Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
31211.29Skamil
31221.29Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
31231.61Skre		    "%d\n", TWAIT_FNAME, child2, child);
31241.29Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
31251.29Skamil		    child2);
31261.1Skamil
31271.29Skamil		validate_status_stopped(status, SIGTRAP);
31281.1Skamil
31291.61Skre		SYSCALL_REQUIRE(
31301.61Skre		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
31311.125Skamil		if (trackspawn && strcmp(fn, "spawn") == 0) {
31321.125Skamil			ATF_REQUIRE_EQ(
31331.125Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
31341.125Skamil			       PTRACE_POSIX_SPAWN);
31351.125Skamil		}
31361.125Skamil		if (trackfork && strcmp(fn, "fork") == 0) {
31371.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
31381.30Skamil			       PTRACE_FORK);
31391.30Skamil		}
31401.125Skamil		if (trackvfork && strcmp(fn, "vfork") == 0) {
31411.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
31421.30Skamil			       PTRACE_VFORK);
31431.30Skamil		}
31441.30Skamil
31451.29Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
31461.29Skamil
31471.29Skamil		DPRINTF("Before resuming the forkee process where it left off "
31481.29Skamil		    "and without signal to be sent\n");
31491.61Skre		SYSCALL_REQUIRE(
31501.61Skre		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
31511.29Skamil
31521.29Skamil		DPRINTF("Before resuming the child process where it left off "
31531.61Skre		    "and without signal to be sent\n");
31541.29Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31551.30Skamil	}
31561.30Skamil#endif
31571.30Skamil
31581.125Skamil	if (trackvforkdone && strcmp(fn, "vfork") == 0) {
31591.30Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
31601.61Skre		    child);
31611.61Skre		TWAIT_REQUIRE_SUCCESS(
31621.61Skre		    wpid = TWAIT_GENERIC(child, &status, 0), child);
31631.30Skamil
31641.30Skamil		validate_status_stopped(status, SIGTRAP);
31651.30Skamil
31661.61Skre		SYSCALL_REQUIRE(
31671.61Skre		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
31681.30Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
31691.30Skamil
31701.30Skamil		child2 = state.pe_other_pid;
31711.30Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
31721.61Skre		    child2);
31731.30Skamil
31741.30Skamil		DPRINTF("Before resuming the child process where it left off "
31751.61Skre		    "and without signal to be sent\n");
31761.30Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31771.30Skamil	}
31781.29Skamil
31791.30Skamil#if defined(TWAIT_HAVE_PID)
31801.125Skamil	if ((trackspawn && strcmp(fn, "spawn") == 0) ||
31811.125Skamil	    (trackfork && strcmp(fn, "fork") == 0) ||
31821.125Skamil	    (trackvfork && strcmp(fn, "vfork") == 0)) {
31831.29Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
31841.61Skre		    "\n", TWAIT_FNAME);
31851.61Skre		TWAIT_REQUIRE_SUCCESS(
31861.61Skre		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
31871.29Skamil
31881.29Skamil		validate_status_exited(status, exitval2);
31891.29Skamil
31901.29Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
31911.61Skre		    "process\n", TWAIT_FNAME);
31921.29Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
31931.29Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
31941.29Skamil	}
31951.29Skamil#endif
31961.1Skamil
31971.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
31981.1Skamil	    "SIGCHLD\n", TWAIT_FNAME);
31991.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
32001.1Skamil
32011.1Skamil	validate_status_stopped(status, SIGCHLD);
32021.1Skamil
32031.13Schristos	DPRINTF("Before resuming the child process where it left off and "
32041.1Skamil	    "without signal to be sent\n");
32051.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
32061.1Skamil
32071.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
32081.1Skamil	    TWAIT_FNAME);
32091.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
32101.1Skamil
32111.1Skamil	validate_status_exited(status, exitval);
32121.1Skamil
32131.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
32141.1Skamil	    TWAIT_FNAME);
32151.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
32161.1Skamil}
32171.28Skamil
32181.125Skamil#define FORK_TEST(name,fun,tspawn,tfork,tvfork,tvforkdone)		\
32191.61SkreATF_TC(name);								\
32201.61SkreATF_TC_HEAD(name, tc)							\
32211.61Skre{									\
32221.125Skamil	atf_tc_set_md_var(tc, "descr", "Verify " fun "() "		\
32231.125Skamil	    "called with 0%s%s%s%s in EVENT_MASK",			\
32241.126Skamil	    tspawn ? "|PTRACE_POSIX_SPAWN" : "",			\
32251.105Skamil	    tfork ? "|PTRACE_FORK" : "",				\
32261.105Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
32271.105Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
32281.61Skre}									\
32291.61Skre									\
32301.61SkreATF_TC_BODY(name, tc)							\
32311.61Skre{									\
32321.61Skre									\
32331.125Skamil	fork_body(fun, tspawn, tfork, tvfork, tvforkdone);		\
32341.32Skamil}
32351.32Skamil
32361.125SkamilFORK_TEST(fork1, "fork", false, false, false, false)
32371.31Skamil#if defined(TWAIT_HAVE_PID)
32381.125SkamilFORK_TEST(fork2, "fork", false, true, false, false)
32391.125SkamilFORK_TEST(fork3, "fork", false, false, true, false)
32401.125SkamilFORK_TEST(fork4, "fork", false, true, true, false)
32411.31Skamil#endif
32421.125SkamilFORK_TEST(fork5, "fork", false, false, false, true)
32431.31Skamil#if defined(TWAIT_HAVE_PID)
32441.125SkamilFORK_TEST(fork6, "fork", false, true, false, true)
32451.125SkamilFORK_TEST(fork7, "fork", false, false, true, true)
32461.125SkamilFORK_TEST(fork8, "fork", false, true, true, true)
32471.125Skamil#endif
32481.125SkamilFORK_TEST(fork9, "fork", true, false, false, false)
32491.125Skamil#if defined(TWAIT_HAVE_PID)
32501.125SkamilFORK_TEST(fork10, "fork", true, true, false, false)
32511.125SkamilFORK_TEST(fork11, "fork", true, false, true, false)
32521.125SkamilFORK_TEST(fork12, "fork", true, true, true, false)
32531.125Skamil#endif
32541.125SkamilFORK_TEST(fork13, "fork", true, false, false, true)
32551.125Skamil#if defined(TWAIT_HAVE_PID)
32561.125SkamilFORK_TEST(fork14, "fork", true, true, false, true)
32571.125SkamilFORK_TEST(fork15, "fork", true, false, true, true)
32581.125SkamilFORK_TEST(fork16, "fork", true, true, true, true)
32591.31Skamil#endif
32601.1Skamil
32611.110Skamil#if TEST_VFORK_ENABLED
32621.125SkamilFORK_TEST(vfork1, "vfork", false, false, false, false)
32631.31Skamil#if defined(TWAIT_HAVE_PID)
32641.125SkamilFORK_TEST(vfork2, "vfork", false, true, false, false)
32651.125SkamilFORK_TEST(vfork3, "vfork", false, false, true, false)
32661.125SkamilFORK_TEST(vfork4, "vfork", false, true, true, false)
32671.31Skamil#endif
32681.125SkamilFORK_TEST(vfork5, "vfork", false, false, false, true)
32691.31Skamil#if defined(TWAIT_HAVE_PID)
32701.125SkamilFORK_TEST(vfork6, "vfork", false, true, false, true)
32711.125SkamilFORK_TEST(vfork7, "vfork", false, false, true, true)
32721.125SkamilFORK_TEST(vfork8, "vfork", false, true, true, true)
32731.31Skamil#endif
32741.125SkamilFORK_TEST(vfork9, "vfork", true, false, false, false)
32751.125Skamil#if defined(TWAIT_HAVE_PID)
32761.125SkamilFORK_TEST(vfork10, "vfork", true, true, false, false)
32771.125SkamilFORK_TEST(vfork11, "vfork", true, false, true, false)
32781.125SkamilFORK_TEST(vfork12, "vfork", true, true, true, false)
32791.110Skamil#endif
32801.125SkamilFORK_TEST(vfork13, "vfork", true, false, false, true)
32811.124Skamil#if defined(TWAIT_HAVE_PID)
32821.125SkamilFORK_TEST(vfork14, "vfork", true, true, false, true)
32831.125SkamilFORK_TEST(vfork15, "vfork", true, false, true, true)
32841.125SkamilFORK_TEST(vfork16, "vfork", true, true, true, true)
32851.124Skamil#endif
32861.125Skamil#endif
32871.125Skamil
32881.125SkamilFORK_TEST(posix_spawn1, "spawn", false, false, false, false)
32891.125SkamilFORK_TEST(posix_spawn2, "spawn", false, true, false, false)
32901.125SkamilFORK_TEST(posix_spawn3, "spawn", false, false, true, false)
32911.125SkamilFORK_TEST(posix_spawn4, "spawn", false, true, true, false)
32921.125SkamilFORK_TEST(posix_spawn5, "spawn", false, false, false, true)
32931.125SkamilFORK_TEST(posix_spawn6, "spawn", false, true, false, true)
32941.125SkamilFORK_TEST(posix_spawn7, "spawn", false, false, true, true)
32951.125SkamilFORK_TEST(posix_spawn8, "spawn", false, true, true, true)
32961.124Skamil#if defined(TWAIT_HAVE_PID)
32971.125SkamilFORK_TEST(posix_spawn9, "spawn", true, false, false, false)
32981.125SkamilFORK_TEST(posix_spawn10, "spawn", true, true, false, false)
32991.125SkamilFORK_TEST(posix_spawn11, "spawn", true, false, true, false)
33001.125SkamilFORK_TEST(posix_spawn12, "spawn", true, true, true, false)
33011.125SkamilFORK_TEST(posix_spawn13, "spawn", true, false, false, true)
33021.125SkamilFORK_TEST(posix_spawn14, "spawn", true, true, false, true)
33031.125SkamilFORK_TEST(posix_spawn15, "spawn", true, false, true, true)
33041.125SkamilFORK_TEST(posix_spawn16, "spawn", true, true, true, true)
33051.124Skamil#endif
33061.124Skamil
33071.54Skamil/// ----------------------------------------------------------------------------
33081.31Skamil
33091.116Skamil#if defined(TWAIT_HAVE_PID)
33101.116Skamilstatic void
33111.126Skamilfork_detach_forker_body(const char *fn, bool kill_process)
33121.116Skamil{
33131.116Skamil	const int exitval = 5;
33141.126Skamil	const int exitval2 = 0; /* Matches exit value from /bin/echo */
33151.116Skamil	const int sigval = SIGSTOP;
33161.116Skamil	pid_t child, child2 = 0, wpid;
33171.116Skamil#if defined(TWAIT_HAVE_STATUS)
33181.116Skamil	int status;
33191.116Skamil#endif
33201.116Skamil	ptrace_state_t state;
33211.116Skamil	const int slen = sizeof(state);
33221.116Skamil	ptrace_event_t event;
33231.116Skamil	const int elen = sizeof(event);
33241.116Skamil
33251.116Skamil	int op;
33261.116Skamil
33271.126Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
33281.116Skamil
33291.116Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
33301.116Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
33311.116Skamil	if (child == 0) {
33321.116Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
33331.116Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
33341.116Skamil
33351.116Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
33361.116Skamil		FORKEE_ASSERT(raise(sigval) == 0);
33371.116Skamil
33381.126Skamil		if (strcmp(fn, "spawn") == 0) {
33391.126Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
33401.126Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
33411.126Skamil		} else  {
33421.126Skamil			if (strcmp(fn, "fork") == 0) {
33431.126Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
33441.126Skamil			} else {
33451.126Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
33461.126Skamil			}
33471.116Skamil
33481.126Skamil			if (child2 == 0)
33491.126Skamil				_exit(exitval2);
33501.126Skamil		}
33511.116Skamil
33521.116Skamil		FORKEE_REQUIRE_SUCCESS
33531.116Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
33541.116Skamil
33551.116Skamil		forkee_status_exited(status, exitval2);
33561.116Skamil
33571.116Skamil		DPRINTF("Before exiting of the child process\n");
33581.116Skamil		_exit(exitval);
33591.116Skamil	}
33601.116Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
33611.116Skamil
33621.116Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
33631.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
33641.116Skamil
33651.116Skamil	validate_status_stopped(status, sigval);
33661.116Skamil
33671.116Skamil	DPRINTF("Set EVENT_MASK for the child %d\n", child);
33681.126Skamil	event.pe_set_event = PTRACE_POSIX_SPAWN | PTRACE_FORK | PTRACE_VFORK
33691.126Skamil		| PTRACE_VFORK_DONE;
33701.116Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
33711.116Skamil
33721.116Skamil	DPRINTF("Before resuming the child process where it left off and "
33731.116Skamil	    "without signal to be sent\n");
33741.116Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
33751.116Skamil
33761.116Skamil	DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME, child);
33771.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
33781.116Skamil
33791.116Skamil	validate_status_stopped(status, SIGTRAP);
33801.116Skamil
33811.116Skamil	SYSCALL_REQUIRE(
33821.116Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
33831.126Skamil
33841.126Skamil	if (strcmp(fn, "spawn") == 0)
33851.126Skamil		op = PTRACE_POSIX_SPAWN;
33861.126Skamil	else if (strcmp(fn, "fork") == 0)
33871.126Skamil		op = PTRACE_FORK;
33881.126Skamil	else
33891.126Skamil		op = PTRACE_VFORK;
33901.126Skamil
33911.116Skamil	ATF_REQUIRE_EQ(state.pe_report_event & op, op);
33921.116Skamil
33931.116Skamil	child2 = state.pe_other_pid;
33941.116Skamil	DPRINTF("Reported ptrace event with forkee %d\n", child2);
33951.116Skamil
33961.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
33971.126Skamil	    strcmp(fn, "vfork") == 0)
33981.116Skamil		op = kill_process ? PT_KILL : PT_DETACH;
33991.116Skamil	else
34001.116Skamil		op = PT_CONTINUE;
34011.116Skamil	SYSCALL_REQUIRE(ptrace(op, child, (void *)1, 0) != -1);
34021.116Skamil
34031.116Skamil	DPRINTF("Before calling %s() for the forkee %d of the child %d\n",
34041.116Skamil	    TWAIT_FNAME, child2, child);
34051.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0), child2);
34061.116Skamil
34071.116Skamil	validate_status_stopped(status, SIGTRAP);
34081.116Skamil
34091.116Skamil	SYSCALL_REQUIRE(
34101.116Skamil	    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
34111.126Skamil	if (strcmp(fn, "spawn") == 0)
34121.126Skamil		op = PTRACE_POSIX_SPAWN;
34131.126Skamil	else if (strcmp(fn, "fork") == 0)
34141.126Skamil		op = PTRACE_FORK;
34151.126Skamil	else
34161.126Skamil		op = PTRACE_VFORK;
34171.126Skamil
34181.116Skamil	ATF_REQUIRE_EQ(state.pe_report_event & op, op);
34191.116Skamil	ATF_REQUIRE_EQ(state.pe_other_pid, child);
34201.116Skamil
34211.116Skamil	DPRINTF("Before resuming the forkee process where it left off "
34221.116Skamil	    "and without signal to be sent\n");
34231.116Skamil 	SYSCALL_REQUIRE(
34241.116Skamil	    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
34251.116Skamil
34261.126Skamil	if (strcmp(fn, "vforkdone") == 0) {
34271.116Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
34281.116Skamil		    child);
34291.116Skamil		TWAIT_REQUIRE_SUCCESS(
34301.116Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
34311.116Skamil
34321.116Skamil		validate_status_stopped(status, SIGTRAP);
34331.116Skamil
34341.116Skamil		SYSCALL_REQUIRE(
34351.116Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
34361.116Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
34371.116Skamil
34381.116Skamil		child2 = state.pe_other_pid;
34391.116Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
34401.116Skamil		    child2);
34411.116Skamil
34421.116Skamil		op = kill_process ? PT_KILL : PT_DETACH;
34431.116Skamil		DPRINTF("Before resuming the child process where it left off "
34441.116Skamil		    "and without signal to be sent\n");
34451.116Skamil		SYSCALL_REQUIRE(ptrace(op, child, (void *)1, 0) != -1);
34461.116Skamil	}
34471.116Skamil
34481.116Skamil	DPRINTF("Before calling %s() for the forkee - expected exited\n",
34491.116Skamil	    TWAIT_FNAME);
34501.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0), child2);
34511.116Skamil
34521.116Skamil	validate_status_exited(status, exitval2);
34531.116Skamil
34541.116Skamil	DPRINTF("Before calling %s() for the forkee - expected no process\n",
34551.116Skamil	    TWAIT_FNAME);
34561.116Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child2, &status, 0));
34571.116Skamil
34581.116Skamil	DPRINTF("Before calling %s() for the forkee - expected exited\n",
34591.116Skamil	    TWAIT_FNAME);
34601.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
34611.116Skamil
34621.116Skamil	if (kill_process) {
34631.116Skamil		validate_status_signaled(status, SIGKILL, 0);
34641.116Skamil	} else {
34651.116Skamil		validate_status_exited(status, exitval);
34661.116Skamil	}
34671.116Skamil
34681.116Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
34691.116Skamil	    TWAIT_FNAME);
34701.116Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
34711.116Skamil}
34721.116Skamil
34731.126Skamil#define FORK_DETACH_FORKER(name,event,kprocess)				\
34741.116SkamilATF_TC(name);								\
34751.116SkamilATF_TC_HEAD(name, tc)							\
34761.116Skamil{									\
34771.126Skamil	atf_tc_set_md_var(tc, "descr", "Verify %s " event,		\
34781.126Skamil	    kprocess ? "killed" : "detached");				\
34791.116Skamil}									\
34801.116Skamil									\
34811.116SkamilATF_TC_BODY(name, tc)							\
34821.116Skamil{									\
34831.116Skamil									\
34841.126Skamil	fork_detach_forker_body(event, kprocess);			\
34851.116Skamil}
34861.116Skamil
34871.126SkamilFORK_DETACH_FORKER(posix_spawn_detach_spawner, "spawn", false)
34881.126SkamilFORK_DETACH_FORKER(fork_detach_forker, "fork", false)
34891.116Skamil#if TEST_VFORK_ENABLED
34901.126SkamilFORK_DETACH_FORKER(vfork_detach_vforker, "vfork", false)
34911.126SkamilFORK_DETACH_FORKER(vfork_detach_vforkerdone, "vforkdone", false)
34921.116Skamil#endif
34931.126Skamil
34941.126SkamilFORK_DETACH_FORKER(posix_spawn_kill_spawner, "spawn", true)
34951.126SkamilFORK_DETACH_FORKER(fork_kill_forker, "fork", true)
34961.116Skamil#if TEST_VFORK_ENABLED
34971.126SkamilFORK_DETACH_FORKER(vfork_kill_vforker, "vfork", true)
34981.126SkamilFORK_DETACH_FORKER(vfork_kill_vforkerdone, "vforkdone", true)
34991.116Skamil#endif
35001.116Skamil#endif
35011.116Skamil
35021.116Skamil/// ----------------------------------------------------------------------------
35031.116Skamil
35041.110Skamil#if TEST_VFORK_ENABLED
35051.108Skamilstatic void
35061.108Skamiltraceme_vfork_fork_body(pid_t (*fn)(void))
35071.108Skamil{
35081.108Skamil	const int exitval = 5;
35091.108Skamil	const int exitval2 = 15;
35101.108Skamil	pid_t child, child2 = 0, wpid;
35111.108Skamil#if defined(TWAIT_HAVE_STATUS)
35121.108Skamil	int status;
35131.108Skamil#endif
35141.108Skamil
35151.108Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
35161.108Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
35171.108Skamil	if (child == 0) {
35181.108Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
35191.108Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
35201.108Skamil
35211.108Skamil		FORKEE_ASSERT((child2 = (fn)()) != -1);
35221.108Skamil
35231.108Skamil		if (child2 == 0)
35241.108Skamil			_exit(exitval2);
35251.108Skamil
35261.108Skamil		FORKEE_REQUIRE_SUCCESS
35271.108Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
35281.108Skamil
35291.108Skamil		forkee_status_exited(status, exitval2);
35301.108Skamil
35311.108Skamil		DPRINTF("Before exiting of the child process\n");
35321.108Skamil		_exit(exitval);
35331.108Skamil	}
35341.108Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
35351.108Skamil
35361.108Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
35371.108Skamil	    TWAIT_FNAME);
35381.108Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
35391.108Skamil
35401.108Skamil	validate_status_exited(status, exitval);
35411.108Skamil
35421.108Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
35431.108Skamil	    TWAIT_FNAME);
35441.108Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
35451.108Skamil}
35461.108Skamil
35471.108Skamil#define TRACEME_VFORK_FORK_TEST(name,fun)				\
35481.108SkamilATF_TC(name);								\
35491.108SkamilATF_TC_HEAD(name, tc)							\
35501.108Skamil{									\
35511.108Skamil	atf_tc_set_md_var(tc, "descr", "Verify " #fun "(2) "		\
35521.108Skamil	    "called from vfork(2)ed child");				\
35531.108Skamil}									\
35541.108Skamil									\
35551.108SkamilATF_TC_BODY(name, tc)							\
35561.108Skamil{									\
35571.108Skamil									\
35581.108Skamil	traceme_vfork_fork_body(fun);					\
35591.108Skamil}
35601.108Skamil
35611.108SkamilTRACEME_VFORK_FORK_TEST(traceme_vfork_fork, fork)
35621.108SkamilTRACEME_VFORK_FORK_TEST(traceme_vfork_vfork, vfork)
35631.110Skamil#endif
35641.108Skamil
35651.108Skamil/// ----------------------------------------------------------------------------
35661.108Skamil
35671.54Skamilenum bytes_transfer_type {
35681.54Skamil	BYTES_TRANSFER_DATA,
35691.54Skamil	BYTES_TRANSFER_DATAIO,
35701.54Skamil	BYTES_TRANSFER_TEXT,
35711.54Skamil	BYTES_TRANSFER_TEXTIO,
35721.54Skamil	BYTES_TRANSFER_AUXV
35731.54Skamil};
35741.31Skamil
35751.54Skamilstatic int __used
35761.54Skamilbytes_transfer_dummy(int a, int b, int c, int d)
35771.54Skamil{
35781.54Skamil	int e, f, g, h;
35791.1Skamil
35801.54Skamil	a *= 4;
35811.54Skamil	b += 3;
35821.54Skamil	c -= 2;
35831.54Skamil	d /= 1;
35841.1Skamil
35851.54Skamil	e = strtol("10", NULL, 10);
35861.54Skamil	f = strtol("20", NULL, 10);
35871.54Skamil	g = strtol("30", NULL, 10);
35881.54Skamil	h = strtol("40", NULL, 10);
35891.1Skamil
35901.54Skamil	return (a + b * c - d) + (e * f - g / h);
35911.1Skamil}
35921.1Skamil
35931.54Skamilstatic void
35941.55Schristosbytes_transfer(int operation, size_t size, enum bytes_transfer_type type)
35951.1Skamil{
35961.1Skamil	const int exitval = 5;
35971.1Skamil	const int sigval = SIGSTOP;
35981.1Skamil	pid_t child, wpid;
35991.54Skamil	bool skip = false;
36001.1Skamil
36011.54Skamil	int lookup_me = 0;
36021.54Skamil	uint8_t lookup_me8 = 0;
36031.54Skamil	uint16_t lookup_me16 = 0;
36041.54Skamil	uint32_t lookup_me32 = 0;
36051.54Skamil	uint64_t lookup_me64 = 0;
36061.1Skamil
36071.54Skamil	int magic = 0x13579246;
36081.54Skamil	uint8_t magic8 = 0xab;
36091.54Skamil	uint16_t magic16 = 0x1234;
36101.54Skamil	uint32_t magic32 = 0x98765432;
36111.54Skamil	uint64_t magic64 = 0xabcdef0123456789;
36121.1Skamil
36131.54Skamil	struct ptrace_io_desc io;
36141.1Skamil#if defined(TWAIT_HAVE_STATUS)
36151.1Skamil	int status;
36161.1Skamil#endif
36171.60Skre	/* 513 is just enough, for the purposes of ATF it's good enough */
36181.60Skre	AuxInfo ai[513], *aip;
36191.55Schristos
36201.55Schristos	ATF_REQUIRE(size < sizeof(ai));
36211.1Skamil
36221.54Skamil	/* Prepare variables for .TEXT transfers */
36231.54Skamil	switch (type) {
36241.54Skamil	case BYTES_TRANSFER_TEXT:
36251.54Skamil		memcpy(&magic, bytes_transfer_dummy, sizeof(magic));
36261.54Skamil		break;
36271.54Skamil	case BYTES_TRANSFER_TEXTIO:
36281.54Skamil		switch (size) {
36291.54Skamil		case 8:
36301.54Skamil			memcpy(&magic8, bytes_transfer_dummy, sizeof(magic8));
36311.54Skamil			break;
36321.54Skamil		case 16:
36331.54Skamil			memcpy(&magic16, bytes_transfer_dummy, sizeof(magic16));
36341.54Skamil			break;
36351.54Skamil		case 32:
36361.54Skamil			memcpy(&magic32, bytes_transfer_dummy, sizeof(magic32));
36371.54Skamil			break;
36381.54Skamil		case 64:
36391.54Skamil			memcpy(&magic64, bytes_transfer_dummy, sizeof(magic64));
36401.54Skamil			break;
36411.54Skamil		}
36421.54Skamil		break;
36431.54Skamil	default:
36441.54Skamil		break;
36451.54Skamil	}
36461.1Skamil
36471.54Skamil	/* Prepare variables for PIOD and AUXV transfers */
36481.54Skamil	switch (type) {
36491.54Skamil	case BYTES_TRANSFER_TEXTIO:
36501.54Skamil	case BYTES_TRANSFER_DATAIO:
36511.54Skamil		io.piod_op = operation;
36521.54Skamil		switch (size) {
36531.54Skamil		case 8:
36541.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
36551.54Skamil			               (void *)bytes_transfer_dummy :
36561.54Skamil			               &lookup_me8;
36571.54Skamil			io.piod_addr = &lookup_me8;
36581.54Skamil			io.piod_len = sizeof(lookup_me8);
36591.54Skamil			break;
36601.54Skamil		case 16:
36611.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
36621.54Skamil			               (void *)bytes_transfer_dummy :
36631.54Skamil			               &lookup_me16;
36641.54Skamil			io.piod_addr = &lookup_me16;
36651.54Skamil			io.piod_len = sizeof(lookup_me16);
36661.54Skamil			break;
36671.54Skamil		case 32:
36681.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
36691.54Skamil			               (void *)bytes_transfer_dummy :
36701.54Skamil			               &lookup_me32;
36711.54Skamil			io.piod_addr = &lookup_me32;
36721.54Skamil			io.piod_len = sizeof(lookup_me32);
36731.54Skamil			break;
36741.54Skamil		case 64:
36751.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
36761.54Skamil			               (void *)bytes_transfer_dummy :
36771.54Skamil			               &lookup_me64;
36781.54Skamil			io.piod_addr = &lookup_me64;
36791.54Skamil			io.piod_len = sizeof(lookup_me64);
36801.54Skamil			break;
36811.54Skamil		default:
36821.54Skamil			break;
36831.54Skamil		}
36841.54Skamil		break;
36851.54Skamil	case BYTES_TRANSFER_AUXV:
36861.54Skamil		io.piod_op = operation;
36871.54Skamil		io.piod_offs = 0;
36881.54Skamil		io.piod_addr = ai;
36891.54Skamil		io.piod_len = size;
36901.54Skamil		break;
36911.54Skamil	default:
36921.54Skamil		break;
36931.1Skamil	}
36941.1Skamil
36951.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
36961.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
36971.1Skamil	if (child == 0) {
36981.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
36991.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
37001.1Skamil
37011.54Skamil		switch (type) {
37021.54Skamil		case BYTES_TRANSFER_DATA:
37031.54Skamil			switch (operation) {
37041.54Skamil			case PT_READ_D:
37051.54Skamil			case PT_READ_I:
37061.54Skamil				lookup_me = magic;
37071.54Skamil				break;
37081.54Skamil			default:
37091.54Skamil				break;
37101.54Skamil			}
37111.54Skamil			break;
37121.54Skamil		case BYTES_TRANSFER_DATAIO:
37131.54Skamil			switch (operation) {
37141.54Skamil			case PIOD_READ_D:
37151.54Skamil			case PIOD_READ_I:
37161.54Skamil				switch (size) {
37171.54Skamil				case 8:
37181.54Skamil					lookup_me8 = magic8;
37191.54Skamil					break;
37201.54Skamil				case 16:
37211.54Skamil					lookup_me16 = magic16;
37221.54Skamil					break;
37231.54Skamil				case 32:
37241.54Skamil					lookup_me32 = magic32;
37251.54Skamil					break;
37261.54Skamil				case 64:
37271.54Skamil					lookup_me64 = magic64;
37281.54Skamil					break;
37291.54Skamil				default:
37301.54Skamil					break;
37311.54Skamil				}
37321.54Skamil				break;
37331.54Skamil			default:
37341.54Skamil				break;
37351.54Skamil			}
37361.54Skamil		default:
37371.54Skamil			break;
37381.54Skamil		}
37391.54Skamil
37401.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
37411.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
37421.1Skamil
37431.54Skamil		/* Handle PIOD and PT separately as operation values overlap */
37441.54Skamil		switch (type) {
37451.54Skamil		case BYTES_TRANSFER_DATA:
37461.54Skamil			switch (operation) {
37471.54Skamil			case PT_WRITE_D:
37481.54Skamil			case PT_WRITE_I:
37491.54Skamil				FORKEE_ASSERT_EQ(lookup_me, magic);
37501.54Skamil				break;
37511.54Skamil			default:
37521.54Skamil				break;
37531.54Skamil			}
37541.54Skamil			break;
37551.54Skamil		case BYTES_TRANSFER_DATAIO:
37561.54Skamil			switch (operation) {
37571.54Skamil			case PIOD_WRITE_D:
37581.54Skamil			case PIOD_WRITE_I:
37591.54Skamil				switch (size) {
37601.54Skamil				case 8:
37611.54Skamil					FORKEE_ASSERT_EQ(lookup_me8, magic8);
37621.54Skamil					break;
37631.54Skamil				case 16:
37641.54Skamil					FORKEE_ASSERT_EQ(lookup_me16, magic16);
37651.54Skamil					break;
37661.54Skamil				case 32:
37671.54Skamil					FORKEE_ASSERT_EQ(lookup_me32, magic32);
37681.54Skamil					break;
37691.54Skamil				case 64:
37701.54Skamil					FORKEE_ASSERT_EQ(lookup_me64, magic64);
37711.54Skamil					break;
37721.54Skamil				default:
37731.54Skamil					break;
37741.54Skamil				}
37751.54Skamil				break;
37761.54Skamil			default:
37771.54Skamil				break;
37781.54Skamil			}
37791.54Skamil			break;
37801.54Skamil		case BYTES_TRANSFER_TEXT:
37811.54Skamil			FORKEE_ASSERT(memcmp(&magic, bytes_transfer_dummy,
37821.54Skamil			                     sizeof(magic)) == 0);
37831.54Skamil			break;
37841.54Skamil		case BYTES_TRANSFER_TEXTIO:
37851.54Skamil			switch (size) {
37861.54Skamil			case 8:
37871.54Skamil				FORKEE_ASSERT(memcmp(&magic8,
37881.54Skamil				                     bytes_transfer_dummy,
37891.54Skamil				                     sizeof(magic8)) == 0);
37901.54Skamil				break;
37911.54Skamil			case 16:
37921.54Skamil				FORKEE_ASSERT(memcmp(&magic16,
37931.54Skamil				                     bytes_transfer_dummy,
37941.54Skamil				                     sizeof(magic16)) == 0);
37951.54Skamil				break;
37961.54Skamil			case 32:
37971.54Skamil				FORKEE_ASSERT(memcmp(&magic32,
37981.54Skamil				                     bytes_transfer_dummy,
37991.54Skamil				                     sizeof(magic32)) == 0);
38001.54Skamil				break;
38011.54Skamil			case 64:
38021.54Skamil				FORKEE_ASSERT(memcmp(&magic64,
38031.54Skamil				                     bytes_transfer_dummy,
38041.54Skamil				                     sizeof(magic64)) == 0);
38051.54Skamil				break;
38061.54Skamil			}
38071.54Skamil			break;
38081.54Skamil		default:
38091.54Skamil			break;
38101.54Skamil		}
38111.54Skamil
38121.13Schristos		DPRINTF("Before exiting of the child process\n");
38131.1Skamil		_exit(exitval);
38141.1Skamil	}
38151.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
38161.1Skamil
38171.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
38181.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
38191.1Skamil
38201.1Skamil	validate_status_stopped(status, sigval);
38211.1Skamil
38221.54Skamil	/* Check PaX MPROTECT */
38231.54Skamil	if (!can_we_write_to_text(child)) {
38241.54Skamil		switch (type) {
38251.54Skamil		case BYTES_TRANSFER_TEXTIO:
38261.54Skamil			switch (operation) {
38271.54Skamil			case PIOD_WRITE_D:
38281.54Skamil			case PIOD_WRITE_I:
38291.54Skamil				skip = true;
38301.54Skamil				break;
38311.54Skamil			default:
38321.54Skamil				break;
38331.54Skamil			}
38341.54Skamil			break;
38351.54Skamil		case BYTES_TRANSFER_TEXT:
38361.54Skamil			switch (operation) {
38371.54Skamil			case PT_WRITE_D:
38381.54Skamil			case PT_WRITE_I:
38391.54Skamil				skip = true;
38401.54Skamil				break;
38411.54Skamil			default:
38421.54Skamil				break;
38431.54Skamil			}
38441.54Skamil			break;
38451.54Skamil		default:
38461.54Skamil			break;
38471.54Skamil		}
38481.54Skamil	}
38491.1Skamil
38501.54Skamil	/* Bailout cleanly killing the child process */
38511.54Skamil	if (skip) {
38521.54Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
38531.54Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
38541.54Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
38551.54Skamil		                      child);
38561.1Skamil
38571.54Skamil		validate_status_signaled(status, SIGKILL, 0);
38581.1Skamil
38591.54Skamil		atf_tc_skip("PaX MPROTECT setup prevents writes to .text");
38601.54Skamil	}
38611.1Skamil
38621.54Skamil	DPRINTF("Calling operation to transfer bytes between child=%d and "
38631.54Skamil	       "parent=%d\n", child, getpid());
38641.1Skamil
38651.54Skamil	switch (type) {
38661.54Skamil	case BYTES_TRANSFER_TEXTIO:
38671.54Skamil	case BYTES_TRANSFER_DATAIO:
38681.54Skamil	case BYTES_TRANSFER_AUXV:
38691.54Skamil		switch (operation) {
38701.54Skamil		case PIOD_WRITE_D:
38711.54Skamil		case PIOD_WRITE_I:
38721.54Skamil			switch (size) {
38731.54Skamil			case 8:
38741.54Skamil				lookup_me8 = magic8;
38751.54Skamil				break;
38761.54Skamil			case 16:
38771.54Skamil				lookup_me16 = magic16;
38781.54Skamil				break;
38791.54Skamil			case 32:
38801.54Skamil				lookup_me32 = magic32;
38811.54Skamil				break;
38821.54Skamil			case 64:
38831.54Skamil				lookup_me64 = magic64;
38841.54Skamil				break;
38851.54Skamil			default:
38861.54Skamil				break;
38871.54Skamil			}
38881.54Skamil			break;
38891.54Skamil		default:
38901.54Skamil			break;
38911.54Skamil		}
38921.54Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
38931.54Skamil		switch (operation) {
38941.54Skamil		case PIOD_READ_D:
38951.54Skamil		case PIOD_READ_I:
38961.54Skamil			switch (size) {
38971.54Skamil			case 8:
38981.54Skamil				ATF_REQUIRE_EQ(lookup_me8, magic8);
38991.54Skamil				break;
39001.54Skamil			case 16:
39011.54Skamil				ATF_REQUIRE_EQ(lookup_me16, magic16);
39021.54Skamil				break;
39031.54Skamil			case 32:
39041.54Skamil				ATF_REQUIRE_EQ(lookup_me32, magic32);
39051.54Skamil				break;
39061.54Skamil			case 64:
39071.54Skamil				ATF_REQUIRE_EQ(lookup_me64, magic64);
39081.54Skamil				break;
39091.54Skamil			default:
39101.54Skamil				break;
39111.54Skamil			}
39121.54Skamil			break;
39131.54Skamil		case PIOD_READ_AUXV:
39141.54Skamil			DPRINTF("Asserting that AUXV length (%zu) is > 0\n",
39151.54Skamil			        io.piod_len);
39161.54Skamil			ATF_REQUIRE(io.piod_len > 0);
39171.54Skamil			for (aip = ai; aip->a_type != AT_NULL; aip++)
39181.54Skamil				DPRINTF("a_type=%#llx a_v=%#llx\n",
39191.54Skamil				    (long long int)aip->a_type,
39201.54Skamil				    (long long int)aip->a_v);
39211.54Skamil			break;
39221.54Skamil		default:
39231.54Skamil			break;
39241.54Skamil		}
39251.54Skamil		break;
39261.54Skamil	case BYTES_TRANSFER_TEXT:
39271.54Skamil		switch (operation) {
39281.54Skamil		case PT_READ_D:
39291.54Skamil		case PT_READ_I:
39301.54Skamil			errno = 0;
39311.54Skamil			lookup_me = ptrace(operation, child,
39321.54Skamil			                   bytes_transfer_dummy, 0);
39331.54Skamil			ATF_REQUIRE_EQ(lookup_me, magic);
39341.54Skamil			SYSCALL_REQUIRE_ERRNO(errno, 0);
39351.54Skamil			break;
39361.54Skamil		case PT_WRITE_D:
39371.54Skamil		case PT_WRITE_I:
39381.54Skamil			SYSCALL_REQUIRE(ptrace(operation, child,
39391.54Skamil			                       bytes_transfer_dummy, magic)
39401.54Skamil			                != -1);
39411.54Skamil			break;
39421.54Skamil		default:
39431.54Skamil			break;
39441.54Skamil		}
39451.54Skamil		break;
39461.54Skamil	case BYTES_TRANSFER_DATA:
39471.54Skamil		switch (operation) {
39481.54Skamil		case PT_READ_D:
39491.54Skamil		case PT_READ_I:
39501.54Skamil			errno = 0;
39511.54Skamil			lookup_me = ptrace(operation, child, &lookup_me, 0);
39521.54Skamil			ATF_REQUIRE_EQ(lookup_me, magic);
39531.54Skamil			SYSCALL_REQUIRE_ERRNO(errno, 0);
39541.54Skamil			break;
39551.54Skamil		case PT_WRITE_D:
39561.54Skamil		case PT_WRITE_I:
39571.54Skamil			lookup_me = magic;
39581.54Skamil			SYSCALL_REQUIRE(ptrace(operation, child, &lookup_me,
39591.54Skamil			                       magic) != -1);
39601.54Skamil			break;
39611.54Skamil		default:
39621.54Skamil			break;
39631.54Skamil		}
39641.54Skamil		break;
39651.54Skamil	default:
39661.54Skamil		break;
39671.54Skamil	}
39681.1Skamil
39691.13Schristos	DPRINTF("Before resuming the child process where it left off and "
39701.1Skamil	    "without signal to be sent\n");
39711.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
39721.1Skamil
39731.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
39741.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
39751.1Skamil
39761.1Skamil	validate_status_exited(status, exitval);
39771.1Skamil
39781.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
39791.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
39801.1Skamil}
39811.1Skamil
39821.61Skre#define BYTES_TRANSFER(test, operation, size, type)			\
39831.61SkreATF_TC(test);								\
39841.61SkreATF_TC_HEAD(test, tc)							\
39851.61Skre{									\
39861.61Skre	atf_tc_set_md_var(tc, "descr",					\
39871.61Skre	    "Verify bytes transfer operation" #operation " and size " #size \
39881.61Skre	    " of type " #type);						\
39891.61Skre}									\
39901.61Skre									\
39911.61SkreATF_TC_BODY(test, tc)							\
39921.61Skre{									\
39931.61Skre									\
39941.61Skre	bytes_transfer(operation, size, BYTES_TRANSFER_##type);		\
39951.1Skamil}
39961.1Skamil
39971.54Skamil// DATA
39981.1Skamil
39991.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_8, PIOD_READ_D, 8, DATAIO)
40001.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_16, PIOD_READ_D, 16, DATAIO)
40011.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_32, PIOD_READ_D, 32, DATAIO)
40021.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_64, PIOD_READ_D, 64, DATAIO)
40031.54Skamil
40041.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_8, PIOD_READ_I, 8, DATAIO)
40051.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_16, PIOD_READ_I, 16, DATAIO)
40061.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_32, PIOD_READ_I, 32, DATAIO)
40071.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_64, PIOD_READ_I, 64, DATAIO)
40081.54Skamil
40091.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_8, PIOD_WRITE_D, 8, DATAIO)
40101.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_16, PIOD_WRITE_D, 16, DATAIO)
40111.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_32, PIOD_WRITE_D, 32, DATAIO)
40121.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_64, PIOD_WRITE_D, 64, DATAIO)
40131.54Skamil
40141.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_8, PIOD_WRITE_I, 8, DATAIO)
40151.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_16, PIOD_WRITE_I, 16, DATAIO)
40161.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_32, PIOD_WRITE_I, 32, DATAIO)
40171.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_64, PIOD_WRITE_I, 64, DATAIO)
40181.54Skamil
40191.54SkamilBYTES_TRANSFER(bytes_transfer_read_d, PT_READ_D, 32, DATA)
40201.54SkamilBYTES_TRANSFER(bytes_transfer_read_i, PT_READ_I, 32, DATA)
40211.54SkamilBYTES_TRANSFER(bytes_transfer_write_d, PT_WRITE_D, 32, DATA)
40221.54SkamilBYTES_TRANSFER(bytes_transfer_write_i, PT_WRITE_I, 32, DATA)
40231.54Skamil
40241.54Skamil// TEXT
40251.54Skamil
40261.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_8_text, PIOD_READ_D, 8, TEXTIO)
40271.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_16_text, PIOD_READ_D, 16, TEXTIO)
40281.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_32_text, PIOD_READ_D, 32, TEXTIO)
40291.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_64_text, PIOD_READ_D, 64, TEXTIO)
40301.54Skamil
40311.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_8_text, PIOD_READ_I, 8, TEXTIO)
40321.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_16_text, PIOD_READ_I, 16, TEXTIO)
40331.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_32_text, PIOD_READ_I, 32, TEXTIO)
40341.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_64_text, PIOD_READ_I, 64, TEXTIO)
40351.54Skamil
40361.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_8_text, PIOD_WRITE_D, 8, TEXTIO)
40371.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_16_text, PIOD_WRITE_D, 16, TEXTIO)
40381.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_32_text, PIOD_WRITE_D, 32, TEXTIO)
40391.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_64_text, PIOD_WRITE_D, 64, TEXTIO)
40401.54Skamil
40411.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_8_text, PIOD_WRITE_I, 8, TEXTIO)
40421.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_16_text, PIOD_WRITE_I, 16, TEXTIO)
40431.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_32_text, PIOD_WRITE_I, 32, TEXTIO)
40441.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_64_text, PIOD_WRITE_I, 64, TEXTIO)
40451.54Skamil
40461.54SkamilBYTES_TRANSFER(bytes_transfer_read_d_text, PT_READ_D, 32, TEXT)
40471.54SkamilBYTES_TRANSFER(bytes_transfer_read_i_text, PT_READ_I, 32, TEXT)
40481.54SkamilBYTES_TRANSFER(bytes_transfer_write_d_text, PT_WRITE_D, 32, TEXT)
40491.54SkamilBYTES_TRANSFER(bytes_transfer_write_i_text, PT_WRITE_I, 32, TEXT)
40501.1Skamil
40511.54Skamil// AUXV
40521.1Skamil
40531.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_auxv, PIOD_READ_AUXV, 4096, AUXV)
40541.1Skamil
40551.54Skamil/// ----------------------------------------------------------------------------
40561.1Skamil
40571.101Skamilstatic void
40581.101Skamilbytes_transfer_alignment(const char *operation)
40591.101Skamil{
40601.101Skamil	const int exitval = 5;
40611.101Skamil	const int sigval = SIGSTOP;
40621.101Skamil	pid_t child, wpid;
40631.101Skamil#if defined(TWAIT_HAVE_STATUS)
40641.101Skamil	int status;
40651.101Skamil#endif
40661.101Skamil	char *buffer;
40671.101Skamil	int vector;
40681.101Skamil	size_t len;
40691.101Skamil	size_t i;
40701.101Skamil	int op;
40711.101Skamil
40721.101Skamil	struct ptrace_io_desc io;
40731.101Skamil	struct ptrace_siginfo info;
40741.101Skamil
40751.101Skamil	memset(&io, 0, sizeof(io));
40761.101Skamil	memset(&info, 0, sizeof(info));
40771.101Skamil
40781.101Skamil	/* Testing misaligned byte transfer crossing page boundaries */
40791.101Skamil	len = sysconf(_SC_PAGESIZE) * 2;
40801.101Skamil	buffer = malloc(len);
40811.101Skamil	ATF_REQUIRE(buffer != NULL);
40821.101Skamil
40831.101Skamil	/* Initialize the buffer with random data */
40841.101Skamil	for (i = 0; i < len; i++)
40851.101Skamil		buffer[i] = i & 0xff;
40861.101Skamil
40871.101Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
40881.101Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
40891.101Skamil	if (child == 0) {
40901.101Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
40911.101Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
40921.101Skamil
40931.101Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
40941.101Skamil		FORKEE_ASSERT(raise(sigval) == 0);
40951.101Skamil
40961.101Skamil		DPRINTF("Before exiting of the child process\n");
40971.101Skamil		_exit(exitval);
40981.101Skamil	}
40991.101Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
41001.101Skamil
41011.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
41021.101Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
41031.101Skamil
41041.101Skamil	validate_status_stopped(status, sigval);
41051.101Skamil
41061.101Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
41071.101Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info))
41081.101Skamil		!= -1);
41091.101Skamil
41101.101Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
41111.101Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
41121.101Skamil		"si_errno=%#x\n",
41131.101Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
41141.101Skamil		info.psi_siginfo.si_errno);
41151.101Skamil
41161.101Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
41171.101Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
41181.101Skamil
41191.101Skamil	if (strcmp(operation, "PT_READ_I") == 0 ||
41201.101Skamil	    strcmp(operation, "PT_READ_D") == 0) {
41211.101Skamil		if (strcmp(operation, "PT_READ_I"))
41221.101Skamil			op = PT_READ_I;
41231.101Skamil		else
41241.101Skamil			op = PT_READ_D;
41251.101Skamil
41261.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
41271.101Skamil			errno = 0;
41281.101Skamil			vector = ptrace(op, child, buffer + i, 0);
41291.101Skamil			ATF_REQUIRE_EQ(errno, 0);
41301.101Skamil			ATF_REQUIRE(!memcmp(&vector, buffer + i, sizeof(int)));
41311.101Skamil		}
41321.101Skamil	} else if (strcmp(operation, "PT_WRITE_I") == 0 ||
41331.101Skamil	           strcmp(operation, "PT_WRITE_D") == 0) {
41341.101Skamil		if (strcmp(operation, "PT_WRITE_I"))
41351.101Skamil			op = PT_WRITE_I;
41361.101Skamil		else
41371.101Skamil			op = PT_WRITE_D;
41381.101Skamil
41391.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
41401.101Skamil			memcpy(&vector, buffer + i, sizeof(int));
41411.101Skamil			SYSCALL_REQUIRE(ptrace(op, child, buffer + 1, vector)
41421.101Skamil			    != -1);
41431.101Skamil		}
41441.101Skamil	} else if (strcmp(operation, "PIOD_READ_I") == 0 ||
41451.101Skamil	           strcmp(operation, "PIOD_READ_D") == 0) {
41461.101Skamil		if (strcmp(operation, "PIOD_READ_I"))
41471.101Skamil			op = PIOD_READ_I;
41481.101Skamil		else
41491.101Skamil			op = PIOD_READ_D;
41501.101Skamil
41511.101Skamil		io.piod_op = op;
41521.101Skamil		io.piod_addr = &vector;
41531.101Skamil		io.piod_len = sizeof(int);
41541.101Skamil
41551.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
41561.101Skamil			io.piod_offs = buffer + i;
41571.101Skamil
41581.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
41591.101Skamil			                != -1);
41601.101Skamil			ATF_REQUIRE(!memcmp(&vector, buffer + i, sizeof(int)));
41611.101Skamil		}
41621.101Skamil	} else if (strcmp(operation, "PIOD_WRITE_I") == 0 ||
41631.101Skamil	           strcmp(operation, "PIOD_WRITE_D") == 0) {
41641.101Skamil		if (strcmp(operation, "PIOD_WRITE_I"))
41651.101Skamil			op = PIOD_WRITE_I;
41661.101Skamil		else
41671.101Skamil			op = PIOD_WRITE_D;
41681.101Skamil
41691.101Skamil		io.piod_op = op;
41701.101Skamil		io.piod_addr = &vector;
41711.101Skamil		io.piod_len = sizeof(int);
41721.101Skamil
41731.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
41741.101Skamil			io.piod_offs = buffer + i;
41751.101Skamil
41761.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
41771.101Skamil			                != -1);
41781.101Skamil		}
41791.101Skamil	} else if (strcmp(operation, "PIOD_READ_AUXV") == 0) {
41801.101Skamil		io.piod_op = PIOD_READ_AUXV;
41811.101Skamil		io.piod_addr = &vector;
41821.101Skamil		io.piod_len = sizeof(int);
41831.101Skamil
41841.101Skamil		errno = 0;
41851.101Skamil		i = 0;
41861.101Skamil		/* Read the whole AUXV vector, it has no clear length */
41871.120Skamil		while (io.piod_len > 0) {
41881.101Skamil			io.piod_offs = (void *)(intptr_t)i;
41891.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
41901.120Skamil			                != -1 || (io.piod_len == 0 && i > 0));
41911.101Skamil			++i;
41921.101Skamil		}
41931.101Skamil	}
41941.101Skamil
41951.101Skamil	DPRINTF("Before resuming the child process where it left off "
41961.101Skamil	    "and without signal to be sent\n");
41971.101Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
41981.101Skamil
41991.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
42001.101Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
42011.101Skamil	    child);
42021.101Skamil
42031.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
42041.101Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
42051.101Skamil}
42061.101Skamil
42071.101Skamil#define BYTES_TRANSFER_ALIGNMENT(test, operation)			\
42081.101SkamilATF_TC(test);								\
42091.101SkamilATF_TC_HEAD(test, tc)							\
42101.101Skamil{									\
42111.101Skamil	atf_tc_set_md_var(tc, "descr",					\
42121.101Skamil	    "Verify bytes transfer for potentially misaligned "		\
42131.101Skamil	    "operation " operation);					\
42141.101Skamil}									\
42151.101Skamil									\
42161.101SkamilATF_TC_BODY(test, tc)							\
42171.101Skamil{									\
42181.101Skamil									\
42191.101Skamil	bytes_transfer_alignment(operation);				\
42201.101Skamil}
42211.101Skamil
42221.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_read_i, "PT_READ_I")
42231.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_read_d, "PT_READ_D")
42241.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_write_i, "PT_WRITE_I")
42251.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_write_d, "PT_WRITE_D")
42261.101Skamil
42271.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_i, "PIOD_READ_I")
42281.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_d, "PIOD_READ_D")
42291.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_write_i, "PIOD_WRITE_I")
42301.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_write_d, "PIOD_WRITE_D")
42311.101Skamil
42321.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_auxv, "PIOD_READ_AUXV")
42331.101Skamil
42341.101Skamil/// ----------------------------------------------------------------------------
42351.101Skamil
42361.115Skamilstatic void
42371.115Skamilbytes_transfer_eof(const char *operation)
42381.115Skamil{
42391.115Skamil	const int exitval = 5;
42401.115Skamil	const int sigval = SIGSTOP;
42411.115Skamil	pid_t child, wpid;
42421.115Skamil#if defined(TWAIT_HAVE_STATUS)
42431.115Skamil	int status;
42441.115Skamil#endif
42451.115Skamil	FILE *fp;
42461.115Skamil	char *p;
42471.115Skamil	int vector;
42481.115Skamil	int op;
42491.115Skamil
42501.115Skamil	struct ptrace_io_desc io;
42511.115Skamil	struct ptrace_siginfo info;
42521.115Skamil
42531.115Skamil	memset(&io, 0, sizeof(io));
42541.115Skamil	memset(&info, 0, sizeof(info));
42551.115Skamil
42561.115Skamil	vector = 0;
42571.115Skamil
42581.115Skamil	fp = tmpfile();
42591.115Skamil	ATF_REQUIRE(fp != NULL);
42601.115Skamil
42611.115Skamil	p = mmap(0, 1, PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(fp), 0);
42621.115Skamil	ATF_REQUIRE(p != MAP_FAILED);
42631.115Skamil
42641.115Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
42651.115Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
42661.115Skamil	if (child == 0) {
42671.115Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
42681.115Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
42691.115Skamil
42701.115Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
42711.115Skamil		FORKEE_ASSERT(raise(sigval) == 0);
42721.115Skamil
42731.115Skamil		DPRINTF("Before exiting of the child process\n");
42741.115Skamil		_exit(exitval);
42751.115Skamil	}
42761.115Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
42771.115Skamil
42781.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
42791.115Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
42801.115Skamil
42811.115Skamil	validate_status_stopped(status, sigval);
42821.115Skamil
42831.115Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
42841.115Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info))
42851.115Skamil		!= -1);
42861.115Skamil
42871.115Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
42881.115Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
42891.115Skamil		"si_errno=%#x\n",
42901.115Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
42911.115Skamil		info.psi_siginfo.si_errno);
42921.115Skamil
42931.115Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
42941.115Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
42951.115Skamil
42961.115Skamil	if (strcmp(operation, "PT_READ_I") == 0 ||
42971.115Skamil	    strcmp(operation, "PT_READ_D") == 0) {
42981.115Skamil		if (strcmp(operation, "PT_READ_I"))
42991.115Skamil			op = PT_READ_I;
43001.115Skamil		else
43011.115Skamil			op = PT_READ_D;
43021.115Skamil
43031.115Skamil		errno = 0;
43041.115Skamil		SYSCALL_REQUIRE(ptrace(op, child, p, 0) == -1);
43051.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
43061.115Skamil	} else if (strcmp(operation, "PT_WRITE_I") == 0 ||
43071.115Skamil	           strcmp(operation, "PT_WRITE_D") == 0) {
43081.115Skamil		if (strcmp(operation, "PT_WRITE_I"))
43091.115Skamil			op = PT_WRITE_I;
43101.115Skamil		else
43111.115Skamil			op = PT_WRITE_D;
43121.115Skamil
43131.115Skamil		errno = 0;
43141.115Skamil		SYSCALL_REQUIRE(ptrace(op, child, p, vector) == -1);
43151.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
43161.115Skamil	} else if (strcmp(operation, "PIOD_READ_I") == 0 ||
43171.115Skamil	           strcmp(operation, "PIOD_READ_D") == 0) {
43181.115Skamil		if (strcmp(operation, "PIOD_READ_I"))
43191.115Skamil			op = PIOD_READ_I;
43201.115Skamil		else
43211.115Skamil			op = PIOD_READ_D;
43221.115Skamil
43231.115Skamil		io.piod_op = op;
43241.115Skamil		io.piod_addr = &vector;
43251.115Skamil		io.piod_len = sizeof(int);
43261.115Skamil		io.piod_offs = p;
43271.115Skamil
43281.115Skamil		errno = 0;
43291.115Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io)) == -1);
43301.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
43311.115Skamil	} else if (strcmp(operation, "PIOD_WRITE_I") == 0 ||
43321.115Skamil	           strcmp(operation, "PIOD_WRITE_D") == 0) {
43331.115Skamil		if (strcmp(operation, "PIOD_WRITE_I"))
43341.115Skamil			op = PIOD_WRITE_I;
43351.115Skamil		else
43361.115Skamil			op = PIOD_WRITE_D;
43371.115Skamil
43381.115Skamil		io.piod_op = op;
43391.115Skamil		io.piod_addr = &vector;
43401.115Skamil		io.piod_len = sizeof(int);
43411.115Skamil		io.piod_offs = p;
43421.115Skamil
43431.115Skamil		errno = 0;
43441.115Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io)) == -1);
43451.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
43461.115Skamil	}
43471.115Skamil
43481.115Skamil	DPRINTF("Before resuming the child process where it left off "
43491.115Skamil	    "and without signal to be sent\n");
43501.115Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
43511.115Skamil
43521.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
43531.115Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
43541.115Skamil	    child);
43551.115Skamil
43561.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
43571.115Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
43581.115Skamil}
43591.115Skamil
43601.115Skamil#define BYTES_TRANSFER_EOF(test, operation)				\
43611.115SkamilATF_TC(test);								\
43621.115SkamilATF_TC_HEAD(test, tc)							\
43631.115Skamil{									\
43641.115Skamil	atf_tc_set_md_var(tc, "descr",					\
43651.115Skamil	    "Verify bytes EOF byte transfer for the " operation		\
43661.115Skamil	    " operation");						\
43671.115Skamil}									\
43681.115Skamil									\
43691.115SkamilATF_TC_BODY(test, tc)							\
43701.115Skamil{									\
43711.115Skamil									\
43721.115Skamil	bytes_transfer_eof(operation);					\
43731.115Skamil}
43741.115Skamil
43751.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_read_i, "PT_READ_I")
43761.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_read_d, "PT_READ_D")
43771.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_write_i, "PT_WRITE_I")
43781.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_write_d, "PT_WRITE_D")
43791.115Skamil
43801.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_read_i, "PIOD_READ_I")
43811.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_read_d, "PIOD_READ_D")
43821.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_i, "PIOD_WRITE_I")
43831.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_d, "PIOD_WRITE_D")
43841.115Skamil
43851.115Skamil/// ----------------------------------------------------------------------------
43861.115Skamil
43871.76Sscole#if defined(HAVE_GPREGS) || defined(HAVE_FPREGS)
43881.72Skamilstatic void
43891.72Skamilaccess_regs(const char *regset, const char *aux)
43901.1Skamil{
43911.1Skamil	const int exitval = 5;
43921.1Skamil	const int sigval = SIGSTOP;
43931.1Skamil	pid_t child, wpid;
43941.1Skamil#if defined(TWAIT_HAVE_STATUS)
43951.1Skamil	int status;
43961.1Skamil#endif
43971.72Skamil#if defined(HAVE_GPREGS)
43981.72Skamil	struct reg gpr;
43991.76Sscole	register_t rgstr;
44001.1Skamil#endif
44011.72Skamil#if defined(HAVE_FPREGS)
44021.72Skamil	struct fpreg fpr;
44031.1Skamil#endif
44041.76Sscole
44051.72Skamil#if !defined(HAVE_GPREGS)
44061.72Skamil	if (strcmp(regset, "regs") == 0)
44071.72Skamil		atf_tc_fail("Impossible test scenario!");
44081.1Skamil#endif
44091.1Skamil
44101.72Skamil#if !defined(HAVE_FPREGS)
44111.72Skamil	if (strcmp(regset, "fpregs") == 0)
44121.72Skamil		atf_tc_fail("Impossible test scenario!");
44131.1Skamil#endif
44141.1Skamil
44151.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
44161.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
44171.1Skamil	if (child == 0) {
44181.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
44191.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
44201.1Skamil
44211.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
44221.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
44231.1Skamil
44241.13Schristos		DPRINTF("Before exiting of the child process\n");
44251.1Skamil		_exit(exitval);
44261.1Skamil	}
44271.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
44281.1Skamil
44291.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
44301.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
44311.1Skamil
44321.1Skamil	validate_status_stopped(status, sigval);
44331.1Skamil
44341.1Skamil#if defined(HAVE_GPREGS)
44351.72Skamil	if (strcmp(regset, "regs") == 0) {
44361.72Skamil		DPRINTF("Call GETREGS for the child process\n");
44371.72Skamil		SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1);
44381.72Skamil
44391.72Skamil		if (strcmp(aux, "none") == 0) {
44401.72Skamil			DPRINTF("Retrieved registers\n");
44411.72Skamil		} else if (strcmp(aux, "pc") == 0) {
44421.72Skamil			rgstr = PTRACE_REG_PC(&gpr);
44431.72Skamil			DPRINTF("Retrieved %" PRIxREGISTER "\n", rgstr);
44441.72Skamil		} else if (strcmp(aux, "set_pc") == 0) {
44451.72Skamil			rgstr = PTRACE_REG_PC(&gpr);
44461.72Skamil			PTRACE_REG_SET_PC(&gpr, rgstr);
44471.72Skamil		} else if (strcmp(aux, "sp") == 0) {
44481.72Skamil			rgstr = PTRACE_REG_SP(&gpr);
44491.72Skamil			DPRINTF("Retrieved %" PRIxREGISTER "\n", rgstr);
44501.72Skamil		} else if (strcmp(aux, "intrv") == 0) {
44511.72Skamil			rgstr = PTRACE_REG_INTRV(&gpr);
44521.72Skamil			DPRINTF("Retrieved %" PRIxREGISTER "\n", rgstr);
44531.72Skamil		} else if (strcmp(aux, "setregs") == 0) {
44541.72Skamil			DPRINTF("Call SETREGS for the child process\n");
44551.72Skamil			SYSCALL_REQUIRE(
44561.72Skamil			    ptrace(PT_GETREGS, child, &gpr, 0) != -1);
44571.72Skamil		}
44581.72Skamil	}
44591.1Skamil#endif
44601.1Skamil
44611.72Skamil#if defined(HAVE_FPREGS)
44621.72Skamil	if (strcmp(regset, "fpregs") == 0) {
44631.72Skamil		DPRINTF("Call GETFPREGS for the child process\n");
44641.72Skamil		SYSCALL_REQUIRE(ptrace(PT_GETFPREGS, child, &fpr, 0) != -1);
44651.72Skamil
44661.72Skamil		if (strcmp(aux, "getfpregs") == 0) {
44671.72Skamil			DPRINTF("Retrieved FP registers\n");
44681.72Skamil		} else if (strcmp(aux, "setfpregs") == 0) {
44691.72Skamil			DPRINTF("Call SETFPREGS for the child\n");
44701.72Skamil			SYSCALL_REQUIRE(
44711.72Skamil			    ptrace(PT_SETFPREGS, child, &fpr, 0) != -1);
44721.72Skamil		}
44731.1Skamil	}
44741.1Skamil#endif
44751.1Skamil
44761.13Schristos	DPRINTF("Before resuming the child process where it left off and "
44771.1Skamil	    "without signal to be sent\n");
44781.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
44791.1Skamil
44801.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
44811.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
44821.1Skamil
44831.1Skamil	validate_status_exited(status, exitval);
44841.1Skamil
44851.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
44861.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
44871.1Skamil}
44881.1Skamil
44891.72Skamil#define ACCESS_REGS(test, regset, aux)					\
44901.72SkamilATF_TC(test);								\
44911.72SkamilATF_TC_HEAD(test, tc)							\
44921.72Skamil{									\
44931.72Skamil        atf_tc_set_md_var(tc, "descr",					\
44941.72Skamil            "Verify " regset " with auxiliary operation: " aux);	\
44951.72Skamil}									\
44961.72Skamil									\
44971.72SkamilATF_TC_BODY(test, tc)							\
44981.72Skamil{									\
44991.72Skamil									\
45001.72Skamil        access_regs(regset, aux);					\
45011.1Skamil}
45021.1Skamil#endif
45031.1Skamil
45041.72Skamil#if defined(HAVE_GPREGS)
45051.72SkamilACCESS_REGS(access_regs1, "regs", "none")
45061.72SkamilACCESS_REGS(access_regs2, "regs", "pc")
45071.72SkamilACCESS_REGS(access_regs3, "regs", "set_pc")
45081.72SkamilACCESS_REGS(access_regs4, "regs", "sp")
45091.72SkamilACCESS_REGS(access_regs5, "regs", "intrv")
45101.72SkamilACCESS_REGS(access_regs6, "regs", "setregs")
45111.1Skamil#endif
45121.1Skamil#if defined(HAVE_FPREGS)
45131.72SkamilACCESS_REGS(access_fpregs1, "fpregs", "getfpregs")
45141.72SkamilACCESS_REGS(access_fpregs2, "fpregs", "setfpregs")
45151.1Skamil#endif
45161.1Skamil
45171.72Skamil/// ----------------------------------------------------------------------------
45181.1Skamil
45191.1Skamil#if defined(PT_STEP)
45201.1Skamilstatic void
45211.95Skamilptrace_step(int N, int setstep, bool masked, bool ignored)
45221.1Skamil{
45231.1Skamil	const int exitval = 5;
45241.1Skamil	const int sigval = SIGSTOP;
45251.1Skamil	pid_t child, wpid;
45261.1Skamil#if defined(TWAIT_HAVE_STATUS)
45271.1Skamil	int status;
45281.1Skamil#endif
45291.1Skamil	int happy;
45301.95Skamil	struct sigaction sa;
45311.81Skamil	struct ptrace_siginfo info;
45321.95Skamil	sigset_t intmask;
45331.95Skamil	struct kinfo_proc2 kp;
45341.95Skamil	size_t len = sizeof(kp);
45351.95Skamil
45361.95Skamil	int name[6];
45371.95Skamil	const size_t namelen = __arraycount(name);
45381.95Skamil	ki_sigset_t kp_sigmask;
45391.95Skamil	ki_sigset_t kp_sigignore;
45401.1Skamil
45411.1Skamil#if defined(__arm__)
45421.1Skamil	/* PT_STEP not supported on arm 32-bit */
45431.1Skamil	atf_tc_expect_fail("PR kern/52119");
45441.1Skamil#endif
45451.1Skamil
45461.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
45471.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
45481.1Skamil	if (child == 0) {
45491.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
45501.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
45511.1Skamil
45521.95Skamil		if (masked) {
45531.95Skamil			sigemptyset(&intmask);
45541.95Skamil			sigaddset(&intmask, SIGTRAP);
45551.95Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
45561.95Skamil		}
45571.95Skamil
45581.95Skamil		if (ignored) {
45591.95Skamil			memset(&sa, 0, sizeof(sa));
45601.95Skamil			sa.sa_handler = SIG_IGN;
45611.95Skamil			sigemptyset(&sa.sa_mask);
45621.95Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
45631.95Skamil		}
45641.95Skamil
45651.1Skamil		happy = check_happy(999);
45661.1Skamil
45671.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
45681.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
45691.1Skamil
45701.1Skamil		FORKEE_ASSERT_EQ(happy, check_happy(999));
45711.1Skamil
45721.13Schristos		DPRINTF("Before exiting of the child process\n");
45731.1Skamil		_exit(exitval);
45741.1Skamil	}
45751.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
45761.1Skamil
45771.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
45781.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
45791.1Skamil
45801.1Skamil	validate_status_stopped(status, sigval);
45811.1Skamil
45821.81Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
45831.81Skamil	SYSCALL_REQUIRE(
45841.81Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
45851.81Skamil
45861.81Skamil	DPRINTF("Before checking siginfo_t\n");
45871.81Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
45881.81Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
45891.81Skamil
45901.95Skamil	name[0] = CTL_KERN,
45911.95Skamil	name[1] = KERN_PROC2,
45921.95Skamil	name[2] = KERN_PROC_PID;
45931.95Skamil	name[3] = child;
45941.95Skamil	name[4] = sizeof(kp);
45951.95Skamil	name[5] = 1;
45961.95Skamil
45971.95Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
45981.95Skamil
45991.95Skamil	if (masked)
46001.95Skamil		kp_sigmask = kp.p_sigmask;
46011.95Skamil
46021.95Skamil	if (ignored)
46031.95Skamil		kp_sigignore = kp.p_sigignore;
46041.95Skamil
46051.1Skamil	while (N --> 0) {
46061.2Skamil		if (setstep) {
46071.13Schristos			DPRINTF("Before resuming the child process where it "
46081.2Skamil			    "left off and without signal to be sent (use "
46091.9Skamil			    "PT_SETSTEP and PT_CONTINUE)\n");
46101.13Schristos			SYSCALL_REQUIRE(ptrace(PT_SETSTEP, child, 0, 0) != -1);
46111.13Schristos			SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0)
46121.2Skamil			    != -1);
46131.2Skamil		} else {
46141.13Schristos			DPRINTF("Before resuming the child process where it "
46151.2Skamil			    "left off and without signal to be sent (use "
46161.2Skamil			    "PT_STEP)\n");
46171.13Schristos			SYSCALL_REQUIRE(ptrace(PT_STEP, child, (void *)1, 0)
46181.2Skamil			    != -1);
46191.2Skamil		}
46201.1Skamil
46211.13Schristos		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46221.1Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
46231.1Skamil		    child);
46241.1Skamil
46251.1Skamil		validate_status_stopped(status, SIGTRAP);
46261.2Skamil
46271.81Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
46281.81Skamil		SYSCALL_REQUIRE(
46291.81Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
46301.81Skamil
46311.81Skamil		DPRINTF("Before checking siginfo_t\n");
46321.81Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
46331.81Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_TRACE);
46341.81Skamil
46351.2Skamil		if (setstep) {
46361.13Schristos			SYSCALL_REQUIRE(ptrace(PT_CLEARSTEP, child, 0, 0) != -1);
46371.2Skamil		}
46381.95Skamil
46391.95Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
46401.95Skamil
46411.95Skamil		if (masked) {
46421.95Skamil			DPRINTF("kp_sigmask="
46431.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
46441.95Skamil			    PRIx32 "\n",
46451.95Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
46461.95Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
46471.95Skamil
46481.95Skamil			DPRINTF("kp.p_sigmask="
46491.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
46501.95Skamil			    PRIx32 "\n",
46511.95Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
46521.95Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
46531.95Skamil
46541.95Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
46551.95Skamil			    sizeof(kp_sigmask)));
46561.95Skamil		}
46571.95Skamil
46581.95Skamil		if (ignored) {
46591.95Skamil			DPRINTF("kp_sigignore="
46601.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
46611.95Skamil			    PRIx32 "\n",
46621.95Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
46631.95Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
46641.95Skamil
46651.95Skamil			DPRINTF("kp.p_sigignore="
46661.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
46671.95Skamil			    PRIx32 "\n",
46681.95Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
46691.95Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
46701.95Skamil
46711.95Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
46721.95Skamil			    sizeof(kp_sigignore)));
46731.95Skamil		}
46741.1Skamil	}
46751.1Skamil
46761.13Schristos	DPRINTF("Before resuming the child process where it left off and "
46771.1Skamil	    "without signal to be sent\n");
46781.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
46791.1Skamil
46801.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46811.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
46821.1Skamil
46831.1Skamil	validate_status_exited(status, exitval);
46841.1Skamil
46851.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46861.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
46871.1Skamil}
46881.1Skamil
46891.73Skamil#define PTRACE_STEP(test, N, setstep)					\
46901.73SkamilATF_TC(test);								\
46911.73SkamilATF_TC_HEAD(test, tc)							\
46921.73Skamil{									\
46931.73Skamil        atf_tc_set_md_var(tc, "descr",					\
46941.74Skamil            "Verify " #N " (PT_SETSTEP set to: " #setstep ")");		\
46951.73Skamil}									\
46961.73Skamil									\
46971.73SkamilATF_TC_BODY(test, tc)							\
46981.73Skamil{									\
46991.73Skamil									\
47001.95Skamil        ptrace_step(N, setstep, false, false);				\
47011.1Skamil}
47021.1Skamil
47031.73SkamilPTRACE_STEP(step1, 1, 0)
47041.73SkamilPTRACE_STEP(step2, 2, 0)
47051.73SkamilPTRACE_STEP(step3, 3, 0)
47061.73SkamilPTRACE_STEP(step4, 4, 0)
47071.73SkamilPTRACE_STEP(setstep1, 1, 1)
47081.73SkamilPTRACE_STEP(setstep2, 2, 1)
47091.73SkamilPTRACE_STEP(setstep3, 3, 1)
47101.73SkamilPTRACE_STEP(setstep4, 4, 1)
47111.95Skamil
47121.95SkamilATF_TC(step_signalmasked);
47131.95SkamilATF_TC_HEAD(step_signalmasked, tc)
47141.95Skamil{
47151.95Skamil	atf_tc_set_md_var(tc, "descr", "Verify PT_STEP with masked SIGTRAP");
47161.95Skamil}
47171.95Skamil
47181.95SkamilATF_TC_BODY(step_signalmasked, tc)
47191.95Skamil{
47201.95Skamil
47211.95Skamil	ptrace_step(1, 0, true, false);
47221.95Skamil}
47231.95Skamil
47241.95SkamilATF_TC(step_signalignored);
47251.95SkamilATF_TC_HEAD(step_signalignored, tc)
47261.95Skamil{
47271.95Skamil	atf_tc_set_md_var(tc, "descr", "Verify PT_STEP with ignored SIGTRAP");
47281.95Skamil}
47291.95Skamil
47301.95SkamilATF_TC_BODY(step_signalignored, tc)
47311.95Skamil{
47321.95Skamil
47331.95Skamil	ptrace_step(1, 0, false, true);
47341.95Skamil}
47351.1Skamil#endif
47361.1Skamil
47371.73Skamil/// ----------------------------------------------------------------------------
47381.1Skamil
47391.75Skamilstatic void
47401.75Skamilptrace_kill(const char *type)
47411.1Skamil{
47421.75Skamil	const int sigval = SIGSTOP;
47431.1Skamil	pid_t child, wpid;
47441.1Skamil#if defined(TWAIT_HAVE_STATUS)
47451.1Skamil	int status;
47461.1Skamil#endif
47471.1Skamil
47481.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
47491.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
47501.1Skamil	if (child == 0) {
47511.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
47521.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
47531.1Skamil
47541.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
47551.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
47561.1Skamil
47571.1Skamil		/* NOTREACHED */
47581.1Skamil		FORKEE_ASSERTX(0 &&
47591.1Skamil		    "Child should be terminated by a signal from its parent");
47601.1Skamil	}
47611.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
47621.1Skamil
47631.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
47641.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
47651.1Skamil
47661.1Skamil	validate_status_stopped(status, sigval);
47671.1Skamil
47681.75Skamil	DPRINTF("Before killing the child process with %s\n", type);
47691.75Skamil	if (strcmp(type, "ptrace(PT_KILL)") == 0) {
47701.75Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void*)1, 0) != -1);
47711.75Skamil	} else if (strcmp(type, "kill(SIGKILL)") == 0) {
47721.75Skamil		kill(child, SIGKILL);
47731.75Skamil	} else if (strcmp(type, "killpg(SIGKILL)") == 0) {
47741.75Skamil		setpgid(child, 0);
47751.75Skamil		killpg(getpgid(child), SIGKILL);
47761.75Skamil	}
47771.1Skamil
47781.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
47791.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
47801.1Skamil
47811.75Skamil	validate_status_signaled(status, SIGKILL, 0);
47821.1Skamil
47831.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
47841.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
47851.1Skamil}
47861.1Skamil
47871.75Skamil#define PTRACE_KILL(test, type)						\
47881.75SkamilATF_TC(test);								\
47891.75SkamilATF_TC_HEAD(test, tc)							\
47901.75Skamil{									\
47911.75Skamil        atf_tc_set_md_var(tc, "descr",					\
47921.75Skamil            "Verify killing the child with " type);			\
47931.75Skamil}									\
47941.75Skamil									\
47951.75SkamilATF_TC_BODY(test, tc)							\
47961.75Skamil{									\
47971.75Skamil									\
47981.75Skamil        ptrace_kill(type);						\
47991.1Skamil}
48001.1Skamil
48011.75Skamil// PT_CONTINUE with SIGKILL is covered by traceme_sendsignal_simple1
48021.75SkamilPTRACE_KILL(kill1, "ptrace(PT_KILL)")
48031.75SkamilPTRACE_KILL(kill2, "kill(SIGKILL)")
48041.75SkamilPTRACE_KILL(kill3, "killpg(SIGKILL)")
48051.1Skamil
48061.75Skamil/// ----------------------------------------------------------------------------
48071.1Skamil
48081.77Skamilstatic void
48091.77Skamiltraceme_lwpinfo(const int threads)
48101.1Skamil{
48111.1Skamil	const int sigval = SIGSTOP;
48121.77Skamil	const int sigval2 = SIGINT;
48131.1Skamil	pid_t child, wpid;
48141.1Skamil#if defined(TWAIT_HAVE_STATUS)
48151.1Skamil	int status;
48161.1Skamil#endif
48171.77Skamil	struct ptrace_lwpinfo lwp = {0, 0};
48181.77Skamil	struct ptrace_siginfo info;
48191.77Skamil
48201.77Skamil	/* Maximum number of supported threads in this test */
48211.77Skamil	pthread_t t[3];
48221.77Skamil	int n, rv;
48231.77Skamil
48241.77Skamil	ATF_REQUIRE((int)__arraycount(t) >= threads);
48251.1Skamil
48261.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
48271.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
48281.1Skamil	if (child == 0) {
48291.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
48301.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
48311.1Skamil
48321.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
48331.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
48341.1Skamil
48351.77Skamil		for (n = 0; n < threads; n++) {
48361.77Skamil			rv = pthread_create(&t[n], NULL, infinite_thread, NULL);
48371.77Skamil			FORKEE_ASSERT(rv == 0);
48381.77Skamil		}
48391.77Skamil
48401.77Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval2));
48411.77Skamil		FORKEE_ASSERT(raise(sigval2) == 0);
48421.77Skamil
48431.77Skamil		/* NOTREACHED */
48441.77Skamil		FORKEE_ASSERTX(0 && "Not reached");
48451.1Skamil	}
48461.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
48471.1Skamil
48481.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48491.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
48501.1Skamil
48511.1Skamil	validate_status_stopped(status, sigval);
48521.1Skamil
48531.77Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
48541.77Skamil	SYSCALL_REQUIRE(
48551.77Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
48561.77Skamil
48571.77Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
48581.77Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
48591.77Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
48601.77Skamil	    info.psi_siginfo.si_errno);
48611.77Skamil
48621.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
48631.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
48641.77Skamil
48651.13Schristos	DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
48661.77Skamil	SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
48671.1Skamil
48681.77Skamil	DPRINTF("Assert that there exists a single thread only\n");
48691.77Skamil	ATF_REQUIRE(lwp.pl_lwpid > 0);
48701.1Skamil
48711.13Schristos	DPRINTF("Assert that lwp thread %d received event PL_EVENT_SIGNAL\n",
48721.77Skamil	    lwp.pl_lwpid);
48731.77Skamil	FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
48741.1Skamil
48751.13Schristos	DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
48761.77Skamil	SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
48771.1Skamil
48781.77Skamil	DPRINTF("Assert that there exists a single thread only\n");
48791.77Skamil	ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
48801.1Skamil
48811.13Schristos	DPRINTF("Before resuming the child process where it left off and "
48821.1Skamil	    "without signal to be sent\n");
48831.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
48841.1Skamil
48851.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48861.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
48871.1Skamil
48881.77Skamil	validate_status_stopped(status, sigval2);
48891.77Skamil
48901.77Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
48911.77Skamil	SYSCALL_REQUIRE(
48921.77Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
48931.77Skamil
48941.77Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
48951.77Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
48961.77Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
48971.77Skamil	    info.psi_siginfo.si_errno);
48981.77Skamil
48991.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval2);
49001.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
49011.77Skamil
49021.77Skamil	memset(&lwp, 0, sizeof(lwp));
49031.77Skamil
49041.77Skamil	for (n = 0; n <= threads; n++) {
49051.77Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
49061.77Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
49071.77Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
49081.77Skamil
49091.77Skamil		DPRINTF("Assert that the thread exists\n");
49101.77Skamil		ATF_REQUIRE(lwp.pl_lwpid > 0);
49111.77Skamil
49121.77Skamil		DPRINTF("Assert that lwp thread %d received expected event\n",
49131.77Skamil		    lwp.pl_lwpid);
49141.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, info.psi_lwpid == lwp.pl_lwpid ?
49151.77Skamil		    PL_EVENT_SIGNAL : PL_EVENT_NONE);
49161.77Skamil	}
49171.77Skamil	DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
49181.77Skamil	SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
49191.77Skamil	DPRINTF("LWP=%d\n", lwp.pl_lwpid);
49201.77Skamil
49211.77Skamil	DPRINTF("Assert that there are no more threads\n");
49221.77Skamil	ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
49231.77Skamil
49241.77Skamil	DPRINTF("Before resuming the child process where it left off and "
49251.77Skamil	    "without signal to be sent\n");
49261.77Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, SIGKILL) != -1);
49271.77Skamil
49281.77Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
49291.77Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
49301.77Skamil
49311.77Skamil	validate_status_signaled(status, SIGKILL, 0);
49321.1Skamil
49331.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
49341.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
49351.1Skamil}
49361.1Skamil
49371.77Skamil#define TRACEME_LWPINFO(test, threads)					\
49381.77SkamilATF_TC(test);								\
49391.77SkamilATF_TC_HEAD(test, tc)							\
49401.77Skamil{									\
49411.77Skamil	atf_tc_set_md_var(tc, "descr",					\
49421.77Skamil	    "Verify LWPINFO with the child with " #threads		\
49431.77Skamil	    " spawned extra threads");					\
49441.77Skamil}									\
49451.77Skamil									\
49461.77SkamilATF_TC_BODY(test, tc)							\
49471.77Skamil{									\
49481.77Skamil									\
49491.77Skamil	traceme_lwpinfo(threads);					\
49501.1Skamil}
49511.1Skamil
49521.77SkamilTRACEME_LWPINFO(traceme_lwpinfo0, 0)
49531.77SkamilTRACEME_LWPINFO(traceme_lwpinfo1, 1)
49541.77SkamilTRACEME_LWPINFO(traceme_lwpinfo2, 2)
49551.77SkamilTRACEME_LWPINFO(traceme_lwpinfo3, 3)
49561.77Skamil
49571.77Skamil/// ----------------------------------------------------------------------------
49581.77Skamil
49591.77Skamil#if defined(TWAIT_HAVE_PID)
49601.77Skamilstatic void
49611.77Skamilattach_lwpinfo(const int threads)
49621.1Skamil{
49631.77Skamil	const int sigval = SIGINT;
49641.1Skamil	struct msg_fds parent_tracee, parent_tracer;
49651.1Skamil	const int exitval_tracer = 10;
49661.1Skamil	pid_t tracee, tracer, wpid;
49671.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
49681.1Skamil#if defined(TWAIT_HAVE_STATUS)
49691.1Skamil	int status;
49701.1Skamil#endif
49711.77Skamil	struct ptrace_lwpinfo lwp = {0, 0};
49721.77Skamil	struct ptrace_siginfo info;
49731.77Skamil
49741.77Skamil	/* Maximum number of supported threads in this test */
49751.77Skamil	pthread_t t[3];
49761.77Skamil	int n, rv;
49771.1Skamil
49781.13Schristos	DPRINTF("Spawn tracee\n");
49791.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
49801.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
49811.1Skamil	tracee = atf_utils_fork();
49821.1Skamil	if (tracee == 0) {
49831.1Skamil		/* Wait for message from the parent */
49841.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
49851.1Skamil
49861.77Skamil		CHILD_FROM_PARENT("spawn threads", parent_tracee, msg);
49871.77Skamil
49881.77Skamil		for (n = 0; n < threads; n++) {
49891.77Skamil			rv = pthread_create(&t[n], NULL, infinite_thread, NULL);
49901.77Skamil			FORKEE_ASSERT(rv == 0);
49911.77Skamil		}
49921.77Skamil
49931.77Skamil		CHILD_TO_PARENT("tracee exit", parent_tracee, msg);
49941.77Skamil
49951.77Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
49961.77Skamil		FORKEE_ASSERT(raise(sigval) == 0);
49971.77Skamil
49981.77Skamil		/* NOTREACHED */
49991.77Skamil		FORKEE_ASSERTX(0 && "Not reached");
50001.1Skamil	}
50011.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
50021.1Skamil
50031.13Schristos	DPRINTF("Spawn debugger\n");
50041.1Skamil	tracer = atf_utils_fork();
50051.1Skamil	if (tracer == 0) {
50061.1Skamil		/* No IPC to communicate with the child */
50071.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
50081.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
50091.1Skamil
50101.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
50111.1Skamil		FORKEE_REQUIRE_SUCCESS(
50121.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
50131.1Skamil
50141.1Skamil		forkee_status_stopped(status, SIGSTOP);
50151.1Skamil
50161.77Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
50171.77Skamil		    "tracee");
50181.77Skamil		FORKEE_ASSERT(
50191.77Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
50201.77Skamil
50211.77Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
50221.77Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
50231.77Skamil		    "si_errno=%#x\n",
50241.77Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
50251.77Skamil		    info.psi_siginfo.si_errno);
50261.77Skamil
50271.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
50281.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
50291.77Skamil
50301.13Schristos		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
50311.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
50321.1Skamil		    != -1);
50331.1Skamil
50341.13Schristos		DPRINTF("Assert that there exists a thread\n");
50351.77Skamil		FORKEE_ASSERTX(lwp.pl_lwpid > 0);
50361.1Skamil
50371.13Schristos		DPRINTF("Assert that lwp thread %d received event "
50381.77Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
50391.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
50401.1Skamil
50411.77Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
50421.77Skamil		    "tracee\n");
50431.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
50441.1Skamil		    != -1);
50451.1Skamil
50461.77Skamil		DPRINTF("Assert that there are no more lwp threads in "
50471.77Skamil		    "tracee\n");
50481.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
50491.1Skamil
50501.1Skamil		/* Resume tracee with PT_CONTINUE */
50511.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
50521.1Skamil
50531.1Skamil		/* Inform parent that tracer has attached to tracee */
50541.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
50551.77Skamil
50561.1Skamil		/* Wait for parent */
50571.1Skamil		CHILD_FROM_PARENT("tracer wait", parent_tracer, msg);
50581.1Skamil
50591.77Skamil		/* Wait for tracee and assert that it raised a signal */
50601.77Skamil		FORKEE_REQUIRE_SUCCESS(
50611.77Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
50621.77Skamil
50631.77Skamil		forkee_status_stopped(status, SIGINT);
50641.77Skamil
50651.77Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
50661.77Skamil		    "child");
50671.77Skamil		FORKEE_ASSERT(
50681.77Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
50691.77Skamil
50701.77Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
50711.77Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
50721.77Skamil		    "si_errno=%#x\n",
50731.77Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
50741.77Skamil		    info.psi_siginfo.si_errno);
50751.77Skamil
50761.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
50771.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
50781.77Skamil
50791.77Skamil		memset(&lwp, 0, sizeof(lwp));
50801.77Skamil
50811.77Skamil		for (n = 0; n <= threads; n++) {
50821.77Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
50831.77Skamil			    "child\n");
50841.77Skamil			FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp,
50851.77Skamil			    sizeof(lwp)) != -1);
50861.77Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
50871.77Skamil
50881.77Skamil			DPRINTF("Assert that the thread exists\n");
50891.77Skamil			FORKEE_ASSERT(lwp.pl_lwpid > 0);
50901.77Skamil
50911.77Skamil			DPRINTF("Assert that lwp thread %d received expected "
50921.77Skamil			    "event\n", lwp.pl_lwpid);
50931.77Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
50941.77Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
50951.77Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
50961.77Skamil		}
50971.77Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
50981.77Skamil		    "tracee\n");
50991.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
51001.77Skamil		    != -1);
51011.77Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
51021.77Skamil
51031.77Skamil		DPRINTF("Assert that there are no more threads\n");
51041.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
51051.77Skamil
51061.77Skamil		DPRINTF("Before resuming the child process where it left off "
51071.77Skamil		    "and without signal to be sent\n");
51081.77Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, SIGKILL)
51091.77Skamil		    != -1);
51101.77Skamil
51111.1Skamil		/* Wait for tracee and assert that it exited */
51121.1Skamil		FORKEE_REQUIRE_SUCCESS(
51131.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
51141.1Skamil
51151.77Skamil		forkee_status_signaled(status, SIGKILL, 0);
51161.1Skamil
51171.13Schristos		DPRINTF("Before exiting of the tracer process\n");
51181.1Skamil		_exit(exitval_tracer);
51191.1Skamil	}
51201.1Skamil
51211.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
51221.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
51231.1Skamil
51241.77Skamil	DPRINTF("Resume the tracee and spawn threads\n");
51251.77Skamil	PARENT_TO_CHILD("spawn threads", parent_tracee, msg);
51261.77Skamil
51271.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
51281.77Skamil	PARENT_FROM_CHILD("tracee exit", parent_tracee, msg);
51291.1Skamil
51301.77Skamil	DPRINTF("Resume the tracer and let it detect multiple threads\n");
51311.1Skamil	PARENT_TO_CHILD("tracer wait", parent_tracer, msg);
51321.1Skamil
51331.13Schristos	DPRINTF("Wait for tracer to finish its job and exit - calling %s()\n",
51341.1Skamil	    TWAIT_FNAME);
51351.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
51361.1Skamil	    tracer);
51371.1Skamil
51381.1Skamil	validate_status_exited(status, exitval_tracer);
51391.1Skamil
51401.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
51411.1Skamil	    TWAIT_FNAME);
51421.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
51431.1Skamil	    tracee);
51441.1Skamil
51451.77Skamil	validate_status_signaled(status, SIGKILL, 0);
51461.1Skamil
51471.1Skamil	msg_close(&parent_tracer);
51481.1Skamil	msg_close(&parent_tracee);
51491.1Skamil}
51501.77Skamil
51511.77Skamil#define ATTACH_LWPINFO(test, threads)					\
51521.77SkamilATF_TC(test);								\
51531.77SkamilATF_TC_HEAD(test, tc)							\
51541.77Skamil{									\
51551.77Skamil	atf_tc_set_md_var(tc, "descr",					\
51561.77Skamil	    "Verify LWPINFO with the child with " #threads		\
51571.77Skamil	    " spawned extra threads (tracer is not the original "	\
51581.77Skamil	    "parent)");							\
51591.77Skamil}									\
51601.77Skamil									\
51611.77SkamilATF_TC_BODY(test, tc)							\
51621.77Skamil{									\
51631.77Skamil									\
51641.77Skamil	attach_lwpinfo(threads);					\
51651.77Skamil}
51661.77Skamil
51671.77SkamilATTACH_LWPINFO(attach_lwpinfo0, 0)
51681.77SkamilATTACH_LWPINFO(attach_lwpinfo1, 1)
51691.77SkamilATTACH_LWPINFO(attach_lwpinfo2, 2)
51701.77SkamilATTACH_LWPINFO(attach_lwpinfo3, 3)
51711.1Skamil#endif
51721.1Skamil
51731.77Skamil/// ----------------------------------------------------------------------------
51741.77Skamil
51751.1Skamilstatic void
51761.79Skamilptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c), int *signal_caught)
51771.1Skamil{
51781.1Skamil	const int exitval = 5;
51791.1Skamil	const int sigval = SIGINT;
51801.1Skamil	const int sigfaked = SIGTRAP;
51811.1Skamil	const int sicodefaked = TRAP_BRKPT;
51821.1Skamil	pid_t child, wpid;
51831.1Skamil	struct sigaction sa;
51841.1Skamil#if defined(TWAIT_HAVE_STATUS)
51851.1Skamil	int status;
51861.1Skamil#endif
51871.1Skamil	struct ptrace_siginfo info;
51881.1Skamil	memset(&info, 0, sizeof(info));
51891.1Skamil
51901.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
51911.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
51921.1Skamil	if (child == 0) {
51931.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
51941.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
51951.1Skamil
51961.79Skamil		sa.sa_sigaction = sah;
51971.1Skamil		sa.sa_flags = SA_SIGINFO;
51981.1Skamil		sigemptyset(&sa.sa_mask);
51991.1Skamil
52001.79Skamil		FORKEE_ASSERT(sigaction(faked ? sigfaked : sigval, &sa, NULL)
52011.79Skamil		    != -1);
52021.1Skamil
52031.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
52041.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
52051.1Skamil
52061.79Skamil		FORKEE_ASSERT_EQ(*signal_caught, 1);
52071.1Skamil
52081.13Schristos		DPRINTF("Before exiting of the child process\n");
52091.1Skamil		_exit(exitval);
52101.1Skamil	}
52111.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
52121.1Skamil
52131.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
52141.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
52151.1Skamil
52161.1Skamil	validate_status_stopped(status, sigval);
52171.1Skamil
52181.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
52191.61Skre	SYSCALL_REQUIRE(
52201.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
52211.1Skamil
52221.13Schristos	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
52231.13Schristos	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
52241.1Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
52251.1Skamil	    info.psi_siginfo.si_errno);
52261.1Skamil
52271.79Skamil	if (faked) {
52281.79Skamil		DPRINTF("Before setting new faked signal to signo=%d "
52291.79Skamil		    "si_code=%d\n", sigfaked, sicodefaked);
52301.79Skamil		info.psi_siginfo.si_signo = sigfaked;
52311.79Skamil		info.psi_siginfo.si_code = sicodefaked;
52321.79Skamil	}
52331.1Skamil
52341.13Schristos	DPRINTF("Before calling ptrace(2) with PT_SET_SIGINFO for child\n");
52351.61Skre	SYSCALL_REQUIRE(
52361.61Skre	    ptrace(PT_SET_SIGINFO, child, &info, sizeof(info)) != -1);
52371.1Skamil
52381.79Skamil	if (faked) {
52391.79Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
52401.79Skamil		    "child\n");
52411.79Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
52421.79Skamil		    sizeof(info)) != -1);
52431.1Skamil
52441.79Skamil		DPRINTF("Before checking siginfo_t\n");
52451.79Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigfaked);
52461.79Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, sicodefaked);
52471.79Skamil	}
52481.1Skamil
52491.13Schristos	DPRINTF("Before resuming the child process where it left off and "
52501.1Skamil	    "without signal to be sent\n");
52511.79Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
52521.79Skamil	    faked ? sigfaked : sigval) != -1);
52531.1Skamil
52541.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
52551.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
52561.1Skamil
52571.1Skamil	validate_status_exited(status, exitval);
52581.1Skamil
52591.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
52601.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
52611.1Skamil}
52621.1Skamil
52631.79Skamil#define PTRACE_SIGINFO(test, faked)					\
52641.79SkamilATF_TC(test);								\
52651.79SkamilATF_TC_HEAD(test, tc)							\
52661.79Skamil{									\
52671.79Skamil	atf_tc_set_md_var(tc, "descr",					\
52681.79Skamil	    "Verify basic PT_GET_SIGINFO and PT_SET_SIGINFO calls"	\
52691.79Skamil	    "with%s setting signal to new value", faked ? "" : "out");	\
52701.79Skamil}									\
52711.79Skamil									\
52721.79Skamilstatic int test##_caught = 0;						\
52731.79Skamil									\
52741.79Skamilstatic void								\
52751.79Skamiltest##_sighandler(int sig, siginfo_t *info, void *ctx)			\
52761.79Skamil{									\
52771.79Skamil	if (faked) {							\
52781.79Skamil		FORKEE_ASSERT_EQ(sig, SIGTRAP);				\
52791.79Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGTRAP);		\
52801.79Skamil		FORKEE_ASSERT_EQ(info->si_code, TRAP_BRKPT);		\
52811.79Skamil	} else {							\
52821.79Skamil		FORKEE_ASSERT_EQ(sig, SIGINT);				\
52831.79Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGINT);		\
52841.79Skamil		FORKEE_ASSERT_EQ(info->si_code, SI_LWP);		\
52851.79Skamil	}								\
52861.79Skamil									\
52871.79Skamil	++ test##_caught;						\
52881.79Skamil}									\
52891.79Skamil									\
52901.79SkamilATF_TC_BODY(test, tc)							\
52911.79Skamil{									\
52921.79Skamil									\
52931.79Skamil	ptrace_siginfo(faked, test##_sighandler, & test##_caught); 	\
52941.79Skamil}
52951.79Skamil
52961.79SkamilPTRACE_SIGINFO(siginfo_set_unmodified, false)
52971.79SkamilPTRACE_SIGINFO(siginfo_set_faked, true)
52981.79Skamil
52991.79Skamil/// ----------------------------------------------------------------------------
53001.79Skamil
53011.97Skamilstatic void
53021.97Skamiltraceme_exec(bool masked, bool ignored)
53031.1Skamil{
53041.1Skamil	const int sigval = SIGTRAP;
53051.1Skamil	pid_t child, wpid;
53061.1Skamil#if defined(TWAIT_HAVE_STATUS)
53071.1Skamil	int status;
53081.1Skamil#endif
53091.97Skamil	struct sigaction sa;
53101.97Skamil	struct ptrace_siginfo info;
53111.97Skamil	sigset_t intmask;
53121.97Skamil	struct kinfo_proc2 kp;
53131.97Skamil	size_t len = sizeof(kp);
53141.97Skamil
53151.97Skamil	int name[6];
53161.97Skamil	const size_t namelen = __arraycount(name);
53171.97Skamil	ki_sigset_t kp_sigmask;
53181.97Skamil	ki_sigset_t kp_sigignore;
53191.1Skamil
53201.1Skamil	memset(&info, 0, sizeof(info));
53211.1Skamil
53221.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
53231.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
53241.1Skamil	if (child == 0) {
53251.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
53261.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
53271.1Skamil
53281.97Skamil		if (masked) {
53291.97Skamil			sigemptyset(&intmask);
53301.97Skamil			sigaddset(&intmask, sigval);
53311.97Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
53321.97Skamil		}
53331.97Skamil
53341.97Skamil		if (ignored) {
53351.97Skamil			memset(&sa, 0, sizeof(sa));
53361.97Skamil			sa.sa_handler = SIG_IGN;
53371.97Skamil			sigemptyset(&sa.sa_mask);
53381.97Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
53391.97Skamil		}
53401.97Skamil
53411.13Schristos		DPRINTF("Before calling execve(2) from child\n");
53421.1Skamil		execlp("/bin/echo", "/bin/echo", NULL);
53431.1Skamil
53441.1Skamil		FORKEE_ASSERT(0 && "Not reached");
53451.1Skamil	}
53461.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
53471.1Skamil
53481.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
53491.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
53501.1Skamil
53511.1Skamil	validate_status_stopped(status, sigval);
53521.1Skamil
53531.97Skamil	name[0] = CTL_KERN,
53541.97Skamil	name[1] = KERN_PROC2,
53551.97Skamil	name[2] = KERN_PROC_PID;
53561.97Skamil	name[3] = getpid();
53571.97Skamil	name[4] = sizeof(kp);
53581.97Skamil	name[5] = 1;
53591.97Skamil
53601.97Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
53611.97Skamil
53621.97Skamil	if (masked)
53631.97Skamil		kp_sigmask = kp.p_sigmask;
53641.97Skamil
53651.97Skamil	if (ignored)
53661.97Skamil		kp_sigignore = kp.p_sigignore;
53671.97Skamil
53681.97Skamil	name[3] = getpid();
53691.97Skamil
53701.97Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
53711.97Skamil
53721.97Skamil	if (masked) {
53731.97Skamil		DPRINTF("kp_sigmask="
53741.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
53751.97Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
53761.97Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
53771.97Skamil
53781.97Skamil		DPRINTF("kp.p_sigmask="
53791.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
53801.97Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
53811.97Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
53821.97Skamil
53831.97Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
53841.97Skamil		    sizeof(kp_sigmask)));
53851.97Skamil	}
53861.97Skamil
53871.97Skamil	if (ignored) {
53881.97Skamil		DPRINTF("kp_sigignore="
53891.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
53901.97Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
53911.97Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
53921.97Skamil
53931.97Skamil		DPRINTF("kp.p_sigignore="
53941.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
53951.97Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
53961.97Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
53971.97Skamil
53981.97Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
53991.97Skamil		    sizeof(kp_sigignore)));
54001.97Skamil	}
54011.97Skamil
54021.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
54031.61Skre	SYSCALL_REQUIRE(
54041.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
54051.1Skamil
54061.13Schristos	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
54071.13Schristos	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
54081.1Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
54091.1Skamil	    info.psi_siginfo.si_errno);
54101.1Skamil
54111.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
54121.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
54131.1Skamil
54141.13Schristos	DPRINTF("Before resuming the child process where it left off and "
54151.1Skamil	    "without signal to be sent\n");
54161.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
54171.1Skamil
54181.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
54191.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
54201.1Skamil
54211.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
54221.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
54231.1Skamil}
54241.1Skamil
54251.97Skamil#define TRACEME_EXEC(test, masked, ignored)				\
54261.97SkamilATF_TC(test);								\
54271.97SkamilATF_TC_HEAD(test, tc)							\
54281.97Skamil{									\
54291.97Skamil       atf_tc_set_md_var(tc, "descr",					\
54301.97Skamil           "Detect SIGTRAP TRAP_EXEC from "				\
54311.97Skamil           "child%s%s", masked ? " with masked signal" : "",		\
54321.97Skamil           masked ? " with ignored signal" : "");			\
54331.97Skamil}									\
54341.97Skamil									\
54351.97SkamilATF_TC_BODY(test, tc)							\
54361.97Skamil{									\
54371.97Skamil									\
54381.97Skamil       traceme_exec(masked, ignored);					\
54391.97Skamil}
54401.97Skamil
54411.97SkamilTRACEME_EXEC(traceme_exec, false, false)
54421.97SkamilTRACEME_EXEC(traceme_signalmasked_exec, true, false)
54431.97SkamilTRACEME_EXEC(traceme_signalignored_exec, false, true)
54441.97Skamil
54451.82Skamil/// ----------------------------------------------------------------------------
54461.82Skamil
54471.83Skamilstatic volatile int done;
54481.1Skamil
54491.83Skamilstatic void *
54501.83Skamiltrace_threads_cb(void *arg __unused)
54511.1Skamil{
54521.1Skamil
54531.83Skamil	done++;
54541.83Skamil
54551.83Skamil	while (done < 3)
54561.83Skamil		continue;
54571.83Skamil
54581.83Skamil	return NULL;
54591.1Skamil}
54601.1Skamil
54611.83Skamilstatic void
54621.83Skamiltrace_threads(bool trace_create, bool trace_exit)
54631.1Skamil{
54641.1Skamil	const int sigval = SIGSTOP;
54651.1Skamil	pid_t child, wpid;
54661.1Skamil#if defined(TWAIT_HAVE_STATUS)
54671.1Skamil	int status;
54681.1Skamil#endif
54691.1Skamil	ptrace_state_t state;
54701.1Skamil	const int slen = sizeof(state);
54711.1Skamil	ptrace_event_t event;
54721.1Skamil	const int elen = sizeof(event);
54731.83Skamil	struct ptrace_siginfo info;
54741.83Skamil
54751.83Skamil	pthread_t t[3];
54761.83Skamil	int rv;
54771.83Skamil	size_t n;
54781.1Skamil	lwpid_t lid;
54791.83Skamil
54801.83Skamil	/* Track created and exited threads */
54811.83Skamil	bool traced_lwps[__arraycount(t)];
54821.83Skamil
54831.128Skamil#if !TEST_LWP_ENABLED
54841.120Skamil	if (trace_create || trace_exit)
54851.119Skamil		atf_tc_skip("PR kern/51995");
54861.128Skamil#endif
54871.1Skamil
54881.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
54891.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
54901.1Skamil	if (child == 0) {
54911.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
54921.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
54931.1Skamil
54941.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
54951.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
54961.1Skamil
54971.83Skamil		for (n = 0; n < __arraycount(t); n++) {
54981.83Skamil			rv = pthread_create(&t[n], NULL, trace_threads_cb,
54991.83Skamil			    NULL);
55001.83Skamil			FORKEE_ASSERT(rv == 0);
55011.83Skamil		}
55021.1Skamil
55031.83Skamil		for (n = 0; n < __arraycount(t); n++) {
55041.83Skamil			rv = pthread_join(t[n], NULL);
55051.83Skamil			FORKEE_ASSERT(rv == 0);
55061.83Skamil		}
55071.1Skamil
55081.83Skamil		/*
55091.83Skamil		 * There is race between _exit() and pthread_join() detaching
55101.83Skamil		 * a thread. For simplicity kill the process after detecting
55111.83Skamil		 * LWP events.
55121.83Skamil		 */
55131.83Skamil		while (true)
55141.83Skamil			continue;
55151.1Skamil
55161.83Skamil		FORKEE_ASSERT(0 && "Not reached");
55171.1Skamil	}
55181.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
55191.1Skamil
55201.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
55211.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
55221.1Skamil
55231.1Skamil	validate_status_stopped(status, sigval);
55241.1Skamil
55251.83Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
55261.83Skamil	SYSCALL_REQUIRE(
55271.83Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
55281.1Skamil
55291.83Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
55301.83Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
55311.83Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
55321.83Skamil	    info.psi_siginfo.si_errno);
55331.1Skamil
55341.83Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
55351.83Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
55361.1Skamil
55371.83Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
55381.83Skamil	memset(&event, 0, sizeof(event));
55391.83Skamil	if (trace_create)
55401.83Skamil		event.pe_set_event |= PTRACE_LWP_CREATE;
55411.83Skamil	if (trace_exit)
55421.83Skamil		event.pe_set_event |= PTRACE_LWP_EXIT;
55431.83Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
55441.1Skamil
55451.13Schristos	DPRINTF("Before resuming the child process where it left off and "
55461.1Skamil	    "without signal to be sent\n");
55471.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
55481.1Skamil
55491.83Skamil	memset(traced_lwps, 0, sizeof(traced_lwps));
55501.1Skamil
55511.83Skamil	for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
55521.83Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
55531.83Skamil		    "SIGTRAP\n", TWAIT_FNAME);
55541.83Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
55551.83Skamil		    child);
55561.1Skamil
55571.83Skamil		validate_status_stopped(status, SIGTRAP);
55581.1Skamil
55591.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
55601.83Skamil		    "child\n");
55611.83Skamil		SYSCALL_REQUIRE(
55621.83Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
55631.1Skamil
55641.83Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
55651.83Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
55661.83Skamil		    "si_errno=%#x\n",
55671.83Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
55681.83Skamil		    info.psi_siginfo.si_errno);
55691.1Skamil
55701.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
55711.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
55721.1Skamil
55731.83Skamil		SYSCALL_REQUIRE(
55741.83Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
55751.1Skamil
55761.83Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
55771.83Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
55781.1Skamil
55791.83Skamil		lid = state.pe_lwp;
55801.83Skamil		DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
55811.1Skamil
55821.83Skamil		traced_lwps[lid - 1] = true;
55831.1Skamil
55841.83Skamil		DPRINTF("Before resuming the child process where it left off "
55851.83Skamil		    "and without signal to be sent\n");
55861.83Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
55871.83Skamil	}
55881.1Skamil
55891.83Skamil	for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
55901.83Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
55911.83Skamil		    "SIGTRAP\n", TWAIT_FNAME);
55921.83Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
55931.83Skamil		    child);
55941.1Skamil
55951.83Skamil		validate_status_stopped(status, SIGTRAP);
55961.1Skamil
55971.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
55981.83Skamil		    "child\n");
55991.83Skamil		SYSCALL_REQUIRE(
56001.83Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
56011.1Skamil
56021.83Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
56031.83Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
56041.83Skamil		    "si_errno=%#x\n",
56051.83Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
56061.83Skamil		    info.psi_siginfo.si_errno);
56071.1Skamil
56081.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
56091.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
56101.1Skamil
56111.83Skamil		SYSCALL_REQUIRE(
56121.83Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
56131.1Skamil
56141.83Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
56151.83Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
56161.1Skamil
56171.83Skamil		lid = state.pe_lwp;
56181.83Skamil		DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
56191.1Skamil
56201.83Skamil		if (trace_create) {
56211.83Skamil			ATF_REQUIRE(traced_lwps[lid - 1] == true);
56221.83Skamil			traced_lwps[lid - 1] = false;
56231.83Skamil		}
56241.1Skamil
56251.83Skamil		DPRINTF("Before resuming the child process where it left off "
56261.83Skamil		    "and without signal to be sent\n");
56271.83Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
56281.83Skamil	}
56291.1Skamil
56301.83Skamil	kill(child, SIGKILL);
56311.1Skamil
56321.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
56331.1Skamil	    TWAIT_FNAME);
56341.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
56351.1Skamil
56361.83Skamil	validate_status_signaled(status, SIGKILL, 0);
56371.1Skamil
56381.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
56391.1Skamil	    TWAIT_FNAME);
56401.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
56411.1Skamil}
56421.1Skamil
56431.83Skamil#define TRACE_THREADS(test, trace_create, trace_exit)			\
56441.83SkamilATF_TC(test);								\
56451.83SkamilATF_TC_HEAD(test, tc)							\
56461.83Skamil{									\
56471.83Skamil        atf_tc_set_md_var(tc, "descr",					\
56481.83Skamil            "Verify spawning threads with%s tracing LWP create and"	\
56491.83Skamil	    "with%s tracing LWP exit", trace_create ? "" : "out",	\
56501.83Skamil	    trace_exit ? "" : "out");					\
56511.83Skamil}									\
56521.83Skamil									\
56531.83SkamilATF_TC_BODY(test, tc)							\
56541.83Skamil{									\
56551.83Skamil									\
56561.83Skamil        trace_threads(trace_create, trace_exit);			\
56571.83Skamil}
56581.83Skamil
56591.119SkamilTRACE_THREADS(trace_thread_nolwpevents, false, false)
56601.119SkamilTRACE_THREADS(trace_thread_lwpexit, false, true)
56611.119SkamilTRACE_THREADS(trace_thread_lwpcreate, true, false)
56621.119SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true)
56631.83Skamil
56641.83Skamil/// ----------------------------------------------------------------------------
56651.83Skamil
56661.84SkamilATF_TC(signal_mask_unrelated);
56671.84SkamilATF_TC_HEAD(signal_mask_unrelated, tc)
56681.1Skamil{
56691.1Skamil	atf_tc_set_md_var(tc, "descr",
56701.1Skamil	    "Verify that masking single unrelated signal does not stop tracer "
56711.1Skamil	    "from catching other signals");
56721.1Skamil}
56731.1Skamil
56741.84SkamilATF_TC_BODY(signal_mask_unrelated, tc)
56751.1Skamil{
56761.1Skamil	const int exitval = 5;
56771.1Skamil	const int sigval = SIGSTOP;
56781.1Skamil	const int sigmasked = SIGTRAP;
56791.1Skamil	const int signotmasked = SIGINT;
56801.1Skamil	pid_t child, wpid;
56811.1Skamil#if defined(TWAIT_HAVE_STATUS)
56821.1Skamil	int status;
56831.1Skamil#endif
56841.1Skamil	sigset_t intmask;
56851.1Skamil
56861.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
56871.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
56881.1Skamil	if (child == 0) {
56891.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
56901.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
56911.1Skamil
56921.1Skamil		sigemptyset(&intmask);
56931.1Skamil		sigaddset(&intmask, sigmasked);
56941.1Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
56951.1Skamil
56961.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
56971.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
56981.1Skamil
56991.13Schristos		DPRINTF("Before raising %s from child\n",
57001.1Skamil		    strsignal(signotmasked));
57011.1Skamil		FORKEE_ASSERT(raise(signotmasked) == 0);
57021.1Skamil
57031.13Schristos		DPRINTF("Before exiting of the child process\n");
57041.1Skamil		_exit(exitval);
57051.1Skamil	}
57061.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
57071.1Skamil
57081.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
57091.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
57101.1Skamil
57111.1Skamil	validate_status_stopped(status, sigval);
57121.1Skamil
57131.13Schristos	DPRINTF("Before resuming the child process where it left off and "
57141.1Skamil	    "without signal to be sent\n");
57151.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
57161.1Skamil
57171.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
57181.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
57191.1Skamil
57201.1Skamil	validate_status_stopped(status, signotmasked);
57211.1Skamil
57221.13Schristos	DPRINTF("Before resuming the child process where it left off and "
57231.1Skamil	    "without signal to be sent\n");
57241.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
57251.1Skamil
57261.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
57271.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
57281.1Skamil
57291.1Skamil	validate_status_exited(status, exitval);
57301.1Skamil
57311.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
57321.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
57331.1Skamil}
57341.1Skamil
57351.84Skamil/// ----------------------------------------------------------------------------
57361.84Skamil
57371.1Skamil#if defined(TWAIT_HAVE_PID)
57381.99Skamilstatic void
57391.126Skamilfork2_body(const char *fn, bool masked, bool ignored)
57401.1Skamil{
57411.1Skamil	const int exitval = 5;
57421.126Skamil	const int exitval2 = 0; /* Match exit status from /bin/echo */
57431.1Skamil	const int sigval = SIGSTOP;
57441.99Skamil	pid_t child, child2 = 0, wpid;
57451.1Skamil#if defined(TWAIT_HAVE_STATUS)
57461.1Skamil	int status;
57471.1Skamil#endif
57481.1Skamil	ptrace_state_t state;
57491.1Skamil	const int slen = sizeof(state);
57501.1Skamil	ptrace_event_t event;
57511.1Skamil	const int elen = sizeof(event);
57521.99Skamil	struct sigaction sa;
57531.99Skamil	struct ptrace_siginfo info;
57541.99Skamil	sigset_t intmask;
57551.99Skamil	struct kinfo_proc2 kp;
57561.99Skamil	size_t len = sizeof(kp);
57571.99Skamil
57581.99Skamil	int name[6];
57591.99Skamil	const size_t namelen = __arraycount(name);
57601.99Skamil	ki_sigset_t kp_sigmask;
57611.99Skamil	ki_sigset_t kp_sigignore;
57621.1Skamil
57631.126Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
57641.14Schristos
57651.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
57661.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
57671.1Skamil	if (child == 0) {
57681.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
57691.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
57701.1Skamil
57711.99Skamil		if (masked) {
57721.99Skamil			sigemptyset(&intmask);
57731.99Skamil			sigaddset(&intmask, SIGTRAP);
57741.99Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
57751.99Skamil		}
57761.99Skamil
57771.99Skamil		if (ignored) {
57781.99Skamil			memset(&sa, 0, sizeof(sa));
57791.99Skamil			sa.sa_handler = SIG_IGN;
57801.99Skamil			sigemptyset(&sa.sa_mask);
57811.99Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
57821.99Skamil		}
57831.1Skamil
57841.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
57851.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
57861.1Skamil
57871.126Skamil		if (strcmp(fn, "spawn") == 0) {
57881.126Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
57891.126Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
57901.126Skamil		} else  {
57911.126Skamil			if (strcmp(fn, "fork") == 0) {
57921.126Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
57931.126Skamil			} else {
57941.126Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
57951.126Skamil			}
57961.126Skamil			if (child2 == 0)
57971.126Skamil				_exit(exitval2);
57981.126Skamil		}
57991.1Skamil
58001.1Skamil		FORKEE_REQUIRE_SUCCESS
58011.99Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
58021.1Skamil
58031.1Skamil		forkee_status_exited(status, exitval2);
58041.1Skamil
58051.13Schristos		DPRINTF("Before exiting of the child process\n");
58061.1Skamil		_exit(exitval);
58071.1Skamil	}
58081.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
58091.1Skamil
58101.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
58111.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
58121.1Skamil
58131.1Skamil	validate_status_stopped(status, sigval);
58141.1Skamil
58151.99Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
58161.99Skamil	SYSCALL_REQUIRE(
58171.99Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
58181.99Skamil
58191.99Skamil	DPRINTF("Before checking siginfo_t\n");
58201.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
58211.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
58221.1Skamil
58231.99Skamil	name[0] = CTL_KERN,
58241.99Skamil	name[1] = KERN_PROC2,
58251.99Skamil	name[2] = KERN_PROC_PID;
58261.99Skamil	name[3] = child;
58271.99Skamil	name[4] = sizeof(kp);
58281.99Skamil	name[5] = 1;
58291.1Skamil
58301.99Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
58311.1Skamil
58321.99Skamil	if (masked)
58331.99Skamil		kp_sigmask = kp.p_sigmask;
58341.1Skamil
58351.99Skamil	if (ignored)
58361.99Skamil		kp_sigignore = kp.p_sigignore;
58371.1Skamil
58381.126Skamil	DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
58391.126Skamil	    strcmp(fn, "spawn") == 0 ? "|PTRACE_POSIX_SPAWN" : "",
58401.126Skamil	    strcmp(fn, "fork") == 0 ? "|PTRACE_FORK" : "",
58411.126Skamil	    strcmp(fn, "vfork") == 0 ? "|PTRACE_VFORK" : "",
58421.126Skamil	    strcmp(fn, "vforkdone") == 0 ? "|PTRACE_VFORK_DONE" : "", child);
58431.99Skamil	event.pe_set_event = 0;
58441.126Skamil	if (strcmp(fn, "spawn") == 0)
58451.126Skamil		event.pe_set_event |= PTRACE_POSIX_SPAWN;
58461.126Skamil	if (strcmp(fn, "fork") == 0)
58471.99Skamil		event.pe_set_event |= PTRACE_FORK;
58481.126Skamil	if (strcmp(fn, "vfork") == 0)
58491.99Skamil		event.pe_set_event |= PTRACE_VFORK;
58501.126Skamil	if (strcmp(fn, "vforkdone") == 0)
58511.99Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
58521.99Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
58531.1Skamil
58541.99Skamil	DPRINTF("Before resuming the child process where it left off and "
58551.99Skamil	    "without signal to be sent\n");
58561.99Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
58571.1Skamil
58581.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
58591.126Skamil	    strcmp(fn, "vfork") == 0) {
58601.99Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
58611.99Skamil		    child);
58621.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
58631.99Skamil		    child);
58641.1Skamil
58651.99Skamil		validate_status_stopped(status, SIGTRAP);
58661.1Skamil
58671.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
58681.1Skamil
58691.99Skamil		if (masked) {
58701.99Skamil			DPRINTF("kp_sigmask="
58711.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
58721.99Skamil			    PRIx32 "\n",
58731.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
58741.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
58751.1Skamil
58761.99Skamil			DPRINTF("kp.p_sigmask="
58771.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
58781.99Skamil			    PRIx32 "\n",
58791.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
58801.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
58811.1Skamil
58821.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
58831.99Skamil			    sizeof(kp_sigmask)));
58841.99Skamil		}
58851.1Skamil
58861.99Skamil		if (ignored) {
58871.99Skamil			DPRINTF("kp_sigignore="
58881.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
58891.99Skamil			    PRIx32 "\n",
58901.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
58911.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
58921.1Skamil
58931.99Skamil			DPRINTF("kp.p_sigignore="
58941.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
58951.99Skamil			    PRIx32 "\n",
58961.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
58971.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
58981.1Skamil
58991.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
59001.99Skamil			    sizeof(kp_sigignore)));
59011.99Skamil		}
59021.1Skamil
59031.99Skamil		SYSCALL_REQUIRE(
59041.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
59051.126Skamil		if (strcmp(fn, "spawn") == 0) {
59061.126Skamil			ATF_REQUIRE_EQ(
59071.126Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
59081.126Skamil			       PTRACE_POSIX_SPAWN);
59091.126Skamil		}
59101.126Skamil		if (strcmp(fn, "fork") == 0) {
59111.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
59121.99Skamil			       PTRACE_FORK);
59131.99Skamil		}
59141.126Skamil		if (strcmp(fn, "vfork") == 0) {
59151.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
59161.99Skamil			       PTRACE_VFORK);
59171.99Skamil		}
59181.1Skamil
59191.99Skamil		child2 = state.pe_other_pid;
59201.99Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
59211.1Skamil
59221.99Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
59231.99Skamil		    "%d\n", TWAIT_FNAME, child2, child);
59241.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
59251.99Skamil		    child2);
59261.1Skamil
59271.99Skamil		validate_status_stopped(status, SIGTRAP);
59281.1Skamil
59291.99Skamil		name[3] = child2;
59301.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
59311.1Skamil
59321.99Skamil		if (masked) {
59331.99Skamil			DPRINTF("kp_sigmask="
59341.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
59351.99Skamil			    PRIx32 "\n",
59361.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
59371.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
59381.1Skamil
59391.99Skamil			DPRINTF("kp.p_sigmask="
59401.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
59411.99Skamil			    PRIx32 "\n",
59421.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
59431.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
59441.14Schristos
59451.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
59461.99Skamil			    sizeof(kp_sigmask)));
59471.99Skamil		}
59481.1Skamil
59491.99Skamil		if (ignored) {
59501.99Skamil			DPRINTF("kp_sigignore="
59511.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
59521.99Skamil			    PRIx32 "\n",
59531.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
59541.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
59551.1Skamil
59561.99Skamil			DPRINTF("kp.p_sigignore="
59571.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
59581.99Skamil			    PRIx32 "\n",
59591.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
59601.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
59611.1Skamil
59621.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
59631.99Skamil			    sizeof(kp_sigignore)));
59641.99Skamil		}
59651.1Skamil
59661.99Skamil		SYSCALL_REQUIRE(
59671.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
59681.126Skamil		if (strcmp(fn, "spawn") == 0) {
59691.126Skamil			ATF_REQUIRE_EQ(
59701.126Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
59711.126Skamil			       PTRACE_POSIX_SPAWN);
59721.126Skamil		}
59731.126Skamil		if (strcmp(fn, "fork") == 0) {
59741.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
59751.99Skamil			       PTRACE_FORK);
59761.99Skamil		}
59771.126Skamil		if (strcmp(fn, "vfork") == 0) {
59781.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
59791.99Skamil			       PTRACE_VFORK);
59801.99Skamil		}
59811.1Skamil
59821.99Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
59831.1Skamil
59841.99Skamil		DPRINTF("Before resuming the forkee process where it left off "
59851.99Skamil		    "and without signal to be sent\n");
59861.99Skamil		SYSCALL_REQUIRE(
59871.99Skamil		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
59881.1Skamil
59891.99Skamil		DPRINTF("Before resuming the child process where it left off "
59901.99Skamil		    "and without signal to be sent\n");
59911.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
59921.1Skamil	}
59931.1Skamil
59941.126Skamil	if (strcmp(fn, "vforkdone") == 0) {
59951.99Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
59961.99Skamil		    child);
59971.99Skamil		TWAIT_REQUIRE_SUCCESS(
59981.99Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
59991.1Skamil
60001.99Skamil		validate_status_stopped(status, SIGTRAP);
60011.1Skamil
60021.99Skamil		name[3] = child;
60031.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
60041.1Skamil
60051.102Skamil		/*
60061.102Skamil		 * SIGCHLD is now pending in the signal queue and
60071.102Skamil		 * the kernel presents it to userland as a masked signal.
60081.102Skamil		 */
60091.102Skamil		sigdelset((sigset_t *)&kp.p_sigmask, SIGCHLD);
60101.102Skamil
60111.99Skamil		if (masked) {
60121.99Skamil			DPRINTF("kp_sigmask="
60131.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
60141.99Skamil			    PRIx32 "\n",
60151.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
60161.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
60171.1Skamil
60181.99Skamil			DPRINTF("kp.p_sigmask="
60191.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
60201.99Skamil			    PRIx32 "\n",
60211.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
60221.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
60231.1Skamil
60241.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
60251.99Skamil			    sizeof(kp_sigmask)));
60261.99Skamil		}
60271.1Skamil
60281.99Skamil		if (ignored) {
60291.99Skamil			DPRINTF("kp_sigignore="
60301.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
60311.99Skamil			    PRIx32 "\n",
60321.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
60331.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
60341.1Skamil
60351.99Skamil			DPRINTF("kp.p_sigignore="
60361.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
60371.99Skamil			    PRIx32 "\n",
60381.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
60391.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
60401.1Skamil
60411.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
60421.99Skamil			    sizeof(kp_sigignore)));
60431.99Skamil		}
60441.1Skamil
60451.99Skamil		SYSCALL_REQUIRE(
60461.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
60471.99Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
60481.1Skamil
60491.99Skamil		child2 = state.pe_other_pid;
60501.99Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
60511.99Skamil		    child2);
60521.1Skamil
60531.99Skamil		DPRINTF("Before resuming the child process where it left off "
60541.99Skamil		    "and without signal to be sent\n");
60551.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
60561.99Skamil	}
60571.1Skamil
60581.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
60591.126Skamil	    strcmp(fn, "vfork") == 0) {
60601.99Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
60611.99Skamil		    "\n", TWAIT_FNAME);
60621.99Skamil		TWAIT_REQUIRE_SUCCESS(
60631.99Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
60641.1Skamil
60651.99Skamil		validate_status_exited(status, exitval2);
60661.1Skamil
60671.99Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
60681.99Skamil		    "process\n", TWAIT_FNAME);
60691.99Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
60701.99Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
60711.99Skamil	}
60721.1Skamil
60731.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
60741.1Skamil	    "SIGCHLD\n", TWAIT_FNAME);
60751.57Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
60761.1Skamil
60771.1Skamil	validate_status_stopped(status, SIGCHLD);
60781.1Skamil
60791.57Skamil	DPRINTF("Before resuming the child process where it left off and "
60801.1Skamil	    "without signal to be sent\n");
60811.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
60821.1Skamil
60831.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
60841.1Skamil	    TWAIT_FNAME);
60851.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
60861.1Skamil
60871.1Skamil	validate_status_exited(status, exitval);
60881.1Skamil
60891.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
60901.57Skamil	    TWAIT_FNAME);
60911.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
60921.1Skamil}
60931.1Skamil
60941.126Skamil#define FORK2_TEST(name,fn,masked,ignored)				\
60951.99SkamilATF_TC(name);								\
60961.99SkamilATF_TC_HEAD(name, tc)							\
60971.99Skamil{									\
60981.126Skamil	atf_tc_set_md_var(tc, "descr", "Verify that " fn " is caught "	\
60991.99Skamil	    "regardless of signal %s%s", 				\
61001.99Skamil	    masked ? "masked" : "", ignored ? "ignored" : "");		\
61011.99Skamil}									\
61021.99Skamil									\
61031.99SkamilATF_TC_BODY(name, tc)							\
61041.99Skamil{									\
61051.99Skamil									\
61061.126Skamil	fork2_body(fn, masked, ignored);				\
61071.1Skamil}
61081.1Skamil
61091.126SkamilFORK2_TEST(posix_spawn_singalmasked, "spawn", true, false)
61101.126SkamilFORK2_TEST(posix_spawn_singalignored, "spawn", false, true)
61111.126SkamilFORK2_TEST(fork_singalmasked, "fork", true, false)
61121.126SkamilFORK2_TEST(fork_singalignored, "fork", false, true)
61131.110Skamil#if TEST_VFORK_ENABLED
61141.126SkamilFORK2_TEST(vfork_singalmasked, "vfork", true, false)
61151.126SkamilFORK2_TEST(vfork_singalignored, "vfork", false, true)
61161.126SkamilFORK2_TEST(vforkdone_singalmasked, "vforkdone", true, false)
61171.126SkamilFORK2_TEST(vforkdone_singalignored, "vforkdone", false, true)
61181.1Skamil#endif
61191.110Skamil#endif
61201.1Skamil
61211.99Skamil/// ----------------------------------------------------------------------------
61221.1Skamil
61231.83Skamilvolatile lwpid_t the_lwp_id = 0;
61241.83Skamil
61251.83Skamilstatic void
61261.83Skamillwp_main_func(void *arg)
61271.83Skamil{
61281.83Skamil	the_lwp_id = _lwp_self();
61291.83Skamil	_lwp_exit();
61301.83Skamil}
61311.83Skamil
61321.1SkamilATF_TC(signal9);
61331.1SkamilATF_TC_HEAD(signal9, tc)
61341.1Skamil{
61351.1Skamil	atf_tc_set_md_var(tc, "descr",
61361.1Skamil	    "Verify that masking SIGTRAP in tracee does not stop tracer from "
61371.1Skamil	    "catching PTRACE_LWP_CREATE breakpoint");
61381.1Skamil}
61391.1Skamil
61401.1SkamilATF_TC_BODY(signal9, tc)
61411.1Skamil{
61421.1Skamil	const int exitval = 5;
61431.1Skamil	const int sigval = SIGSTOP;
61441.1Skamil	const int sigmasked = SIGTRAP;
61451.1Skamil	pid_t child, wpid;
61461.1Skamil#if defined(TWAIT_HAVE_STATUS)
61471.1Skamil	int status;
61481.1Skamil#endif
61491.1Skamil	sigset_t intmask;
61501.1Skamil	ptrace_state_t state;
61511.1Skamil	const int slen = sizeof(state);
61521.1Skamil	ptrace_event_t event;
61531.1Skamil	const int elen = sizeof(event);
61541.1Skamil	ucontext_t uc;
61551.1Skamil	lwpid_t lid;
61561.1Skamil	static const size_t ssize = 16*1024;
61571.1Skamil	void *stack;
61581.1Skamil
61591.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
61601.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
61611.1Skamil	if (child == 0) {
61621.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
61631.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
61641.1Skamil
61651.1Skamil		sigemptyset(&intmask);
61661.1Skamil		sigaddset(&intmask, sigmasked);
61671.1Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
61681.1Skamil
61691.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
61701.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
61711.1Skamil
61721.13Schristos		DPRINTF("Before allocating memory for stack in child\n");
61731.1Skamil		FORKEE_ASSERT((stack = malloc(ssize)) != NULL);
61741.1Skamil
61751.13Schristos		DPRINTF("Before making context for new lwp in child\n");
61761.1Skamil		_lwp_makecontext(&uc, lwp_main_func, NULL, NULL, stack, ssize);
61771.1Skamil
61781.13Schristos		DPRINTF("Before creating new in child\n");
61791.1Skamil		FORKEE_ASSERT(_lwp_create(&uc, 0, &lid) == 0);
61801.1Skamil
61811.13Schristos		DPRINTF("Before waiting for lwp %d to exit\n", lid);
61821.1Skamil		FORKEE_ASSERT(_lwp_wait(lid, NULL) == 0);
61831.1Skamil
61841.13Schristos		DPRINTF("Before verifying that reported %d and running lid %d "
61851.1Skamil		    "are the same\n", lid, the_lwp_id);
61861.1Skamil		FORKEE_ASSERT_EQ(lid, the_lwp_id);
61871.1Skamil
61881.13Schristos		DPRINTF("Before exiting of the child process\n");
61891.1Skamil		_exit(exitval);
61901.1Skamil	}
61911.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
61921.1Skamil
61931.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
61941.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
61951.1Skamil
61961.1Skamil	validate_status_stopped(status, sigval);
61971.1Skamil
61981.13Schristos	DPRINTF("Set empty EVENT_MASK for the child %d\n", child);
61991.1Skamil	event.pe_set_event = PTRACE_LWP_CREATE;
62001.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
62011.1Skamil
62021.13Schristos	DPRINTF("Before resuming the child process where it left off and "
62031.1Skamil	    "without signal to be sent\n");
62041.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
62051.1Skamil
62061.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
62071.1Skamil	    "SIGTRAP\n", TWAIT_FNAME);
62081.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
62091.1Skamil
62101.1Skamil	validate_status_stopped(status, sigmasked);
62111.1Skamil
62121.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
62131.1Skamil
62141.1Skamil	ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_LWP_CREATE);
62151.1Skamil
62161.1Skamil	lid = state.pe_lwp;
62171.13Schristos	DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
62181.1Skamil
62191.13Schristos	DPRINTF("Before resuming the child process where it left off and "
62201.1Skamil	    "without signal to be sent\n");
62211.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
62221.1Skamil
62231.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
62241.1Skamil	    TWAIT_FNAME);
62251.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
62261.1Skamil
62271.1Skamil	validate_status_exited(status, exitval);
62281.1Skamil
62291.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
62301.1Skamil	    TWAIT_FNAME);
62311.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
62321.1Skamil}
62331.1Skamil
62341.1SkamilATF_TC(signal10);
62351.1SkamilATF_TC_HEAD(signal10, tc)
62361.1Skamil{
62371.1Skamil	atf_tc_set_md_var(tc, "descr",
62381.1Skamil	    "Verify that masking SIGTRAP in tracee does not stop tracer from "
62391.1Skamil	    "catching PTRACE_LWP_EXIT breakpoint");
62401.1Skamil}
62411.1Skamil
62421.1SkamilATF_TC_BODY(signal10, tc)
62431.1Skamil{
62441.1Skamil	const int exitval = 5;
62451.1Skamil	const int sigval = SIGSTOP;
62461.1Skamil	const int sigmasked = SIGTRAP;
62471.1Skamil	pid_t child, wpid;
62481.1Skamil#if defined(TWAIT_HAVE_STATUS)
62491.1Skamil	int status;
62501.1Skamil#endif
62511.1Skamil	sigset_t intmask;
62521.1Skamil	ptrace_state_t state;
62531.1Skamil	const int slen = sizeof(state);
62541.1Skamil	ptrace_event_t event;
62551.1Skamil	const int elen = sizeof(event);
62561.1Skamil	ucontext_t uc;
62571.1Skamil	lwpid_t lid;
62581.1Skamil	static const size_t ssize = 16*1024;
62591.1Skamil	void *stack;
62601.1Skamil
62611.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
62621.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
62631.1Skamil	if (child == 0) {
62641.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
62651.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
62661.1Skamil
62671.1Skamil		sigemptyset(&intmask);
62681.1Skamil		sigaddset(&intmask, sigmasked);
62691.1Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
62701.1Skamil
62711.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
62721.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
62731.1Skamil
62741.13Schristos		DPRINTF("Before allocating memory for stack in child\n");
62751.1Skamil		FORKEE_ASSERT((stack = malloc(ssize)) != NULL);
62761.1Skamil
62771.13Schristos		DPRINTF("Before making context for new lwp in child\n");
62781.1Skamil		_lwp_makecontext(&uc, lwp_main_func, NULL, NULL, stack, ssize);
62791.1Skamil
62801.13Schristos		DPRINTF("Before creating new in child\n");
62811.1Skamil		FORKEE_ASSERT(_lwp_create(&uc, 0, &lid) == 0);
62821.1Skamil
62831.13Schristos		DPRINTF("Before waiting for lwp %d to exit\n", lid);
62841.1Skamil		FORKEE_ASSERT(_lwp_wait(lid, NULL) == 0);
62851.1Skamil
62861.13Schristos		DPRINTF("Before verifying that reported %d and running lid %d "
62871.1Skamil		    "are the same\n", lid, the_lwp_id);
62881.1Skamil		FORKEE_ASSERT_EQ(lid, the_lwp_id);
62891.1Skamil
62901.13Schristos		DPRINTF("Before exiting of the child process\n");
62911.1Skamil		_exit(exitval);
62921.1Skamil	}
62931.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
62941.1Skamil
62951.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
62961.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
62971.1Skamil
62981.1Skamil	validate_status_stopped(status, sigval);
62991.1Skamil
63001.13Schristos	DPRINTF("Set empty EVENT_MASK for the child %d\n", child);
63011.1Skamil	event.pe_set_event = PTRACE_LWP_EXIT;
63021.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
63031.1Skamil
63041.13Schristos	DPRINTF("Before resuming the child process where it left off and "
63051.1Skamil	    "without signal to be sent\n");
63061.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
63071.1Skamil
63081.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
63091.1Skamil	    "SIGTRAP\n", TWAIT_FNAME);
63101.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
63111.1Skamil
63121.1Skamil	validate_status_stopped(status, sigmasked);
63131.1Skamil
63141.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
63151.1Skamil
63161.1Skamil	ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_LWP_EXIT);
63171.1Skamil
63181.1Skamil	lid = state.pe_lwp;
63191.13Schristos	DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
63201.1Skamil
63211.13Schristos	DPRINTF("Before resuming the child process where it left off and "
63221.1Skamil	    "without signal to be sent\n");
63231.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
63241.1Skamil
63251.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
63261.1Skamil	    TWAIT_FNAME);
63271.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
63281.1Skamil
63291.1Skamil	validate_status_exited(status, exitval);
63301.1Skamil
63311.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
63321.1Skamil	    TWAIT_FNAME);
63331.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
63341.1Skamil}
63351.1Skamil
63361.1Skamilstatic void
63371.1Skamillwp_main_stop(void *arg)
63381.1Skamil{
63391.1Skamil	the_lwp_id = _lwp_self();
63401.1Skamil
63411.1Skamil	raise(SIGTRAP);
63421.1Skamil
63431.1Skamil	_lwp_exit();
63441.1Skamil}
63451.1Skamil
63461.1SkamilATF_TC(suspend1);
63471.1SkamilATF_TC_HEAD(suspend1, tc)
63481.1Skamil{
63491.1Skamil	atf_tc_set_md_var(tc, "descr",
63501.1Skamil	    "Verify that a thread can be suspended by a debugger and later "
63511.1Skamil	    "resumed by a tracee");
63521.1Skamil}
63531.1Skamil
63541.1SkamilATF_TC_BODY(suspend1, tc)
63551.1Skamil{
63561.1Skamil	const int exitval = 5;
63571.1Skamil	const int sigval = SIGSTOP;
63581.1Skamil	pid_t child, wpid;
63591.1Skamil#if defined(TWAIT_HAVE_STATUS)
63601.1Skamil	int status;
63611.1Skamil#endif
63621.1Skamil	ucontext_t uc;
63631.1Skamil	lwpid_t lid;
63641.1Skamil	static const size_t ssize = 16*1024;
63651.1Skamil	void *stack;
63661.1Skamil	struct ptrace_lwpinfo pl;
63671.1Skamil	struct ptrace_siginfo psi;
63681.1Skamil	volatile int go = 0;
63691.1Skamil
63701.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
63711.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
63721.1Skamil	if (child == 0) {
63731.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
63741.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
63751.1Skamil
63761.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
63771.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
63781.1Skamil
63791.13Schristos		DPRINTF("Before allocating memory for stack in child\n");
63801.1Skamil		FORKEE_ASSERT((stack = malloc(ssize)) != NULL);
63811.1Skamil
63821.13Schristos		DPRINTF("Before making context for new lwp in child\n");
63831.1Skamil		_lwp_makecontext(&uc, lwp_main_stop, NULL, NULL, stack, ssize);
63841.1Skamil
63851.13Schristos		DPRINTF("Before creating new in child\n");
63861.1Skamil		FORKEE_ASSERT(_lwp_create(&uc, 0, &lid) == 0);
63871.1Skamil
63881.1Skamil		while (go == 0)
63891.1Skamil			continue;
63901.1Skamil
63911.1Skamil		raise(SIGINT);
63921.1Skamil
63931.1Skamil		FORKEE_ASSERT(_lwp_continue(lid) == 0);
63941.1Skamil
63951.13Schristos		DPRINTF("Before waiting for lwp %d to exit\n", lid);
63961.1Skamil		FORKEE_ASSERT(_lwp_wait(lid, NULL) == 0);
63971.1Skamil
63981.13Schristos		DPRINTF("Before verifying that reported %d and running lid %d "
63991.1Skamil		    "are the same\n", lid, the_lwp_id);
64001.1Skamil		FORKEE_ASSERT_EQ(lid, the_lwp_id);
64011.1Skamil
64021.13Schristos		DPRINTF("Before exiting of the child process\n");
64031.1Skamil		_exit(exitval);
64041.1Skamil	}
64051.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
64061.1Skamil
64071.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
64081.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64091.1Skamil
64101.1Skamil	validate_status_stopped(status, sigval);
64111.1Skamil
64121.13Schristos	DPRINTF("Before resuming the child process where it left off and "
64131.1Skamil	    "without signal to be sent\n");
64141.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
64151.1Skamil
64161.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
64171.1Skamil	    "SIGTRAP\n", TWAIT_FNAME);
64181.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64191.1Skamil
64201.1Skamil	validate_status_stopped(status, SIGTRAP);
64211.1Skamil
64221.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
64231.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
64241.1Skamil
64251.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
64261.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
64271.1Skamil
64281.13Schristos        DPRINTF("Write new go to tracee (PID=%d) from tracer (PID=%d)\n",
64291.1Skamil	    child, getpid());
64301.13Schristos	SYSCALL_REQUIRE(ptrace(PT_WRITE_D, child, __UNVOLATILE(&go), 1) != -1);
64311.1Skamil
64321.13Schristos	DPRINTF("Before resuming the child process where it left off and "
64331.1Skamil	    "without signal to be sent\n");
64341.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
64351.1Skamil
64361.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
64371.1Skamil	    "SIGINT\n", TWAIT_FNAME);
64381.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64391.1Skamil
64401.1Skamil	validate_status_stopped(status, SIGINT);
64411.1Skamil
64421.1Skamil	pl.pl_lwpid = 0;
64431.1Skamil
64441.13Schristos	SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &pl, sizeof(pl)) != -1);
64451.1Skamil	while (pl.pl_lwpid != 0) {
64461.1Skamil
64471.13Schristos		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &pl, sizeof(pl)) != -1);
64481.1Skamil		switch (pl.pl_lwpid) {
64491.1Skamil		case 1:
64501.1Skamil			ATF_REQUIRE_EQ(pl.pl_event, PL_EVENT_SIGNAL);
64511.1Skamil			break;
64521.1Skamil		case 2:
64531.1Skamil			ATF_REQUIRE_EQ(pl.pl_event, PL_EVENT_SUSPENDED);
64541.1Skamil			break;
64551.1Skamil		}
64561.1Skamil	}
64571.1Skamil
64581.13Schristos	DPRINTF("Before resuming the child process where it left off and "
64591.1Skamil	    "without signal to be sent\n");
64601.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
64611.1Skamil
64621.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
64631.1Skamil	    TWAIT_FNAME);
64641.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64651.1Skamil
64661.1Skamil	validate_status_exited(status, exitval);
64671.1Skamil
64681.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
64691.1Skamil	    TWAIT_FNAME);
64701.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
64711.1Skamil}
64721.1Skamil
64731.1SkamilATF_TC(suspend2);
64741.1SkamilATF_TC_HEAD(suspend2, tc)
64751.1Skamil{
64761.1Skamil	atf_tc_set_md_var(tc, "descr",
64771.1Skamil	    "Verify that the while the only thread within a process is "
64781.1Skamil	    "suspended, the whole process cannot be unstopped");
64791.1Skamil}
64801.1Skamil
64811.1SkamilATF_TC_BODY(suspend2, tc)
64821.1Skamil{
64831.1Skamil	const int exitval = 5;
64841.1Skamil	const int sigval = SIGSTOP;
64851.1Skamil	pid_t child, wpid;
64861.1Skamil#if defined(TWAIT_HAVE_STATUS)
64871.1Skamil	int status;
64881.1Skamil#endif
64891.1Skamil	struct ptrace_siginfo psi;
64901.1Skamil
64911.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
64921.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
64931.1Skamil	if (child == 0) {
64941.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
64951.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
64961.1Skamil
64971.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
64981.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
64991.1Skamil
65001.13Schristos		DPRINTF("Before exiting of the child process\n");
65011.1Skamil		_exit(exitval);
65021.1Skamil	}
65031.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
65041.1Skamil
65051.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
65061.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
65071.1Skamil
65081.1Skamil	validate_status_stopped(status, sigval);
65091.1Skamil
65101.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
65111.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
65121.1Skamil
65131.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
65141.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
65151.1Skamil
65161.13Schristos	DPRINTF("Before resuming the child process where it left off and "
65171.1Skamil	    "without signal to be sent\n");
65181.1Skamil	ATF_REQUIRE_ERRNO(EDEADLK,
65191.1Skamil	    ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
65201.1Skamil
65211.13Schristos	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
65221.13Schristos	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
65231.1Skamil
65241.13Schristos	DPRINTF("Before resuming the child process where it left off and "
65251.1Skamil	    "without signal to be sent\n");
65261.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
65271.1Skamil
65281.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
65291.1Skamil	    TWAIT_FNAME);
65301.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
65311.1Skamil
65321.1Skamil	validate_status_exited(status, exitval);
65331.1Skamil
65341.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
65351.1Skamil	    TWAIT_FNAME);
65361.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
65371.1Skamil}
65381.1Skamil
65391.1SkamilATF_TC(resume1);
65401.1SkamilATF_TC_HEAD(resume1, tc)
65411.1Skamil{
65421.1Skamil	atf_tc_set_md_var(tc, "descr",
65431.1Skamil	    "Verify that a thread can be suspended by a debugger and later "
65441.1Skamil	    "resumed by the debugger");
65451.1Skamil}
65461.1Skamil
65471.1SkamilATF_TC_BODY(resume1, tc)
65481.1Skamil{
65491.1Skamil	struct msg_fds fds;
65501.1Skamil	const int exitval = 5;
65511.1Skamil	const int sigval = SIGSTOP;
65521.1Skamil	pid_t child, wpid;
65531.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
65541.1Skamil#if defined(TWAIT_HAVE_STATUS)
65551.1Skamil	int status;
65561.1Skamil#endif
65571.1Skamil	ucontext_t uc;
65581.1Skamil	lwpid_t lid;
65591.1Skamil	static const size_t ssize = 16*1024;
65601.1Skamil	void *stack;
65611.1Skamil	struct ptrace_lwpinfo pl;
65621.1Skamil	struct ptrace_siginfo psi;
65631.1Skamil
65641.13Schristos	SYSCALL_REQUIRE(msg_open(&fds) == 0);
65651.1Skamil
65661.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
65671.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
65681.1Skamil	if (child == 0) {
65691.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
65701.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
65711.1Skamil
65721.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
65731.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
65741.1Skamil
65751.13Schristos		DPRINTF("Before allocating memory for stack in child\n");
65761.1Skamil		FORKEE_ASSERT((stack = malloc(ssize)) != NULL);
65771.1Skamil
65781.13Schristos		DPRINTF("Before making context for new lwp in child\n");
65791.1Skamil		_lwp_makecontext(&uc, lwp_main_stop, NULL, NULL, stack, ssize);
65801.1Skamil
65811.13Schristos		DPRINTF("Before creating new in child\n");
65821.1Skamil		FORKEE_ASSERT(_lwp_create(&uc, 0, &lid) == 0);
65831.1Skamil
65841.1Skamil		CHILD_TO_PARENT("Message", fds, msg);
65851.1Skamil
65861.1Skamil		raise(SIGINT);
65871.1Skamil
65881.13Schristos		DPRINTF("Before waiting for lwp %d to exit\n", lid);
65891.1Skamil		FORKEE_ASSERT(_lwp_wait(lid, NULL) == 0);
65901.1Skamil
65911.13Schristos		DPRINTF("Before verifying that reported %d and running lid %d "
65921.1Skamil		    "are the same\n", lid, the_lwp_id);
65931.1Skamil		FORKEE_ASSERT_EQ(lid, the_lwp_id);
65941.1Skamil
65951.13Schristos		DPRINTF("Before exiting of the child process\n");
65961.1Skamil		_exit(exitval);
65971.1Skamil	}
65981.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
65991.1Skamil
66001.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
66011.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66021.1Skamil
66031.1Skamil	validate_status_stopped(status, sigval);
66041.1Skamil
66051.13Schristos	DPRINTF("Before resuming the child process where it left off and "
66061.1Skamil	    "without signal to be sent\n");
66071.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
66081.1Skamil
66091.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
66101.1Skamil	    "SIGTRAP\n", TWAIT_FNAME);
66111.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66121.1Skamil
66131.1Skamil	validate_status_stopped(status, SIGTRAP);
66141.1Skamil
66151.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
66161.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
66171.1Skamil
66181.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
66191.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
66201.1Skamil
66211.1Skamil	PARENT_FROM_CHILD("Message", fds, msg);
66221.1Skamil
66231.13Schristos	DPRINTF("Before resuming the child process where it left off and "
66241.1Skamil	    "without signal to be sent\n");
66251.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
66261.1Skamil
66271.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
66281.1Skamil	    "SIGINT\n", TWAIT_FNAME);
66291.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66301.1Skamil
66311.1Skamil	validate_status_stopped(status, SIGINT);
66321.1Skamil
66331.1Skamil	pl.pl_lwpid = 0;
66341.1Skamil
66351.13Schristos	SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &pl, sizeof(pl)) != -1);
66361.1Skamil	while (pl.pl_lwpid != 0) {
66371.13Schristos		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &pl, sizeof(pl)) != -1);
66381.1Skamil		switch (pl.pl_lwpid) {
66391.1Skamil		case 1:
66401.1Skamil			ATF_REQUIRE_EQ(pl.pl_event, PL_EVENT_SIGNAL);
66411.1Skamil			break;
66421.1Skamil		case 2:
66431.1Skamil			ATF_REQUIRE_EQ(pl.pl_event, PL_EVENT_SUSPENDED);
66441.1Skamil			break;
66451.1Skamil		}
66461.1Skamil	}
66471.1Skamil
66481.13Schristos	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
66491.13Schristos	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
66501.1Skamil
66511.13Schristos	DPRINTF("Before resuming the child process where it left off and "
66521.1Skamil	    "without signal to be sent\n");
66531.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
66541.1Skamil
66551.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
66561.1Skamil	    TWAIT_FNAME);
66571.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
66581.1Skamil
66591.1Skamil	validate_status_exited(status, exitval);
66601.1Skamil
66611.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
66621.1Skamil	    TWAIT_FNAME);
66631.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
66641.1Skamil
66651.1Skamil	msg_close(&fds);
66661.1Skamil}
66671.1Skamil
66681.1SkamilATF_TC(syscall1);
66691.1SkamilATF_TC_HEAD(syscall1, tc)
66701.1Skamil{
66711.1Skamil	atf_tc_set_md_var(tc, "descr",
66721.1Skamil	    "Verify that getpid(2) can be traced with PT_SYSCALL");
66731.1Skamil}
66741.1Skamil
66751.1SkamilATF_TC_BODY(syscall1, tc)
66761.1Skamil{
66771.1Skamil	const int exitval = 5;
66781.1Skamil	const int sigval = SIGSTOP;
66791.1Skamil	pid_t child, wpid;
66801.1Skamil#if defined(TWAIT_HAVE_STATUS)
66811.1Skamil	int status;
66821.1Skamil#endif
66831.1Skamil	struct ptrace_siginfo info;
66841.1Skamil	memset(&info, 0, sizeof(info));
66851.1Skamil
66861.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
66871.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
66881.1Skamil	if (child == 0) {
66891.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
66901.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
66911.1Skamil
66921.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
66931.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
66941.1Skamil
66951.1Skamil		syscall(SYS_getpid);
66961.1Skamil
66971.13Schristos		DPRINTF("Before exiting of the child process\n");
66981.1Skamil		_exit(exitval);
66991.1Skamil	}
67001.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
67011.1Skamil
67021.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
67031.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
67041.1Skamil
67051.1Skamil	validate_status_stopped(status, sigval);
67061.1Skamil
67071.13Schristos	DPRINTF("Before resuming the child process where it left off and "
67081.1Skamil	    "without signal to be sent\n");
67091.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
67101.1Skamil
67111.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
67121.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
67131.1Skamil
67141.1Skamil	validate_status_stopped(status, SIGTRAP);
67151.1Skamil
67161.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
67171.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
67181.1Skamil
67191.38Skamil	DPRINTF("Before checking siginfo_t and lwpid\n");
67201.38Skamil	ATF_REQUIRE_EQ(info.psi_lwpid, 1);
67211.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
67221.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_SCE);
67231.1Skamil
67241.13Schristos	DPRINTF("Before resuming the child process where it left off and "
67251.1Skamil	    "without signal to be sent\n");
67261.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
67271.1Skamil
67281.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
67291.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
67301.1Skamil
67311.1Skamil	validate_status_stopped(status, SIGTRAP);
67321.1Skamil
67331.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
67341.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
67351.1Skamil
67361.38Skamil	DPRINTF("Before checking siginfo_t and lwpid\n");
67371.38Skamil	ATF_REQUIRE_EQ(info.psi_lwpid, 1);
67381.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
67391.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_SCX);
67401.1Skamil
67411.13Schristos	DPRINTF("Before resuming the child process where it left off and "
67421.1Skamil	    "without signal to be sent\n");
67431.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
67441.1Skamil
67451.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
67461.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
67471.1Skamil
67481.1Skamil	validate_status_exited(status, exitval);
67491.1Skamil
67501.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
67511.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
67521.1Skamil}
67531.1Skamil
67541.1SkamilATF_TC(syscallemu1);
67551.1SkamilATF_TC_HEAD(syscallemu1, tc)
67561.1Skamil{
67571.1Skamil	atf_tc_set_md_var(tc, "descr",
67581.1Skamil	    "Verify that exit(2) can be intercepted with PT_SYSCALLEMU");
67591.1Skamil}
67601.1Skamil
67611.1SkamilATF_TC_BODY(syscallemu1, tc)
67621.1Skamil{
67631.1Skamil	const int exitval = 5;
67641.1Skamil	const int sigval = SIGSTOP;
67651.1Skamil	pid_t child, wpid;
67661.1Skamil#if defined(TWAIT_HAVE_STATUS)
67671.1Skamil	int status;
67681.1Skamil#endif
67691.1Skamil
67701.6Skamil#if defined(__sparc__) && !defined(__sparc64__)
67711.6Skamil	/* syscallemu does not work on sparc (32-bit) */
67721.6Skamil	atf_tc_expect_fail("PR kern/52166");
67731.6Skamil#endif
67741.6Skamil
67751.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
67761.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
67771.1Skamil	if (child == 0) {
67781.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
67791.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
67801.1Skamil
67811.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
67821.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
67831.1Skamil
67841.1Skamil		syscall(SYS_exit, 100);
67851.1Skamil
67861.13Schristos		DPRINTF("Before exiting of the child process\n");
67871.1Skamil		_exit(exitval);
67881.1Skamil	}
67891.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
67901.1Skamil
67911.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
67921.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
67931.1Skamil
67941.1Skamil	validate_status_stopped(status, sigval);
67951.1Skamil
67961.13Schristos	DPRINTF("Before resuming the child process where it left off and "
67971.1Skamil	    "without signal to be sent\n");
67981.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
67991.1Skamil
68001.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68011.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68021.1Skamil
68031.1Skamil	validate_status_stopped(status, SIGTRAP);
68041.1Skamil
68051.13Schristos	DPRINTF("Set SYSCALLEMU for intercepted syscall\n");
68061.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALLEMU, child, (void *)1, 0) != -1);
68071.1Skamil
68081.13Schristos	DPRINTF("Before resuming the child process where it left off and "
68091.1Skamil	    "without signal to be sent\n");
68101.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
68111.1Skamil
68121.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68131.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68141.1Skamil
68151.1Skamil	validate_status_stopped(status, SIGTRAP);
68161.1Skamil
68171.13Schristos	DPRINTF("Before resuming the child process where it left off and "
68181.1Skamil	    "without signal to be sent\n");
68191.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
68201.1Skamil
68211.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68221.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68231.1Skamil
68241.1Skamil	validate_status_exited(status, exitval);
68251.1Skamil
68261.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68271.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
68281.1Skamil}
68291.1Skamil
68301.103Skamil/// ----------------------------------------------------------------------------
68311.103Skamil
68321.106Skamilstatic void
68331.106Skamilclone_body(int flags, bool trackfork, bool trackvfork,
68341.106Skamil    bool trackvforkdone)
68351.106Skamil{
68361.106Skamil	const int exitval = 5;
68371.106Skamil	const int exitval2 = 15;
68381.106Skamil	const int sigval = SIGSTOP;
68391.106Skamil	pid_t child, child2 = 0, wpid;
68401.106Skamil#if defined(TWAIT_HAVE_STATUS)
68411.106Skamil	int status;
68421.106Skamil#endif
68431.106Skamil	ptrace_state_t state;
68441.106Skamil	const int slen = sizeof(state);
68451.106Skamil	ptrace_event_t event;
68461.106Skamil	const int elen = sizeof(event);
68471.106Skamil
68481.106Skamil	const size_t stack_size = 1024 * 1024;
68491.106Skamil	void *stack, *stack_base;
68501.106Skamil
68511.106Skamil	stack = malloc(stack_size);
68521.106Skamil	ATF_REQUIRE(stack != NULL);
68531.106Skamil
68541.106Skamil#ifdef __MACHINE_STACK_GROWS_UP
68551.106Skamil	stack_base = stack;
68561.106Skamil#else
68571.106Skamil	stack_base = (char *)stack + stack_size;
68581.106Skamil#endif
68591.106Skamil
68601.106Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
68611.106Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
68621.106Skamil	if (child == 0) {
68631.106Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
68641.106Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
68651.106Skamil
68661.106Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
68671.106Skamil		FORKEE_ASSERT(raise(sigval) == 0);
68681.106Skamil
68691.106Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
68701.106Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
68711.106Skamil
68721.106Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
68731.106Skamil		    child2);
68741.106Skamil
68751.106Skamil		// XXX WALLSIG?
68761.106Skamil		FORKEE_REQUIRE_SUCCESS
68771.106Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
68781.106Skamil
68791.106Skamil		forkee_status_exited(status, exitval2);
68801.106Skamil
68811.106Skamil		DPRINTF("Before exiting of the child process\n");
68821.106Skamil		_exit(exitval);
68831.106Skamil	}
68841.106Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
68851.106Skamil
68861.106Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
68871.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68881.106Skamil
68891.106Skamil	validate_status_stopped(status, sigval);
68901.106Skamil
68911.106Skamil	DPRINTF("Set 0%s%s%s in EVENT_MASK for the child %d\n",
68921.106Skamil	    trackfork ? "|PTRACE_FORK" : "",
68931.106Skamil	    trackvfork ? "|PTRACE_VFORK" : "",
68941.106Skamil	    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", child);
68951.106Skamil	event.pe_set_event = 0;
68961.106Skamil	if (trackfork)
68971.106Skamil		event.pe_set_event |= PTRACE_FORK;
68981.106Skamil	if (trackvfork)
68991.106Skamil		event.pe_set_event |= PTRACE_VFORK;
69001.106Skamil	if (trackvforkdone)
69011.106Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
69021.106Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
69031.106Skamil
69041.106Skamil	DPRINTF("Before resuming the child process where it left off and "
69051.106Skamil	    "without signal to be sent\n");
69061.106Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
69071.106Skamil
69081.106Skamil#if defined(TWAIT_HAVE_PID)
69091.106Skamil	if ((trackfork && !(flags & CLONE_VFORK)) ||
69101.106Skamil	    (trackvfork && (flags & CLONE_VFORK))) {
69111.106Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
69121.106Skamil		    child);
69131.106Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
69141.106Skamil		    child);
69151.106Skamil
69161.106Skamil		validate_status_stopped(status, SIGTRAP);
69171.106Skamil
69181.106Skamil		SYSCALL_REQUIRE(
69191.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
69201.106Skamil		if (trackfork && !(flags & CLONE_VFORK)) {
69211.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
69221.106Skamil			       PTRACE_FORK);
69231.106Skamil		}
69241.106Skamil		if (trackvfork && (flags & CLONE_VFORK)) {
69251.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
69261.106Skamil			       PTRACE_VFORK);
69271.106Skamil		}
69281.106Skamil
69291.106Skamil		child2 = state.pe_other_pid;
69301.106Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
69311.106Skamil
69321.106Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
69331.106Skamil		    "%d\n", TWAIT_FNAME, child2, child);
69341.106Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
69351.106Skamil		    child2);
69361.106Skamil
69371.106Skamil		validate_status_stopped(status, SIGTRAP);
69381.106Skamil
69391.106Skamil		SYSCALL_REQUIRE(
69401.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
69411.106Skamil		if (trackfork && !(flags & CLONE_VFORK)) {
69421.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
69431.106Skamil			       PTRACE_FORK);
69441.106Skamil		}
69451.106Skamil		if (trackvfork && (flags & CLONE_VFORK)) {
69461.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
69471.106Skamil			       PTRACE_VFORK);
69481.106Skamil		}
69491.106Skamil
69501.106Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
69511.106Skamil
69521.106Skamil		DPRINTF("Before resuming the forkee process where it left off "
69531.106Skamil		    "and without signal to be sent\n");
69541.106Skamil		SYSCALL_REQUIRE(
69551.106Skamil		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
69561.106Skamil
69571.106Skamil		DPRINTF("Before resuming the child process where it left off "
69581.106Skamil		    "and without signal to be sent\n");
69591.106Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
69601.106Skamil	}
69611.106Skamil#endif
69621.106Skamil
69631.106Skamil	if (trackvforkdone && (flags & CLONE_VFORK)) {
69641.106Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
69651.106Skamil		    child);
69661.106Skamil		TWAIT_REQUIRE_SUCCESS(
69671.106Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
69681.106Skamil
69691.106Skamil		validate_status_stopped(status, SIGTRAP);
69701.106Skamil
69711.106Skamil		SYSCALL_REQUIRE(
69721.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
69731.106Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
69741.106Skamil
69751.106Skamil		child2 = state.pe_other_pid;
69761.106Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
69771.106Skamil		    child2);
69781.106Skamil
69791.106Skamil		DPRINTF("Before resuming the child process where it left off "
69801.106Skamil		    "and without signal to be sent\n");
69811.106Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
69821.106Skamil	}
69831.106Skamil
69841.103Skamil#if defined(TWAIT_HAVE_PID)
69851.106Skamil	if ((trackfork && !(flags & CLONE_VFORK)) ||
69861.106Skamil	    (trackvfork && (flags & CLONE_VFORK))) {
69871.106Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
69881.106Skamil		    "\n", TWAIT_FNAME);
69891.106Skamil		TWAIT_REQUIRE_SUCCESS(
69901.106Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
69911.106Skamil
69921.106Skamil		validate_status_exited(status, exitval2);
69931.106Skamil
69941.106Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
69951.106Skamil		    "process\n", TWAIT_FNAME);
69961.106Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
69971.106Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
69981.106Skamil	}
69991.106Skamil#endif
70001.106Skamil
70011.106Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
70021.106Skamil	    "SIGCHLD\n", TWAIT_FNAME);
70031.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
70041.106Skamil
70051.106Skamil	validate_status_stopped(status, SIGCHLD);
70061.106Skamil
70071.106Skamil	DPRINTF("Before resuming the child process where it left off and "
70081.106Skamil	    "without signal to be sent\n");
70091.106Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
70101.106Skamil
70111.106Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
70121.106Skamil	    TWAIT_FNAME);
70131.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
70141.106Skamil
70151.106Skamil	validate_status_exited(status, exitval);
70161.103Skamil
70171.106Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
70181.106Skamil	    TWAIT_FNAME);
70191.106Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
70201.106Skamil}
70211.103Skamil
70221.106Skamil#define CLONE_TEST(name,flags,tfork,tvfork,tvforkdone)			\
70231.106SkamilATF_TC(name);								\
70241.106SkamilATF_TC_HEAD(name, tc)							\
70251.106Skamil{									\
70261.106Skamil	atf_tc_set_md_var(tc, "descr", "Verify clone(%s) "		\
70271.106Skamil	    "called with 0%s%s%s in EVENT_MASK",			\
70281.106Skamil	    #flags,							\
70291.106Skamil	    tfork ? "|PTRACE_FORK" : "",				\
70301.106Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
70311.106Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
70321.106Skamil}									\
70331.106Skamil									\
70341.106SkamilATF_TC_BODY(name, tc)							\
70351.106Skamil{									\
70361.106Skamil									\
70371.106Skamil	clone_body(flags, tfork, tvfork, tvforkdone);			\
70381.103Skamil}
70391.103Skamil
70401.106SkamilCLONE_TEST(clone1, 0, false, false, false)
70411.106Skamil#if defined(TWAIT_HAVE_PID)
70421.106SkamilCLONE_TEST(clone2, 0, true, false, false)
70431.106SkamilCLONE_TEST(clone3, 0, false, true, false)
70441.106SkamilCLONE_TEST(clone4, 0, true, true, false)
70451.106Skamil#endif
70461.106SkamilCLONE_TEST(clone5, 0, false, false, true)
70471.106Skamil#if defined(TWAIT_HAVE_PID)
70481.106SkamilCLONE_TEST(clone6, 0, true, false, true)
70491.106SkamilCLONE_TEST(clone7, 0, false, true, true)
70501.106SkamilCLONE_TEST(clone8, 0, true, true, true)
70511.106Skamil#endif
70521.106Skamil
70531.106SkamilCLONE_TEST(clone_vm1, CLONE_VM, false, false, false)
70541.106Skamil#if defined(TWAIT_HAVE_PID)
70551.106SkamilCLONE_TEST(clone_vm2, CLONE_VM, true, false, false)
70561.106SkamilCLONE_TEST(clone_vm3, CLONE_VM, false, true, false)
70571.106SkamilCLONE_TEST(clone_vm4, CLONE_VM, true, true, false)
70581.106Skamil#endif
70591.106SkamilCLONE_TEST(clone_vm5, CLONE_VM, false, false, true)
70601.106Skamil#if defined(TWAIT_HAVE_PID)
70611.106SkamilCLONE_TEST(clone_vm6, CLONE_VM, true, false, true)
70621.106SkamilCLONE_TEST(clone_vm7, CLONE_VM, false, true, true)
70631.106SkamilCLONE_TEST(clone_vm8, CLONE_VM, true, true, true)
70641.106Skamil#endif
70651.106Skamil
70661.106SkamilCLONE_TEST(clone_fs1, CLONE_FS, false, false, false)
70671.106Skamil#if defined(TWAIT_HAVE_PID)
70681.106SkamilCLONE_TEST(clone_fs2, CLONE_FS, true, false, false)
70691.106SkamilCLONE_TEST(clone_fs3, CLONE_FS, false, true, false)
70701.106SkamilCLONE_TEST(clone_fs4, CLONE_FS, true, true, false)
70711.106Skamil#endif
70721.106SkamilCLONE_TEST(clone_fs5, CLONE_FS, false, false, true)
70731.106Skamil#if defined(TWAIT_HAVE_PID)
70741.106SkamilCLONE_TEST(clone_fs6, CLONE_FS, true, false, true)
70751.106SkamilCLONE_TEST(clone_fs7, CLONE_FS, false, true, true)
70761.106SkamilCLONE_TEST(clone_fs8, CLONE_FS, true, true, true)
70771.106Skamil#endif
70781.106Skamil
70791.106SkamilCLONE_TEST(clone_files1, CLONE_FILES, false, false, false)
70801.106Skamil#if defined(TWAIT_HAVE_PID)
70811.106SkamilCLONE_TEST(clone_files2, CLONE_FILES, true, false, false)
70821.106SkamilCLONE_TEST(clone_files3, CLONE_FILES, false, true, false)
70831.106SkamilCLONE_TEST(clone_files4, CLONE_FILES, true, true, false)
70841.106Skamil#endif
70851.106SkamilCLONE_TEST(clone_files5, CLONE_FILES, false, false, true)
70861.106Skamil#if defined(TWAIT_HAVE_PID)
70871.106SkamilCLONE_TEST(clone_files6, CLONE_FILES, true, false, true)
70881.106SkamilCLONE_TEST(clone_files7, CLONE_FILES, false, true, true)
70891.106SkamilCLONE_TEST(clone_files8, CLONE_FILES, true, true, true)
70901.106Skamil#endif
70911.106Skamil
70921.106Skamil//CLONE_TEST(clone_sighand1, CLONE_SIGHAND, false, false, false)
70931.106Skamil#if defined(TWAIT_HAVE_PID)
70941.106Skamil//CLONE_TEST(clone_sighand2, CLONE_SIGHAND, true, false, false)
70951.106Skamil//CLONE_TEST(clone_sighand3, CLONE_SIGHAND, false, true, false)
70961.106Skamil//CLONE_TEST(clone_sighand4, CLONE_SIGHAND, true, true, false)
70971.106Skamil#endif
70981.106Skamil//CLONE_TEST(clone_sighand5, CLONE_SIGHAND, false, false, true)
70991.106Skamil#if defined(TWAIT_HAVE_PID)
71001.106Skamil//CLONE_TEST(clone_sighand6, CLONE_SIGHAND, true, false, true)
71011.106Skamil//CLONE_TEST(clone_sighand7, CLONE_SIGHAND, false, true, true)
71021.106Skamil//CLONE_TEST(clone_sighand8, CLONE_SIGHAND, true, true, true)
71031.106Skamil#endif
71041.106Skamil
71051.110Skamil#if TEST_VFORK_ENABLED
71061.106SkamilCLONE_TEST(clone_vfork1, CLONE_VFORK, false, false, false)
71071.106Skamil#if defined(TWAIT_HAVE_PID)
71081.106SkamilCLONE_TEST(clone_vfork2, CLONE_VFORK, true, false, false)
71091.106SkamilCLONE_TEST(clone_vfork3, CLONE_VFORK, false, true, false)
71101.106SkamilCLONE_TEST(clone_vfork4, CLONE_VFORK, true, true, false)
71111.106Skamil#endif
71121.106SkamilCLONE_TEST(clone_vfork5, CLONE_VFORK, false, false, true)
71131.106Skamil#if defined(TWAIT_HAVE_PID)
71141.106SkamilCLONE_TEST(clone_vfork6, CLONE_VFORK, true, false, true)
71151.106SkamilCLONE_TEST(clone_vfork7, CLONE_VFORK, false, true, true)
71161.106SkamilCLONE_TEST(clone_vfork8, CLONE_VFORK, true, true, true)
71171.106Skamil#endif
71181.110Skamil#endif
71191.106Skamil
71201.106Skamil/// ----------------------------------------------------------------------------
71211.106Skamil
71221.106Skamil#if defined(TWAIT_HAVE_PID)
71231.103Skamilstatic void
71241.106Skamilclone_body2(int flags, bool masked, bool ignored)
71251.103Skamil{
71261.103Skamil	const int exitval = 5;
71271.103Skamil	const int exitval2 = 15;
71281.103Skamil	const int sigval = SIGSTOP;
71291.103Skamil	pid_t child, child2 = 0, wpid;
71301.103Skamil#if defined(TWAIT_HAVE_STATUS)
71311.103Skamil	int status;
71321.103Skamil#endif
71331.103Skamil	ptrace_state_t state;
71341.103Skamil	const int slen = sizeof(state);
71351.103Skamil	ptrace_event_t event;
71361.103Skamil	const int elen = sizeof(event);
71371.103Skamil	struct sigaction sa;
71381.103Skamil	struct ptrace_siginfo info;
71391.103Skamil	sigset_t intmask;
71401.103Skamil	struct kinfo_proc2 kp;
71411.103Skamil	size_t len = sizeof(kp);
71421.103Skamil
71431.103Skamil	int name[6];
71441.103Skamil	const size_t namelen = __arraycount(name);
71451.103Skamil	ki_sigset_t kp_sigmask;
71461.103Skamil	ki_sigset_t kp_sigignore;
71471.103Skamil
71481.103Skamil	const size_t stack_size = 1024 * 1024;
71491.103Skamil	void *stack, *stack_base;
71501.103Skamil
71511.103Skamil	stack = malloc(stack_size);
71521.103Skamil	ATF_REQUIRE(stack != NULL);
71531.103Skamil
71541.103Skamil#ifdef __MACHINE_STACK_GROWS_UP
71551.103Skamil	stack_base = stack;
71561.103Skamil#else
71571.103Skamil	stack_base = (char *)stack + stack_size;
71581.103Skamil#endif
71591.103Skamil
71601.103Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
71611.103Skamil	if (child == 0) {
71621.103Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
71631.103Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
71641.103Skamil
71651.103Skamil		if (masked) {
71661.103Skamil			sigemptyset(&intmask);
71671.103Skamil			sigaddset(&intmask, SIGTRAP);
71681.103Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
71691.103Skamil		}
71701.103Skamil
71711.103Skamil		if (ignored) {
71721.103Skamil			memset(&sa, 0, sizeof(sa));
71731.103Skamil			sa.sa_handler = SIG_IGN;
71741.103Skamil			sigemptyset(&sa.sa_mask);
71751.103Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
71761.103Skamil		}
71771.103Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
71781.103Skamil		FORKEE_ASSERT(raise(sigval) == 0);
71791.103Skamil
71801.103Skamil		DPRINTF("Before forking process PID=%d flags=%#x\n", getpid(),
71811.103Skamil		    flags);
71821.103Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
71831.103Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
71841.103Skamil
71851.103Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
71861.103Skamil		    child2);
71871.103Skamil
71881.103Skamil		// XXX WALLSIG?
71891.103Skamil		FORKEE_REQUIRE_SUCCESS
71901.103Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
71911.103Skamil
71921.103Skamil		forkee_status_exited(status, exitval2);
71931.103Skamil
71941.103Skamil		DPRINTF("Before exiting of the child process\n");
71951.103Skamil		_exit(exitval);
71961.103Skamil	}
71971.103Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
71981.103Skamil
71991.103Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
72001.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
72011.103Skamil
72021.103Skamil	validate_status_stopped(status, sigval);
72031.103Skamil
72041.103Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
72051.103Skamil	SYSCALL_REQUIRE(
72061.103Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
72071.103Skamil
72081.103Skamil	DPRINTF("Before checking siginfo_t\n");
72091.103Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
72101.103Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
72111.103Skamil
72121.103Skamil	name[0] = CTL_KERN,
72131.103Skamil	name[1] = KERN_PROC2,
72141.103Skamil	name[2] = KERN_PROC_PID;
72151.103Skamil	name[3] = child;
72161.103Skamil	name[4] = sizeof(kp);
72171.103Skamil	name[5] = 1;
72181.103Skamil
72191.103Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
72201.103Skamil
72211.103Skamil	if (masked)
72221.103Skamil		kp_sigmask = kp.p_sigmask;
72231.103Skamil
72241.103Skamil	if (ignored)
72251.103Skamil		kp_sigignore = kp.p_sigignore;
72261.103Skamil
72271.103Skamil	DPRINTF("Set PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE in "
72281.103Skamil	    "EVENT_MASK for the child %d\n", child);
72291.103Skamil	event.pe_set_event = PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE;
72301.103Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
72311.103Skamil
72321.103Skamil	DPRINTF("Before resuming the child process where it left off and "
72331.103Skamil	    "without signal to be sent\n");
72341.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
72351.103Skamil
72361.103Skamil	DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
72371.103Skamil	    child);
72381.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
72391.103Skamil	    child);
72401.103Skamil
72411.103Skamil	validate_status_stopped(status, SIGTRAP);
72421.103Skamil
72431.103Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
72441.103Skamil
72451.103Skamil	if (masked) {
72461.103Skamil		DPRINTF("kp_sigmask="
72471.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
72481.103Skamil		    PRIx32 "\n",
72491.103Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
72501.103Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
72511.103Skamil
72521.103Skamil		DPRINTF("kp.p_sigmask="
72531.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
72541.103Skamil		    PRIx32 "\n",
72551.103Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
72561.103Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
72571.103Skamil
72581.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
72591.103Skamil		    sizeof(kp_sigmask)));
72601.103Skamil	}
72611.103Skamil
72621.103Skamil	if (ignored) {
72631.103Skamil		DPRINTF("kp_sigignore="
72641.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
72651.103Skamil		    PRIx32 "\n",
72661.103Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
72671.103Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
72681.103Skamil
72691.103Skamil		DPRINTF("kp.p_sigignore="
72701.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
72711.103Skamil		    PRIx32 "\n",
72721.103Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
72731.103Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
72741.103Skamil
72751.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
72761.103Skamil		    sizeof(kp_sigignore)));
72771.103Skamil	}
72781.103Skamil
72791.103Skamil	SYSCALL_REQUIRE(
72801.103Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
72811.103Skamil	DPRINTF("state.pe_report_event=%#x pid=%d\n", state.pe_report_event,
72821.103Skamil	    child2);
72831.103Skamil	if (!(flags & CLONE_VFORK)) {
72841.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
72851.103Skamil		       PTRACE_FORK);
72861.103Skamil	} else {
72871.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
72881.103Skamil		       PTRACE_VFORK);
72891.103Skamil	}
72901.103Skamil
72911.103Skamil	child2 = state.pe_other_pid;
72921.103Skamil	DPRINTF("Reported ptrace event with forkee %d\n", child2);
72931.103Skamil
72941.103Skamil	DPRINTF("Before calling %s() for the forkee %d of the child "
72951.103Skamil	    "%d\n", TWAIT_FNAME, child2, child);
72961.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
72971.103Skamil	    child2);
72981.103Skamil
72991.103Skamil	validate_status_stopped(status, SIGTRAP);
73001.103Skamil
73011.103Skamil	name[3] = child2;
73021.103Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
73031.103Skamil
73041.103Skamil	if (masked) {
73051.103Skamil		DPRINTF("kp_sigmask="
73061.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73071.103Skamil		    PRIx32 "\n",
73081.103Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
73091.103Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
73101.103Skamil
73111.103Skamil		DPRINTF("kp.p_sigmask="
73121.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73131.103Skamil		    PRIx32 "\n",
73141.103Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
73151.103Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
73161.103Skamil
73171.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
73181.103Skamil		    sizeof(kp_sigmask)));
73191.103Skamil	}
73201.103Skamil
73211.103Skamil	if (ignored) {
73221.103Skamil		DPRINTF("kp_sigignore="
73231.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73241.103Skamil		    PRIx32 "\n",
73251.103Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
73261.103Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
73271.103Skamil
73281.103Skamil		DPRINTF("kp.p_sigignore="
73291.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73301.103Skamil		    PRIx32 "\n",
73311.103Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
73321.103Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
73331.103Skamil
73341.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
73351.103Skamil		    sizeof(kp_sigignore)));
73361.103Skamil	}
73371.103Skamil
73381.103Skamil	SYSCALL_REQUIRE(
73391.103Skamil	    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
73401.103Skamil	if (!(flags & CLONE_VFORK)) {
73411.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
73421.103Skamil		       PTRACE_FORK);
73431.103Skamil	} else {
73441.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
73451.103Skamil		       PTRACE_VFORK);
73461.103Skamil	}
73471.103Skamil
73481.103Skamil	ATF_REQUIRE_EQ(state.pe_other_pid, child);
73491.103Skamil
73501.103Skamil	DPRINTF("Before resuming the forkee process where it left off "
73511.103Skamil	    "and without signal to be sent\n");
73521.103Skamil	SYSCALL_REQUIRE(
73531.103Skamil	    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
73541.103Skamil
73551.103Skamil	DPRINTF("Before resuming the child process where it left off "
73561.103Skamil	    "and without signal to be sent\n");
73571.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
73581.103Skamil
73591.103Skamil	if (flags & CLONE_VFORK) {
73601.103Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
73611.103Skamil		    child);
73621.103Skamil		TWAIT_REQUIRE_SUCCESS(
73631.103Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
73641.103Skamil
73651.103Skamil		validate_status_stopped(status, SIGTRAP);
73661.103Skamil
73671.103Skamil		name[3] = child;
73681.103Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
73691.103Skamil
73701.103Skamil		/*
73711.103Skamil		 * SIGCHLD is now pending in the signal queue and
73721.103Skamil		 * the kernel presents it to userland as a masked signal.
73731.103Skamil		 */
73741.103Skamil		sigdelset((sigset_t *)&kp.p_sigmask, SIGCHLD);
73751.103Skamil
73761.103Skamil		if (masked) {
73771.103Skamil			DPRINTF("kp_sigmask="
73781.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73791.103Skamil			    PRIx32 "\n",
73801.103Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
73811.103Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
73821.103Skamil
73831.103Skamil			DPRINTF("kp.p_sigmask="
73841.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73851.103Skamil			    PRIx32 "\n",
73861.103Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
73871.103Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
73881.103Skamil
73891.103Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
73901.103Skamil			    sizeof(kp_sigmask)));
73911.103Skamil		}
73921.103Skamil
73931.103Skamil		if (ignored) {
73941.103Skamil			DPRINTF("kp_sigignore="
73951.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
73961.103Skamil			    PRIx32 "\n",
73971.103Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
73981.103Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
73991.103Skamil
74001.103Skamil			DPRINTF("kp.p_sigignore="
74011.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
74021.103Skamil			    PRIx32 "\n",
74031.103Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
74041.103Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
74051.103Skamil
74061.103Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
74071.103Skamil			    sizeof(kp_sigignore)));
74081.103Skamil		}
74091.103Skamil
74101.103Skamil		SYSCALL_REQUIRE(
74111.103Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
74121.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
74131.103Skamil
74141.103Skamil		child2 = state.pe_other_pid;
74151.103Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
74161.103Skamil		    child2);
74171.103Skamil
74181.103Skamil		DPRINTF("Before resuming the child process where it left off "
74191.103Skamil		    "and without signal to be sent\n");
74201.103Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
74211.103Skamil	}
74221.103Skamil
74231.103Skamil	DPRINTF("Before calling %s() for the forkee - expected exited"
74241.103Skamil	    "\n", TWAIT_FNAME);
74251.103Skamil	TWAIT_REQUIRE_SUCCESS(
74261.103Skamil	    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
74271.103Skamil
74281.103Skamil	validate_status_exited(status, exitval2);
74291.103Skamil
74301.103Skamil	DPRINTF("Before calling %s() for the forkee - expected no "
74311.103Skamil	    "process\n", TWAIT_FNAME);
74321.103Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
74331.103Skamil	    wpid = TWAIT_GENERIC(child2, &status, 0));
74341.103Skamil
74351.103Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
74361.103Skamil	    "SIGCHLD\n", TWAIT_FNAME);
74371.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74381.103Skamil
74391.103Skamil	validate_status_stopped(status, SIGCHLD);
74401.103Skamil
74411.103Skamil	DPRINTF("Before resuming the child process where it left off and "
74421.103Skamil	    "without signal to be sent\n");
74431.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
74441.103Skamil
74451.103Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
74461.103Skamil	    TWAIT_FNAME);
74471.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74481.103Skamil
74491.103Skamil	validate_status_exited(status, exitval);
74501.103Skamil
74511.103Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
74521.103Skamil	    TWAIT_FNAME);
74531.103Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
74541.103Skamil}
74551.103Skamil
74561.106Skamil#define CLONE_TEST2(name,flags,masked,ignored)				\
74571.103SkamilATF_TC(name);								\
74581.103SkamilATF_TC_HEAD(name, tc)							\
74591.103Skamil{									\
74601.103Skamil	atf_tc_set_md_var(tc, "descr", "Verify that clone(%s) is caught"\
74611.103Skamil	    " regardless of signal %s%s", 				\
74621.103Skamil	    #flags, masked ? "masked" : "", ignored ? "ignored" : "");	\
74631.103Skamil}									\
74641.103Skamil									\
74651.103SkamilATF_TC_BODY(name, tc)							\
74661.103Skamil{									\
74671.103Skamil									\
74681.106Skamil	clone_body2(flags, masked, ignored);				\
74691.103Skamil}
74701.103Skamil
74711.106SkamilCLONE_TEST2(clone_signalignored, 0, true, false)
74721.106SkamilCLONE_TEST2(clone_signalmasked, 0, false, true)
74731.106SkamilCLONE_TEST2(clone_vm_signalignored, CLONE_VM, true, false)
74741.106SkamilCLONE_TEST2(clone_vm_signalmasked, CLONE_VM, false, true)
74751.106SkamilCLONE_TEST2(clone_fs_signalignored, CLONE_FS, true, false)
74761.106SkamilCLONE_TEST2(clone_fs_signalmasked, CLONE_FS, false, true)
74771.106SkamilCLONE_TEST2(clone_files_signalignored, CLONE_FILES, true, false)
74781.106SkamilCLONE_TEST2(clone_files_signalmasked, CLONE_FILES, false, true)
74791.106Skamil//CLONE_TEST2(clone_sighand_signalignored, CLONE_SIGHAND, true, false) // XXX
74801.106Skamil//CLONE_TEST2(clone_sighand_signalmasked, CLONE_SIGHAND, false, true)  // XXX
74811.110Skamil#if TEST_VFORK_ENABLED
74821.106SkamilCLONE_TEST2(clone_vfork_signalignored, CLONE_VFORK, true, false)
74831.106SkamilCLONE_TEST2(clone_vfork_signalmasked, CLONE_VFORK, false, true)
74841.103Skamil#endif
74851.110Skamil#endif
74861.103Skamil
74871.103Skamil/// ----------------------------------------------------------------------------
74881.103Skamil
74891.111Skamil#if TEST_VFORK_ENABLED
74901.107Skamil#if defined(TWAIT_HAVE_PID)
74911.107Skamilstatic void
74921.107Skamiltraceme_vfork_clone_body(int flags)
74931.107Skamil{
74941.107Skamil	const int exitval = 5;
74951.107Skamil	const int exitval2 = 15;
74961.107Skamil	pid_t child, child2 = 0, wpid;
74971.107Skamil#if defined(TWAIT_HAVE_STATUS)
74981.107Skamil	int status;
74991.107Skamil#endif
75001.107Skamil
75011.107Skamil	const size_t stack_size = 1024 * 1024;
75021.107Skamil	void *stack, *stack_base;
75031.107Skamil
75041.107Skamil	stack = malloc(stack_size);
75051.107Skamil	ATF_REQUIRE(stack != NULL);
75061.107Skamil
75071.107Skamil#ifdef __MACHINE_STACK_GROWS_UP
75081.107Skamil	stack_base = stack;
75091.107Skamil#else
75101.107Skamil	stack_base = (char *)stack + stack_size;
75111.107Skamil#endif
75121.107Skamil
75131.107Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
75141.107Skamil	if (child == 0) {
75151.107Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
75161.107Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
75171.107Skamil
75181.107Skamil		DPRINTF("Before forking process PID=%d flags=%#x\n", getpid(),
75191.107Skamil		    flags);
75201.107Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
75211.107Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
75221.107Skamil
75231.107Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
75241.107Skamil		    child2);
75251.107Skamil
75261.107Skamil		// XXX WALLSIG?
75271.107Skamil		FORKEE_REQUIRE_SUCCESS
75281.107Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
75291.107Skamil
75301.107Skamil		forkee_status_exited(status, exitval2);
75311.107Skamil
75321.107Skamil		DPRINTF("Before exiting of the child process\n");
75331.107Skamil		_exit(exitval);
75341.107Skamil	}
75351.107Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
75361.107Skamil
75371.107Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
75381.107Skamil	    TWAIT_FNAME);
75391.107Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
75401.107Skamil
75411.107Skamil	validate_status_exited(status, exitval);
75421.107Skamil
75431.107Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
75441.107Skamil	    TWAIT_FNAME);
75451.107Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
75461.107Skamil}
75471.107Skamil
75481.107Skamil#define TRACEME_VFORK_CLONE_TEST(name,flags)				\
75491.107SkamilATF_TC(name);								\
75501.107SkamilATF_TC_HEAD(name, tc)							\
75511.107Skamil{									\
75521.107Skamil	atf_tc_set_md_var(tc, "descr", "Verify that clone(%s) is "	\
75531.107Skamil	    "handled correctly with vfork(2)ed tracer", 		\
75541.107Skamil	    #flags);							\
75551.107Skamil}									\
75561.107Skamil									\
75571.107SkamilATF_TC_BODY(name, tc)							\
75581.107Skamil{									\
75591.107Skamil									\
75601.107Skamil	traceme_vfork_clone_body(flags);				\
75611.107Skamil}
75621.107Skamil
75631.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone, 0)
75641.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_vm, CLONE_VM)
75651.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_fs, CLONE_FS)
75661.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_files, CLONE_FILES)
75671.107Skamil//TRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_sighand, CLONE_SIGHAND)  // XXX
75681.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_vfork, CLONE_VFORK)
75691.107Skamil#endif
75701.110Skamil#endif
75711.107Skamil
75721.107Skamil/// ----------------------------------------------------------------------------
75731.107Skamil
75741.122Skamilstatic void
75751.122Skamiluser_va0_disable(int operation)
75761.122Skamil{
75771.122Skamil	pid_t child, wpid;
75781.122Skamil#if defined(TWAIT_HAVE_STATUS)
75791.122Skamil	int status;
75801.122Skamil#endif
75811.122Skamil	const int sigval = SIGSTOP;
75821.122Skamil	int rv;
75831.122Skamil
75841.122Skamil	struct ptrace_siginfo info;
75851.122Skamil
75861.122Skamil	if (get_user_va0_disable() == 0)
75871.122Skamil		atf_tc_skip("vm.user_va0_disable is set to 0");
75881.122Skamil
75891.122Skamil	memset(&info, 0, sizeof(info));
75901.122Skamil
75911.122Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
75921.122Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
75931.122Skamil	if (child == 0) {
75941.122Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
75951.122Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
75961.122Skamil
75971.122Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
75981.122Skamil		FORKEE_ASSERT(raise(sigval) == 0);
75991.122Skamil
76001.122Skamil		/* NOTREACHED */
76011.122Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
76021.122Skamil		__unreachable();
76031.122Skamil	}
76041.122Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
76051.122Skamil
76061.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76071.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
76081.122Skamil
76091.122Skamil	validate_status_stopped(status, sigval);
76101.122Skamil
76111.122Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
76121.122Skamil		"child\n");
76131.122Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
76141.122Skamil		sizeof(info)) != -1);
76151.122Skamil
76161.122Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
76171.122Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
76181.122Skamil		"si_errno=%#x\n",
76191.122Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
76201.122Skamil		info.psi_siginfo.si_errno);
76211.122Skamil
76221.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
76231.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
76241.122Skamil
76251.122Skamil	DPRINTF("Before resuming the child process in PC=0x0 "
76261.122Skamil	    "and without signal to be sent\n");
76271.122Skamil	errno = 0;
76281.122Skamil	rv = ptrace(operation, child, (void *)0, 0);
76291.122Skamil	ATF_REQUIRE_EQ(errno, EINVAL);
76301.122Skamil	ATF_REQUIRE_EQ(rv, -1);
76311.122Skamil
76321.122Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
76331.122Skamil
76341.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76351.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
76361.122Skamil	validate_status_signaled(status, SIGKILL, 0);
76371.122Skamil
76381.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
76391.122Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
76401.122Skamil}
76411.122Skamil
76421.122Skamil#define USER_VA0_DISABLE(test, operation)				\
76431.122SkamilATF_TC(test);								\
76441.122SkamilATF_TC_HEAD(test, tc)							\
76451.122Skamil{									\
76461.122Skamil	atf_tc_set_md_var(tc, "descr",					\
76471.122Skamil	    "Verify behavior of " #operation " with PC set to 0x0");	\
76481.122Skamil}									\
76491.122Skamil									\
76501.122SkamilATF_TC_BODY(test, tc)							\
76511.122Skamil{									\
76521.122Skamil									\
76531.122Skamil	user_va0_disable(operation);					\
76541.122Skamil}
76551.122Skamil
76561.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_continue, PT_CONTINUE)
76571.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_syscall, PT_SYSCALL)
76581.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_detach, PT_DETACH)
76591.122Skamil
76601.122Skamil/// ----------------------------------------------------------------------------
76611.122Skamil
76621.130Smgorny/*
76631.130Smgorny * Parse the core file and find the requested note.  If the reading or parsing
76641.130Smgorny * fails, the test is failed.  If the note is found, it is read onto buf, up to
76651.130Smgorny * buf_len.  The actual length of the note is returned (which can be greater
76661.130Smgorny * than buf_len, indicating that it has been truncated).  If the note is not
76671.130Smgorny * found, -1 is returned.
76681.130Smgorny */
76691.130Smgornystatic ssize_t core_find_note(const char *core_path,
76701.130Smgorny    const char *note_name, uint64_t note_type, void *buf, size_t buf_len)
76711.130Smgorny{
76721.130Smgorny	int core_fd;
76731.130Smgorny	Elf *core_elf;
76741.130Smgorny	size_t core_numhdr, i;
76751.130Smgorny	ssize_t ret = -1;
76761.130Smgorny	/* note: we assume note name will be null-terminated */
76771.130Smgorny	size_t name_len = strlen(note_name) + 1;
76781.130Smgorny
76791.130Smgorny	SYSCALL_REQUIRE((core_fd = open(core_path, O_RDONLY)) != -1);
76801.130Smgorny	SYSCALL_REQUIRE(elf_version(EV_CURRENT) != EV_NONE);
76811.130Smgorny	SYSCALL_REQUIRE((core_elf = elf_begin(core_fd, ELF_C_READ, NULL)));
76821.130Smgorny
76831.130Smgorny	SYSCALL_REQUIRE(elf_getphnum(core_elf, &core_numhdr) != 0);
76841.130Smgorny	for (i = 0; i < core_numhdr && ret == -1; i++) {
76851.130Smgorny		GElf_Phdr core_hdr;
76861.130Smgorny		size_t offset;
76871.130Smgorny		SYSCALL_REQUIRE(gelf_getphdr(core_elf, i, &core_hdr));
76881.130Smgorny		if (core_hdr.p_type != PT_NOTE)
76891.130Smgorny		    continue;
76901.130Smgorny
76911.130Smgorny		for (offset = core_hdr.p_offset;
76921.130Smgorny		    offset < core_hdr.p_offset + core_hdr.p_filesz;) {
76931.130Smgorny			Elf64_Nhdr note_hdr;
76941.130Smgorny			char name_buf[64];
76951.130Smgorny
76961.130Smgorny			switch (gelf_getclass(core_elf)) {
76971.130Smgorny			case ELFCLASS64:
76981.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &note_hdr,
76991.130Smgorny				    sizeof(note_hdr), offset)
77001.130Smgorny				    == sizeof(note_hdr));
77011.130Smgorny				offset += sizeof(note_hdr);
77021.130Smgorny				break;
77031.130Smgorny			case ELFCLASS32:
77041.130Smgorny				{
77051.130Smgorny				Elf32_Nhdr tmp_hdr;
77061.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &tmp_hdr,
77071.130Smgorny				    sizeof(tmp_hdr), offset)
77081.130Smgorny				    == sizeof(tmp_hdr));
77091.130Smgorny				offset += sizeof(tmp_hdr);
77101.130Smgorny				note_hdr.n_namesz = tmp_hdr.n_namesz;
77111.130Smgorny				note_hdr.n_descsz = tmp_hdr.n_descsz;
77121.130Smgorny				note_hdr.n_type = tmp_hdr.n_type;
77131.130Smgorny				}
77141.130Smgorny				break;
77151.130Smgorny			}
77161.130Smgorny
77171.130Smgorny			/* indicates end of notes */
77181.130Smgorny			if (note_hdr.n_namesz == 0 || note_hdr.n_descsz == 0)
77191.130Smgorny				break;
77201.130Smgorny			if (note_hdr.n_namesz == name_len &&
77211.130Smgorny			    note_hdr.n_namesz <= sizeof(name_buf)) {
77221.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, name_buf,
77231.130Smgorny				    note_hdr.n_namesz, offset)
77241.131Skamil				    == (ssize_t)(size_t)note_hdr.n_namesz);
77251.130Smgorny
77261.130Smgorny				if (!strncmp(note_name, name_buf, name_len) &&
77271.130Smgorny				    note_hdr.n_type == note_type)
77281.130Smgorny					ret = note_hdr.n_descsz;
77291.130Smgorny			}
77301.130Smgorny
77311.130Smgorny			offset += note_hdr.n_namesz;
77321.130Smgorny			/* fix to alignment */
77331.130Smgorny			offset = ((offset + core_hdr.p_align - 1)
77341.130Smgorny			    / core_hdr.p_align) * core_hdr.p_align;
77351.130Smgorny
77361.130Smgorny			/* if name & type matched above */
77371.130Smgorny			if (ret != -1) {
77381.130Smgorny				ssize_t read_len = MIN(buf_len,
77391.130Smgorny				    note_hdr.n_descsz);
77401.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, buf,
77411.130Smgorny				    read_len, offset) == read_len);
77421.130Smgorny				break;
77431.130Smgorny			}
77441.130Smgorny
77451.130Smgorny			offset += note_hdr.n_descsz;
77461.130Smgorny		}
77471.130Smgorny	}
77481.130Smgorny
77491.130Smgorny	elf_end(core_elf);
77501.130Smgorny	close(core_fd);
77511.130Smgorny
77521.130Smgorny	return ret;
77531.130Smgorny}
77541.130Smgorny
77551.130SmgornyATF_TC(core_dump_procinfo);
77561.130SmgornyATF_TC_HEAD(core_dump_procinfo, tc)
77571.130Smgorny{
77581.130Smgorny	atf_tc_set_md_var(tc, "descr",
77591.130Smgorny		"Trigger a core dump and verify its contents.");
77601.130Smgorny}
77611.130Smgorny
77621.130SmgornyATF_TC_BODY(core_dump_procinfo, tc)
77631.130Smgorny{
77641.130Smgorny	const int exitval = 5;
77651.130Smgorny	pid_t child, wpid;
77661.130Smgorny#if defined(TWAIT_HAVE_STATUS)
77671.130Smgorny	const int sigval = SIGTRAP;
77681.130Smgorny	int status;
77691.130Smgorny#endif
77701.130Smgorny	char core_path[] = "/tmp/core.XXXXXX";
77711.130Smgorny	int core_fd;
77721.130Smgorny	struct netbsd_elfcore_procinfo procinfo;
77731.130Smgorny
77741.130Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
77751.130Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
77761.130Smgorny	if (child == 0) {
77771.130Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
77781.130Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
77791.130Smgorny
77801.130Smgorny		DPRINTF("Before triggering SIGTRAP\n");
77811.130Smgorny		trigger_trap();
77821.130Smgorny
77831.130Smgorny		DPRINTF("Before exiting of the child process\n");
77841.130Smgorny		_exit(exitval);
77851.130Smgorny	}
77861.130Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
77871.130Smgorny
77881.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
77891.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
77901.130Smgorny
77911.130Smgorny	validate_status_stopped(status, sigval);
77921.130Smgorny
77931.130Smgorny	SYSCALL_REQUIRE((core_fd = mkstemp(core_path)) != -1);
77941.130Smgorny	close(core_fd);
77951.130Smgorny
77961.130Smgorny	DPRINTF("Call DUMPCORE for the child process\n");
77971.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_DUMPCORE, child, core_path, strlen(core_path))
77981.130Smgorny	    != -1);
77991.130Smgorny
78001.130Smgorny	DPRINTF("Read core file\n");
78011.130Smgorny	ATF_REQUIRE_EQ(core_find_note(core_path, "NetBSD-CORE",
78021.130Smgorny	    ELF_NOTE_NETBSD_CORE_PROCINFO, &procinfo, sizeof(procinfo)),
78031.130Smgorny	    sizeof(procinfo));
78041.130Smgorny
78051.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_version, 1);
78061.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_cpisize, sizeof(procinfo));
78071.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_signo, SIGTRAP);
78081.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pid, child);
78091.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ppid, getpid());
78101.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pgrp, getpgid(child));
78111.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_sid, getsid(child));
78121.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ruid, getuid());
78131.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_euid, geteuid());
78141.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_rgid, getgid());
78151.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_egid, getegid());
78161.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_nlwps, 1);
78171.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_siglwp, 1);
78181.130Smgorny
78191.130Smgorny	unlink(core_path);
78201.130Smgorny
78211.130Smgorny	DPRINTF("Before resuming the child process where it left off and "
78221.130Smgorny	    "without signal to be sent\n");
78231.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
78241.130Smgorny
78251.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
78261.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
78271.130Smgorny
78281.130Smgorny	validate_status_exited(status, exitval);
78291.130Smgorny
78301.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
78311.130Smgorny	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
78321.130Smgorny}
78331.130Smgorny
78341.130Smgorny/// ----------------------------------------------------------------------------
78351.130Smgorny
78361.1Skamil#include "t_ptrace_amd64_wait.h"
78371.1Skamil#include "t_ptrace_i386_wait.h"
78381.1Skamil#include "t_ptrace_x86_wait.h"
78391.1Skamil
78401.1SkamilATF_TP_ADD_TCS(tp)
78411.1Skamil{
78421.1Skamil	setvbuf(stdout, NULL, _IONBF, 0);
78431.1Skamil	setvbuf(stderr, NULL, _IONBF, 0);
78441.33Skamil
78451.36Skamil	ATF_TP_ADD_TC(tp, traceme_raise1);
78461.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise2);
78471.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise3);
78481.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise4);
78491.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise5);
78501.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise6);
78511.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise7);
78521.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise8);
78531.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise9);
78541.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise10);
78551.33Skamil
78561.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored1);
78571.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored2);
78581.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored3);
78591.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored4);
78601.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored5);
78611.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored6);
78621.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored7);
78631.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored8);
78641.87Skamil
78651.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked1);
78661.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked2);
78671.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked3);
78681.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked4);
78691.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked5);
78701.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked6);
78711.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked7);
78721.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked8);
78731.86Skamil
78741.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_trap);
78751.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_segv);
78761.71Skamil	ATF_TP_ADD_TC(tp, traceme_crash_ill);
78771.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_fpe);
78781.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_bus);
78791.59Skamil
78801.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_trap);
78811.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_segv);
78821.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_ill);
78831.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_fpe);
78841.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_bus);
78851.88Skamil
78861.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_trap);
78871.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_segv);
78881.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_ill);
78891.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_fpe);
78901.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_bus);
78911.88Skamil
78921.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle1);
78931.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle2);
78941.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle3);
78951.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle4);
78961.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle5);
78971.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle6);
78981.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle7);
78991.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle8);
79001.50Skamil
79011.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked1);
79021.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked2);
79031.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked3);
79041.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked4);
79051.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked5);
79061.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked6);
79071.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked7);
79081.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked8);
79091.50Skamil
79101.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored1);
79111.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored2);
79121.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored3);
79131.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored4);
79141.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored5);
79151.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored6);
79161.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored7);
79171.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored8);
79181.50Skamil
79191.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple1);
79201.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple2);
79211.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple3);
79221.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple4);
79231.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple5);
79241.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple6);
79251.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple7);
79261.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple8);
79271.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple9);
79281.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple10);
79291.1Skamil
79301.37Skamil	ATF_TP_ADD_TC(tp, traceme_pid1_parent);
79311.37Skamil
79321.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise1);
79331.46Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise2);
79341.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise3);
79351.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise4);
79361.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise5);
79371.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise6);
79381.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise7);
79391.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise8);
79401.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise9);
79411.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise10);
79421.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise11);
79431.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise12);
79441.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise13);
79451.40Skamil
79461.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_trap);
79471.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_segv);
79481.71Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_ill);
79491.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_fpe);
79501.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_bus);
79511.41Skamil
79521.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_trap);
79531.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_segv);
79541.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_ill);
79551.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_fpe);
79561.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_bus);
79571.92Skamil
79581.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_trap);
79591.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_segv);
79601.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_ill);
79611.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_fpe);
79621.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_bus);
79631.92Skamil
79641.43Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_exec);
79651.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_exec);
79661.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_exec);
79671.43Skamil
79681.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_trap);
79691.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_segv);
79701.71Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_ill);
79711.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_fpe);
79721.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_bus);
79731.59Skamil
79741.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79751.94Skamil	    unrelated_tracer_sees_signalmasked_crash_trap);
79761.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79771.94Skamil	    unrelated_tracer_sees_signalmasked_crash_segv);
79781.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79791.94Skamil	    unrelated_tracer_sees_signalmasked_crash_ill);
79801.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79811.94Skamil	    unrelated_tracer_sees_signalmasked_crash_fpe);
79821.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79831.94Skamil	    unrelated_tracer_sees_signalmasked_crash_bus);
79841.94Skamil
79851.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79861.94Skamil	    unrelated_tracer_sees_signalignored_crash_trap);
79871.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79881.94Skamil	    unrelated_tracer_sees_signalignored_crash_segv);
79891.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79901.94Skamil	    unrelated_tracer_sees_signalignored_crash_ill);
79911.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79921.94Skamil	    unrelated_tracer_sees_signalignored_crash_fpe);
79931.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
79941.94Skamil	    unrelated_tracer_sees_signalignored_crash_bus);
79951.94Skamil
79961.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sees_terminaton_before_the_parent);
79971.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sysctl_lookup_without_duplicates);
79981.61Skre	ATF_TP_ADD_TC_HAVE_PID(tp,
79991.61Skre		unrelated_tracer_sees_terminaton_before_the_parent);
80001.67Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_attach_to_unrelated_stopped_process);
80011.51Skamil
80021.51Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_child);
80031.66Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_stopped_child);
80041.51Skamil
80051.51Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_parent);
80061.65Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_stopped_parent);
80071.51Skamil
80081.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
80091.51Skamil		tracee_sees_its_original_parent_getppid);
80101.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
80111.51Skamil		tracee_sees_its_original_parent_sysctl_kinfo_proc2);
80121.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
80131.51Skamil		tracee_sees_its_original_parent_procfs_status);
80141.1Skamil
80151.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_empty);
80161.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_fork);
80171.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork);
80181.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork_done);
80191.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_create);
80201.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_exit);
80211.125Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_posix_spawn);
80221.1Skamil
80231.31Skamil	ATF_TP_ADD_TC(tp, fork1);
80241.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork2);
80251.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork3);
80261.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork4);
80271.31Skamil	ATF_TP_ADD_TC(tp, fork5);
80281.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork6);
80291.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork7);
80301.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork8);
80311.125Skamil	ATF_TP_ADD_TC(tp, fork9);
80321.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork10);
80331.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork11);
80341.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork12);
80351.125Skamil	ATF_TP_ADD_TC(tp, fork13);
80361.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork14);
80371.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork15);
80381.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork16);
80391.31Skamil
80401.109Skamil#if TEST_VFORK_ENABLED
80411.31Skamil	ATF_TP_ADD_TC(tp, vfork1);
80421.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork2);
80431.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork3);
80441.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork4);
80451.31Skamil	ATF_TP_ADD_TC(tp, vfork5);
80461.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork6);
80471.104Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork7);
80481.104Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork8);
80491.125Skamil	ATF_TP_ADD_TC(tp, vfork9);
80501.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork10);
80511.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork11);
80521.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork12);
80531.125Skamil	ATF_TP_ADD_TC(tp, vfork13);
80541.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork14);
80551.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork15);
80561.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork16);
80571.116Skamil#endif
80581.1Skamil
80591.124Skamil	ATF_TP_ADD_TC(tp, posix_spawn1);
80601.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn2);
80611.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn3);
80621.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn4);
80631.124Skamil	ATF_TP_ADD_TC(tp, posix_spawn5);
80641.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn6);
80651.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn7);
80661.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn8);
80671.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn9);
80681.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn10);
80691.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn11);
80701.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn12);
80711.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn13);
80721.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn14);
80731.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn15);
80741.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn16);
80751.124Skamil
80761.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_detach_spawner);
80771.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_detach_forker);
80781.116Skamil#if TEST_VFORK_ENABLED
80791.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_detach_vforker);
80801.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_detach_vforkerdone);
80811.116Skamil#endif
80821.126Skamil
80831.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_kill_spawner);
80841.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_kill_forker);
80851.116Skamil#if TEST_VFORK_ENABLED
80861.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_kill_vforker);
80871.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_kill_vforkerdone);
80881.116Skamil#endif
80891.116Skamil
80901.116Skamil#if TEST_VFORK_ENABLED
80911.108Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_fork);
80921.108Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_vfork);
80931.109Skamil#endif
80941.108Skamil
80951.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8);
80961.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16);
80971.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32);
80981.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64);
80991.54Skamil
81001.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8);
81011.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16);
81021.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32);
81031.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64);
81041.54Skamil
81051.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8);
81061.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16);
81071.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32);
81081.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64);
81091.54Skamil
81101.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8);
81111.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16);
81121.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32);
81131.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64);
81141.54Skamil
81151.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d);
81161.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i);
81171.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d);
81181.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i);
81191.54Skamil
81201.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8_text);
81211.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16_text);
81221.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32_text);
81231.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64_text);
81241.54Skamil
81251.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8_text);
81261.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16_text);
81271.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32_text);
81281.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64_text);
81291.54Skamil
81301.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8_text);
81311.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16_text);
81321.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32_text);
81331.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64_text);
81341.54Skamil
81351.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8_text);
81361.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16_text);
81371.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32_text);
81381.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64_text);
81391.54Skamil
81401.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d_text);
81411.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i_text);
81421.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d_text);
81431.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i_text);
81441.1Skamil
81451.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_auxv);
81461.1Skamil
81471.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_i);
81481.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_d);
81491.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_i);
81501.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_d);
81511.101Skamil
81521.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_i);
81531.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_d);
81541.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_i);
81551.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_d);
81561.101Skamil
81571.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_auxv);
81581.101Skamil
81591.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_i);
81601.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_d);
81611.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_i);
81621.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_d);
81631.115Skamil
81641.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_i);
81651.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_d);
81661.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_i);
81671.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_d);
81681.115Skamil
81691.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs1);
81701.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs2);
81711.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs3);
81721.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs4);
81731.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs5);
81741.72Skamil	ATF_TP_ADD_TC_HAVE_GPREGS(tp, access_regs6);
81751.1Skamil
81761.72Skamil	ATF_TP_ADD_TC_HAVE_FPREGS(tp, access_fpregs1);
81771.72Skamil	ATF_TP_ADD_TC_HAVE_FPREGS(tp, access_fpregs2);
81781.1Skamil
81791.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step1);
81801.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step2);
81811.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step3);
81821.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step4);
81831.1Skamil
81841.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep1);
81851.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep2);
81861.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep3);
81871.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep4);
81881.2Skamil
81891.95Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step_signalmasked);
81901.95Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step_signalignored);
81911.95Skamil
81921.1Skamil	ATF_TP_ADD_TC(tp, kill1);
81931.1Skamil	ATF_TP_ADD_TC(tp, kill2);
81941.75Skamil	ATF_TP_ADD_TC(tp, kill3);
81951.1Skamil
81961.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0);
81971.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1);
81981.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2);
81991.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3);
82001.77Skamil
82011.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo0);
82021.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo1);
82031.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo2);
82041.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo3);
82051.1Skamil
82061.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_unmodified);
82071.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_faked);
82081.79Skamil
82091.82Skamil	ATF_TP_ADD_TC(tp, traceme_exec);
82101.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_exec);
82111.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_exec);
82121.1Skamil
82131.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_nolwpevents);
82141.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit);
82151.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate);
82161.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit);
82171.1Skamil
82181.84Skamil	ATF_TP_ADD_TC(tp, signal_mask_unrelated);
82191.84Skamil
82201.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_singalmasked);
82211.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_singalignored);
82221.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_singalmasked);
82231.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_singalignored);
82241.109Skamil#if TEST_VFORK_ENABLED
82251.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_singalmasked);
82261.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_singalignored);
82271.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vforkdone_singalmasked);
82281.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vforkdone_singalignored);
82291.109Skamil#endif
82301.99Skamil
82311.1Skamil	ATF_TP_ADD_TC(tp, signal9);
82321.1Skamil	ATF_TP_ADD_TC(tp, signal10);
82331.1Skamil
82341.1Skamil	ATF_TP_ADD_TC(tp, suspend1);
82351.1Skamil	ATF_TP_ADD_TC(tp, suspend2);
82361.1Skamil
82371.1Skamil	ATF_TP_ADD_TC(tp, resume1);
82381.1Skamil
82391.1Skamil	ATF_TP_ADD_TC(tp, syscall1);
82401.1Skamil
82411.1Skamil	ATF_TP_ADD_TC(tp, syscallemu1);
82421.1Skamil
82431.106Skamil	ATF_TP_ADD_TC(tp, clone1);
82441.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone2);
82451.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone3);
82461.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone4);
82471.106Skamil	ATF_TP_ADD_TC(tp, clone5);
82481.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone6);
82491.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone7);
82501.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone8);
82511.106Skamil
82521.106Skamil	ATF_TP_ADD_TC(tp, clone_vm1);
82531.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm2);
82541.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm3);
82551.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm4);
82561.106Skamil	ATF_TP_ADD_TC(tp, clone_vm5);
82571.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm6);
82581.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm7);
82591.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm8);
82601.106Skamil
82611.106Skamil	ATF_TP_ADD_TC(tp, clone_fs1);
82621.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs2);
82631.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs3);
82641.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs4);
82651.106Skamil	ATF_TP_ADD_TC(tp, clone_fs5);
82661.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs6);
82671.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs7);
82681.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs8);
82691.106Skamil
82701.106Skamil	ATF_TP_ADD_TC(tp, clone_files1);
82711.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files2);
82721.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files3);
82731.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files4);
82741.106Skamil	ATF_TP_ADD_TC(tp, clone_files5);
82751.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files6);
82761.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files7);
82771.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files8);
82781.106Skamil
82791.106Skamil//	ATF_TP_ADD_TC(tp, clone_sighand1); // XXX
82801.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand2); // XXX
82811.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand3); // XXX
82821.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand4); // XXX
82831.106Skamil//	ATF_TP_ADD_TC(tp, clone_sighand5); // XXX
82841.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand6); // XXX
82851.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand7); // XXX
82861.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand8); // XXX
82871.106Skamil
82881.109Skamil#if TEST_VFORK_ENABLED
82891.106Skamil	ATF_TP_ADD_TC(tp, clone_vfork1);
82901.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork2);
82911.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork3);
82921.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork4);
82931.106Skamil	ATF_TP_ADD_TC(tp, clone_vfork5);
82941.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork6);
82951.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork7);
82961.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork8);
82971.109Skamil#endif
82981.106Skamil
82991.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_signalignored);
83001.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_signalmasked);
83011.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm_signalignored);
83021.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm_signalmasked);
83031.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs_signalignored);
83041.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs_signalmasked);
83051.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files_signalignored);
83061.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files_signalmasked);
83071.103Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand_signalignored); // XXX
83081.103Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand_signalmasked); // XXX
83091.109Skamil#if TEST_VFORK_ENABLED
83101.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork_signalignored);
83111.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork_signalmasked);
83121.109Skamil#endif
83131.103Skamil
83141.109Skamil#if TEST_VFORK_ENABLED
83151.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone);
83161.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_vm);
83171.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_fs);
83181.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_files);
83191.107Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_sighand); // XXX
83201.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_vfork);
83211.109Skamil#endif
83221.107Skamil
83231.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_continue);
83241.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall);
83251.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach);
83261.122Skamil
83271.130Smgorny	ATF_TP_ADD_TC(tp, core_dump_procinfo);
83281.130Smgorny
83291.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
83301.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_I386();
83311.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_X86();
83321.1Skamil
83331.1Skamil	return atf_no_error();
83341.1Skamil}
8335