t_ptrace_wait.c revision 1.174
11.174Skamil/*	$NetBSD: t_ptrace_wait.c,v 1.174 2020/05/04 20:55:48 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.174Skamil__RCSID("$NetBSD: t_ptrace_wait.c,v 1.174 2020/05/04 20:55:48 kamil Exp $");
311.143Skamil
321.143Skamil#define __LEGACY_PT_LWPINFO
331.1Skamil
341.1Skamil#include <sys/param.h>
351.1Skamil#include <sys/types.h>
361.130Smgorny#include <sys/exec_elf.h>
371.39Skamil#include <sys/mman.h>
381.1Skamil#include <sys/ptrace.h>
391.1Skamil#include <sys/resource.h>
401.1Skamil#include <sys/stat.h>
411.1Skamil#include <sys/syscall.h>
421.1Skamil#include <sys/sysctl.h>
431.129Smgorny#include <sys/uio.h>
441.1Skamil#include <sys/wait.h>
451.1Skamil#include <machine/reg.h>
461.132Skamil#include <assert.h>
471.1Skamil#include <elf.h>
481.1Skamil#include <err.h>
491.1Skamil#include <errno.h>
501.130Smgorny#include <fcntl.h>
511.1Skamil#include <lwp.h>
521.77Skamil#include <pthread.h>
531.1Skamil#include <sched.h>
541.1Skamil#include <signal.h>
551.124Skamil#include <spawn.h>
561.1Skamil#include <stdint.h>
571.1Skamil#include <stdio.h>
581.1Skamil#include <stdlib.h>
591.1Skamil#include <strings.h>
601.26Skamil#include <time.h>
611.1Skamil#include <unistd.h>
621.1Skamil
631.121Smgorny#if defined(__i386__) || defined(__x86_64__)
641.121Smgorny#include <cpuid.h>
651.121Smgorny#include <x86/cpu_extended_state.h>
661.129Smgorny#include <x86/specialreg.h>
671.121Smgorny#endif
681.121Smgorny
691.130Smgorny#include <libelf.h>
701.130Smgorny#include <gelf.h>
711.130Smgorny
721.1Skamil#include <atf-c.h>
731.1Skamil
741.165Skamil#ifdef ENABLE_TESTS
751.165Skamil
761.132Skamil/* Assumptions in the kernel code that must be kept. */
771.171Skamil__CTASSERT(sizeof(((struct ptrace_state *)0)->pe_report_event) ==
781.171Skamil    sizeof(((siginfo_t *)0)->si_pe_report_event));
791.171Skamil__CTASSERT(sizeof(((struct ptrace_state *)0)->pe_other_pid) ==
801.171Skamil    sizeof(((siginfo_t *)0)->si_pe_other_pid));
811.171Skamil__CTASSERT(sizeof(((struct ptrace_state *)0)->pe_lwp) ==
821.171Skamil    sizeof(((siginfo_t *)0)->si_pe_lwp));
831.171Skamil__CTASSERT(sizeof(((struct ptrace_state *)0)->pe_other_pid) ==
841.171Skamil    sizeof(((struct ptrace_state *)0)->pe_lwp));
851.132Skamil
861.1Skamil#include "h_macros.h"
871.1Skamil
881.1Skamil#include "t_ptrace_wait.h"
891.1Skamil#include "msg.h"
901.1Skamil
911.13Schristos#define SYSCALL_REQUIRE(expr) ATF_REQUIRE_MSG(expr, "%s: %s", # expr, \
921.13Schristos    strerror(errno))
931.18Schristos#define SYSCALL_REQUIRE_ERRNO(res, exp) ATF_REQUIRE_MSG(res == exp, \
941.18Schristos    "%d(%s) != %d", res, strerror(res), exp)
951.13Schristos
961.152Skamilstatic int debug = 0;
971.13Schristos
981.13Schristos#define DPRINTF(a, ...)	do  \
991.123Skamil	if (debug) \
1001.142Skamil	printf("%s() %d.%d %s:%d " a, \
1011.142Skamil	__func__, getpid(), _lwp_self(), __FILE__, __LINE__,  ##__VA_ARGS__); \
1021.13Schristos    while (/*CONSTCOND*/0)
1031.1Skamil
1041.34Skamil/// ----------------------------------------------------------------------------
1051.34Skamil
1061.33Skamilstatic void
1071.33Skamiltraceme_raise(int sigval)
1081.1Skamil{
1091.1Skamil	const int exitval = 5;
1101.1Skamil	pid_t child, wpid;
1111.1Skamil#if defined(TWAIT_HAVE_STATUS)
1121.1Skamil	int status;
1131.1Skamil#endif
1141.1Skamil
1151.133Skamil	ptrace_state_t state, zero_state;
1161.133Skamil	const int slen = sizeof(state);
1171.45Skamil	struct ptrace_siginfo info;
1181.133Skamil	memset(&zero_state, 0, sizeof(zero_state));
1191.45Skamil	memset(&info, 0, sizeof(info));
1201.45Skamil
1211.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
1221.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
1231.1Skamil	if (child == 0) {
1241.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1251.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
1261.1Skamil
1271.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
1281.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
1291.1Skamil
1301.36Skamil		switch (sigval) {
1311.36Skamil		case SIGKILL:
1321.36Skamil			/* NOTREACHED */
1331.36Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
1341.70Smrg			__unreachable();
1351.36Skamil		default:
1361.36Skamil			DPRINTF("Before exiting of the child process\n");
1371.36Skamil			_exit(exitval);
1381.36Skamil		}
1391.1Skamil	}
1401.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
1411.1Skamil
1421.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1431.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
1441.1Skamil
1451.36Skamil	switch (sigval) {
1461.36Skamil	case SIGKILL:
1471.36Skamil		validate_status_signaled(status, sigval, 0);
1481.133Skamil		SYSCALL_REQUIRE(
1491.133Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) == -1);
1501.133Skamil
1511.36Skamil		break;
1521.36Skamil	default:
1531.36Skamil		validate_status_stopped(status, sigval);
1541.1Skamil
1551.45Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
1561.61Skre			"child\n");
1571.45Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
1581.61Skre			sizeof(info)) != -1);
1591.45Skamil
1601.45Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
1611.45Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
1621.61Skre			"si_errno=%#x\n",
1631.61Skre			info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
1641.61Skre			info.psi_siginfo.si_errno);
1651.45Skamil
1661.45Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
1671.45Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
1681.45Skamil
1691.133Skamil		DPRINTF("Assert that PT_GET_PROCESS_STATE returns non-error");
1701.133Skamil		SYSCALL_REQUIRE(
1711.133Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
1721.133Skamil		ATF_REQUIRE(memcmp(&state, &zero_state, slen) == 0);
1731.133Skamil
1741.36Skamil		DPRINTF("Before resuming the child process where it left off "
1751.36Skamil		    "and without signal to be sent\n");
1761.36Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
1771.1Skamil
1781.36Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1791.36Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
1801.61Skre		    child);
1811.36Skamil		break;
1821.36Skamil	}
1831.1Skamil
1841.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1851.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
1861.1Skamil}
1871.1Skamil
1881.61Skre#define TRACEME_RAISE(test, sig)					\
1891.61SkreATF_TC(test);								\
1901.61SkreATF_TC_HEAD(test, tc)							\
1911.61Skre{									\
1921.61Skre	atf_tc_set_md_var(tc, "descr",					\
1931.61Skre	    "Verify " #sig " followed by _exit(2) in a child");		\
1941.61Skre}									\
1951.61Skre									\
1961.61SkreATF_TC_BODY(test, tc)							\
1971.61Skre{									\
1981.61Skre									\
1991.61Skre	traceme_raise(sig);						\
2001.33Skamil}
2011.33Skamil
2021.36SkamilTRACEME_RAISE(traceme_raise1, SIGKILL) /* non-maskable */
2031.33SkamilTRACEME_RAISE(traceme_raise2, SIGSTOP) /* non-maskable */
2041.33SkamilTRACEME_RAISE(traceme_raise3, SIGABRT) /* regular abort trap */
2051.33SkamilTRACEME_RAISE(traceme_raise4, SIGHUP)  /* hangup */
2061.33SkamilTRACEME_RAISE(traceme_raise5, SIGCONT) /* continued? */
2071.85SkamilTRACEME_RAISE(traceme_raise6, SIGTRAP) /* crash signal */
2081.85SkamilTRACEME_RAISE(traceme_raise7, SIGBUS) /* crash signal */
2091.85SkamilTRACEME_RAISE(traceme_raise8, SIGILL) /* crash signal */
2101.85SkamilTRACEME_RAISE(traceme_raise9, SIGFPE) /* crash signal */
2111.85SkamilTRACEME_RAISE(traceme_raise10, SIGSEGV) /* crash signal */
2121.33Skamil
2131.34Skamil/// ----------------------------------------------------------------------------
2141.1Skamil
2151.1Skamilstatic void
2161.87Skamiltraceme_raisesignal_ignored(int sigignored)
2171.87Skamil{
2181.87Skamil	const int exitval = 5;
2191.87Skamil	const int sigval = SIGSTOP;
2201.87Skamil	pid_t child, wpid;
2211.87Skamil	struct sigaction sa;
2221.87Skamil#if defined(TWAIT_HAVE_STATUS)
2231.87Skamil	int status;
2241.87Skamil#endif
2251.87Skamil	struct ptrace_siginfo info;
2261.87Skamil
2271.87Skamil	memset(&info, 0, sizeof(info));
2281.87Skamil
2291.87Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
2301.87Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
2311.87Skamil	if (child == 0) {
2321.87Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
2331.87Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
2341.87Skamil
2351.87Skamil		memset(&sa, 0, sizeof(sa));
2361.87Skamil		sa.sa_handler = SIG_IGN;
2371.87Skamil		sigemptyset(&sa.sa_mask);
2381.87Skamil		FORKEE_ASSERT(sigaction(sigignored, &sa, NULL) != -1);
2391.87Skamil
2401.87Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
2411.87Skamil		FORKEE_ASSERT(raise(sigval) == 0);
2421.87Skamil
2431.87Skamil		DPRINTF("Before raising %s from child\n",
2441.87Skamil		    strsignal(sigignored));
2451.87Skamil		FORKEE_ASSERT(raise(sigignored) == 0);
2461.87Skamil
2471.87Skamil		DPRINTF("Before exiting of the child process\n");
2481.87Skamil		_exit(exitval);
2491.87Skamil	}
2501.87Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
2511.87Skamil
2521.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2531.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2541.87Skamil
2551.87Skamil	validate_status_stopped(status, sigval);
2561.87Skamil
2571.87Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
2581.87Skamil	SYSCALL_REQUIRE(
2591.87Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
2601.87Skamil
2611.87Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
2621.87Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
2631.87Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
2641.87Skamil	    info.psi_siginfo.si_errno);
2651.87Skamil
2661.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
2671.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
2681.87Skamil
2691.87Skamil	DPRINTF("Before resuming the child process where it left off and "
2701.87Skamil	    "without signal to be sent\n");
2711.87Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
2721.87Skamil
2731.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2741.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2751.87Skamil
2761.87Skamil	validate_status_stopped(status, sigignored);
2771.87Skamil
2781.87Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
2791.87Skamil	SYSCALL_REQUIRE(
2801.87Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
2811.87Skamil
2821.87Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
2831.87Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
2841.87Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
2851.87Skamil	    info.psi_siginfo.si_errno);
2861.87Skamil
2871.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigignored);
2881.87Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
2891.87Skamil
2901.87Skamil	DPRINTF("Before resuming the child process where it left off and "
2911.87Skamil	    "without signal to be sent\n");
2921.87Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
2931.87Skamil
2941.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2951.87Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2961.87Skamil
2971.87Skamil	validate_status_exited(status, exitval);
2981.87Skamil
2991.87Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3001.87Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
3011.87Skamil}
3021.87Skamil
3031.87Skamil#define TRACEME_RAISESIGNAL_IGNORED(test, sig)				\
3041.87SkamilATF_TC(test);								\
3051.87SkamilATF_TC_HEAD(test, tc)							\
3061.87Skamil{									\
3071.87Skamil	atf_tc_set_md_var(tc, "descr",					\
3081.87Skamil	    "Verify that ignoring (with SIG_IGN) " #sig " in tracee "	\
3091.87Skamil	    "does not stop tracer from catching this raised signal");	\
3101.87Skamil}									\
3111.87Skamil									\
3121.87SkamilATF_TC_BODY(test, tc)							\
3131.87Skamil{									\
3141.87Skamil									\
3151.87Skamil	traceme_raisesignal_ignored(sig);				\
3161.87Skamil}
3171.87Skamil
3181.87Skamil// A signal handler for SIGKILL and SIGSTOP cannot be ignored.
3191.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored1, SIGABRT) /* abort */
3201.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored2, SIGHUP)  /* hangup */
3211.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored3, SIGCONT) /* cont. */
3221.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored4, SIGTRAP) /* crash */
3231.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored5, SIGBUS) /* crash */
3241.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored6, SIGILL) /* crash */
3251.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored7, SIGFPE) /* crash */
3261.87SkamilTRACEME_RAISESIGNAL_IGNORED(traceme_raisesignal_ignored8, SIGSEGV) /* crash */
3271.87Skamil
3281.87Skamil/// ----------------------------------------------------------------------------
3291.87Skamil
3301.87Skamilstatic void
3311.86Skamiltraceme_raisesignal_masked(int sigmasked)
3321.86Skamil{
3331.86Skamil	const int exitval = 5;
3341.86Skamil	const int sigval = SIGSTOP;
3351.86Skamil	pid_t child, wpid;
3361.86Skamil#if defined(TWAIT_HAVE_STATUS)
3371.86Skamil	int status;
3381.86Skamil#endif
3391.86Skamil	sigset_t intmask;
3401.86Skamil	struct ptrace_siginfo info;
3411.86Skamil
3421.86Skamil	memset(&info, 0, sizeof(info));
3431.86Skamil
3441.86Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
3451.86Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
3461.86Skamil	if (child == 0) {
3471.86Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
3481.86Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
3491.86Skamil
3501.86Skamil		sigemptyset(&intmask);
3511.86Skamil		sigaddset(&intmask, sigmasked);
3521.86Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
3531.86Skamil
3541.86Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
3551.86Skamil		FORKEE_ASSERT(raise(sigval) == 0);
3561.86Skamil
3571.86Skamil		DPRINTF("Before raising %s breakpoint from child\n",
3581.86Skamil		    strsignal(sigmasked));
3591.86Skamil		FORKEE_ASSERT(raise(sigmasked) == 0);
3601.86Skamil
3611.86Skamil		DPRINTF("Before exiting of the child process\n");
3621.86Skamil		_exit(exitval);
3631.86Skamil	}
3641.86Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
3651.86Skamil
3661.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3671.86Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
3681.86Skamil
3691.86Skamil	validate_status_stopped(status, sigval);
3701.86Skamil
3711.86Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
3721.86Skamil	SYSCALL_REQUIRE(
3731.86Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
3741.86Skamil
3751.86Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
3761.86Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
3771.86Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
3781.86Skamil	    info.psi_siginfo.si_errno);
3791.86Skamil
3801.86Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
3811.86Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
3821.86Skamil
3831.86Skamil	DPRINTF("Before resuming the child process where it left off and "
3841.86Skamil	    "without signal to be sent\n");
3851.86Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
3861.86Skamil
3871.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3881.86Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
3891.86Skamil
3901.86Skamil	validate_status_exited(status, exitval);
3911.86Skamil
3921.86Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
3931.86Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
3941.86Skamil}
3951.86Skamil
3961.86Skamil#define TRACEME_RAISESIGNAL_MASKED(test, sig)				\
3971.86SkamilATF_TC(test);								\
3981.86SkamilATF_TC_HEAD(test, tc)							\
3991.86Skamil{									\
4001.86Skamil	atf_tc_set_md_var(tc, "descr",					\
4011.86Skamil	    "Verify that masking (with SIG_BLOCK) " #sig " in tracee "	\
4021.86Skamil	    "stops tracer from catching this raised signal");		\
4031.86Skamil}									\
4041.86Skamil									\
4051.86SkamilATF_TC_BODY(test, tc)							\
4061.86Skamil{									\
4071.86Skamil									\
4081.86Skamil	traceme_raisesignal_masked(sig);				\
4091.86Skamil}
4101.86Skamil
4111.86Skamil// A signal handler for SIGKILL and SIGSTOP cannot be masked.
4121.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked1, SIGABRT) /* abort trap */
4131.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked2, SIGHUP)  /* hangup */
4141.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked3, SIGCONT) /* continued? */
4151.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked4, SIGTRAP) /* crash sig. */
4161.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked5, SIGBUS) /* crash sig. */
4171.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked6, SIGILL) /* crash sig. */
4181.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked7, SIGFPE) /* crash sig. */
4191.86SkamilTRACEME_RAISESIGNAL_MASKED(traceme_raisesignal_masked8, SIGSEGV) /* crash sig. */
4201.86Skamil
4211.86Skamil/// ----------------------------------------------------------------------------
4221.86Skamil
4231.86Skamilstatic void
4241.59Skamiltraceme_crash(int sig)
4251.59Skamil{
4261.59Skamil	pid_t child, wpid;
4271.59Skamil#if defined(TWAIT_HAVE_STATUS)
4281.59Skamil	int status;
4291.59Skamil#endif
4301.59Skamil	struct ptrace_siginfo info;
4311.61Skre
4321.71Skamil#ifndef PTRACE_ILLEGAL_ASM
4331.71Skamil	if (sig == SIGILL)
4341.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
4351.71Skamil#endif
4361.71Skamil
4371.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
4381.114Skamil		atf_tc_skip("FP exceptions are not supported");
4391.114Skamil
4401.59Skamil	memset(&info, 0, sizeof(info));
4411.59Skamil
4421.59Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
4431.59Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
4441.59Skamil	if (child == 0) {
4451.59Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
4461.59Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
4471.59Skamil
4481.59Skamil		DPRINTF("Before executing a trap\n");
4491.59Skamil		switch (sig) {
4501.59Skamil		case SIGTRAP:
4511.59Skamil			trigger_trap();
4521.59Skamil			break;
4531.59Skamil		case SIGSEGV:
4541.59Skamil			trigger_segv();
4551.59Skamil			break;
4561.59Skamil		case SIGILL:
4571.59Skamil			trigger_ill();
4581.59Skamil			break;
4591.59Skamil		case SIGFPE:
4601.59Skamil			trigger_fpe();
4611.59Skamil			break;
4621.59Skamil		case SIGBUS:
4631.59Skamil			trigger_bus();
4641.59Skamil			break;
4651.59Skamil		default:
4661.59Skamil			/* NOTREACHED */
4671.59Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
4681.59Skamil		}
4691.59Skamil
4701.59Skamil		/* NOTREACHED */
4711.59Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
4721.59Skamil	}
4731.59Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
4741.59Skamil
4751.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
4761.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
4771.59Skamil
4781.59Skamil	validate_status_stopped(status, sig);
4791.59Skamil
4801.59Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
4811.61Skre	SYSCALL_REQUIRE(
4821.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
4831.59Skamil
4841.59Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
4851.59Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
4861.61Skre	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
4871.61Skre	    info.psi_siginfo.si_errno);
4881.59Skamil
4891.59Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
4901.59Skamil	switch (sig) {
4911.59Skamil	case SIGTRAP:
4921.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
4931.59Skamil		break;
4941.59Skamil	case SIGSEGV:
4951.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
4961.59Skamil		break;
4971.71Skamil	case SIGILL:
4981.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
4991.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
5001.71Skamil		break;
5011.59Skamil	case SIGFPE:
5021.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
5031.59Skamil		break;
5041.59Skamil	case SIGBUS:
5051.59Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
5061.59Skamil		break;
5071.59Skamil	}
5081.59Skamil
5091.59Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
5101.59Skamil
5111.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5121.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
5131.59Skamil
5141.59Skamil	validate_status_signaled(status, SIGKILL, 0);
5151.59Skamil
5161.59Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5171.59Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
5181.59Skamil}
5191.59Skamil
5201.61Skre#define TRACEME_CRASH(test, sig)					\
5211.61SkreATF_TC(test);								\
5221.61SkreATF_TC_HEAD(test, tc)							\
5231.61Skre{									\
5241.61Skre	atf_tc_set_md_var(tc, "descr",					\
5251.61Skre	    "Verify crash signal " #sig " in a child after PT_TRACE_ME"); \
5261.61Skre}									\
5271.61Skre									\
5281.61SkreATF_TC_BODY(test, tc)							\
5291.61Skre{									\
5301.61Skre									\
5311.61Skre	traceme_crash(sig);						\
5321.59Skamil}
5331.59Skamil
5341.59SkamilTRACEME_CRASH(traceme_crash_trap, SIGTRAP)
5351.59SkamilTRACEME_CRASH(traceme_crash_segv, SIGSEGV)
5361.71SkamilTRACEME_CRASH(traceme_crash_ill, SIGILL)
5371.59SkamilTRACEME_CRASH(traceme_crash_fpe, SIGFPE)
5381.59SkamilTRACEME_CRASH(traceme_crash_bus, SIGBUS)
5391.59Skamil
5401.59Skamil/// ----------------------------------------------------------------------------
5411.59Skamil
5421.59Skamilstatic void
5431.88Skamiltraceme_signalmasked_crash(int sig)
5441.88Skamil{
5451.89Skamil	const int sigval = SIGSTOP;
5461.88Skamil	pid_t child, wpid;
5471.88Skamil#if defined(TWAIT_HAVE_STATUS)
5481.88Skamil	int status;
5491.88Skamil#endif
5501.88Skamil	struct ptrace_siginfo info;
5511.88Skamil	sigset_t intmask;
5521.89Skamil	struct kinfo_proc2 kp;
5531.89Skamil	size_t len = sizeof(kp);
5541.89Skamil
5551.89Skamil	int name[6];
5561.89Skamil	const size_t namelen = __arraycount(name);
5571.89Skamil	ki_sigset_t kp_sigmask;
5581.88Skamil
5591.88Skamil#ifndef PTRACE_ILLEGAL_ASM
5601.88Skamil	if (sig == SIGILL)
5611.88Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
5621.88Skamil#endif
5631.88Skamil
5641.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
5651.114Skamil		atf_tc_skip("FP exceptions are not supported");
5661.114Skamil
5671.88Skamil	memset(&info, 0, sizeof(info));
5681.88Skamil
5691.88Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
5701.88Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
5711.88Skamil	if (child == 0) {
5721.88Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
5731.88Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
5741.88Skamil
5751.88Skamil		sigemptyset(&intmask);
5761.88Skamil		sigaddset(&intmask, sig);
5771.88Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
5781.88Skamil
5791.89Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
5801.89Skamil		FORKEE_ASSERT(raise(sigval) == 0);
5811.89Skamil
5821.88Skamil		DPRINTF("Before executing a trap\n");
5831.88Skamil		switch (sig) {
5841.88Skamil		case SIGTRAP:
5851.88Skamil			trigger_trap();
5861.88Skamil			break;
5871.88Skamil		case SIGSEGV:
5881.88Skamil			trigger_segv();
5891.88Skamil			break;
5901.88Skamil		case SIGILL:
5911.88Skamil			trigger_ill();
5921.88Skamil			break;
5931.88Skamil		case SIGFPE:
5941.88Skamil			trigger_fpe();
5951.88Skamil			break;
5961.88Skamil		case SIGBUS:
5971.88Skamil			trigger_bus();
5981.88Skamil			break;
5991.88Skamil		default:
6001.88Skamil			/* NOTREACHED */
6011.88Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
6021.88Skamil		}
6031.88Skamil
6041.88Skamil		/* NOTREACHED */
6051.88Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
6061.88Skamil	}
6071.88Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
6081.88Skamil
6091.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6101.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
6111.88Skamil
6121.89Skamil	validate_status_stopped(status, sigval);
6131.89Skamil
6141.89Skamil	name[0] = CTL_KERN,
6151.89Skamil	name[1] = KERN_PROC2,
6161.89Skamil	name[2] = KERN_PROC_PID;
6171.89Skamil	name[3] = child;
6181.89Skamil	name[4] = sizeof(kp);
6191.89Skamil	name[5] = 1;
6201.89Skamil
6211.89Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
6221.89Skamil
6231.89Skamil	kp_sigmask = kp.p_sigmask;
6241.89Skamil
6251.89Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
6261.89Skamil	SYSCALL_REQUIRE(
6271.89Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
6281.89Skamil
6291.89Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
6301.89Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
6311.89Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
6321.89Skamil	    info.psi_siginfo.si_errno);
6331.89Skamil
6341.89Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
6351.89Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
6361.89Skamil
6371.89Skamil	DPRINTF("Before resuming the child process where it left off and "
6381.89Skamil	    "without signal to be sent\n");
6391.89Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
6401.89Skamil
6411.89Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6421.89Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
6431.89Skamil
6441.88Skamil	validate_status_stopped(status, sig);
6451.88Skamil
6461.88Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
6471.88Skamil	SYSCALL_REQUIRE(
6481.88Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
6491.88Skamil
6501.88Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
6511.88Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
6521.88Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
6531.88Skamil	    info.psi_siginfo.si_errno);
6541.88Skamil
6551.89Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
6561.89Skamil
6571.89Skamil	DPRINTF("kp_sigmask="
6581.89Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
6591.89Skamil	    kp_sigmask.__bits[0], kp_sigmask.__bits[1], kp_sigmask.__bits[2],
6601.89Skamil	    kp_sigmask.__bits[3]);
6611.89Skamil
6621.89Skamil	DPRINTF("kp.p_sigmask="
6631.89Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
6641.89Skamil	    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
6651.89Skamil	    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
6661.89Skamil
6671.89Skamil	ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask, sizeof(kp_sigmask)));
6681.89Skamil
6691.88Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
6701.88Skamil	switch (sig) {
6711.88Skamil	case SIGTRAP:
6721.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
6731.88Skamil		break;
6741.88Skamil	case SIGSEGV:
6751.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
6761.88Skamil		break;
6771.88Skamil	case SIGILL:
6781.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
6791.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
6801.88Skamil		break;
6811.88Skamil	case SIGFPE:
6821.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
6831.88Skamil		break;
6841.88Skamil	case SIGBUS:
6851.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
6861.88Skamil		break;
6871.88Skamil	}
6881.88Skamil
6891.88Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
6901.88Skamil
6911.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6921.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
6931.88Skamil
6941.88Skamil	validate_status_signaled(status, SIGKILL, 0);
6951.88Skamil
6961.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
6971.88Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
6981.88Skamil}
6991.88Skamil
7001.88Skamil#define TRACEME_SIGNALMASKED_CRASH(test, sig)				\
7011.88SkamilATF_TC(test);								\
7021.88SkamilATF_TC_HEAD(test, tc)							\
7031.88Skamil{									\
7041.88Skamil	atf_tc_set_md_var(tc, "descr",					\
7051.88Skamil	    "Verify masked crash signal " #sig " in a child after "	\
7061.88Skamil	    "PT_TRACE_ME is delivered to its tracer");			\
7071.88Skamil}									\
7081.88Skamil									\
7091.88SkamilATF_TC_BODY(test, tc)							\
7101.88Skamil{									\
7111.88Skamil									\
7121.88Skamil	traceme_signalmasked_crash(sig);				\
7131.88Skamil}
7141.88Skamil
7151.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_trap, SIGTRAP)
7161.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_segv, SIGSEGV)
7171.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_ill, SIGILL)
7181.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_fpe, SIGFPE)
7191.88SkamilTRACEME_SIGNALMASKED_CRASH(traceme_signalmasked_crash_bus, SIGBUS)
7201.88Skamil
7211.88Skamil/// ----------------------------------------------------------------------------
7221.88Skamil
7231.88Skamilstatic void
7241.88Skamiltraceme_signalignored_crash(int sig)
7251.88Skamil{
7261.90Skamil	const int sigval = SIGSTOP;
7271.88Skamil	pid_t child, wpid;
7281.88Skamil#if defined(TWAIT_HAVE_STATUS)
7291.88Skamil	int status;
7301.88Skamil#endif
7311.88Skamil	struct sigaction sa;
7321.88Skamil	struct ptrace_siginfo info;
7331.90Skamil	struct kinfo_proc2 kp;
7341.90Skamil	size_t len = sizeof(kp);
7351.90Skamil
7361.90Skamil	int name[6];
7371.90Skamil	const size_t namelen = __arraycount(name);
7381.90Skamil	ki_sigset_t kp_sigignore;
7391.88Skamil
7401.88Skamil#ifndef PTRACE_ILLEGAL_ASM
7411.88Skamil	if (sig == SIGILL)
7421.88Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
7431.88Skamil#endif
7441.88Skamil
7451.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
7461.114Skamil		atf_tc_skip("FP exceptions are not supported");
7471.114Skamil
7481.88Skamil	memset(&info, 0, sizeof(info));
7491.88Skamil
7501.88Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
7511.88Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
7521.88Skamil	if (child == 0) {
7531.88Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
7541.88Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
7551.88Skamil
7561.88Skamil		memset(&sa, 0, sizeof(sa));
7571.88Skamil		sa.sa_handler = SIG_IGN;
7581.88Skamil		sigemptyset(&sa.sa_mask);
7591.88Skamil
7601.88Skamil		FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
7611.88Skamil
7621.90Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
7631.90Skamil		FORKEE_ASSERT(raise(sigval) == 0);
7641.90Skamil
7651.88Skamil		DPRINTF("Before executing a trap\n");
7661.88Skamil		switch (sig) {
7671.88Skamil		case SIGTRAP:
7681.88Skamil			trigger_trap();
7691.88Skamil			break;
7701.88Skamil		case SIGSEGV:
7711.88Skamil			trigger_segv();
7721.88Skamil			break;
7731.88Skamil		case SIGILL:
7741.88Skamil			trigger_ill();
7751.88Skamil			break;
7761.88Skamil		case SIGFPE:
7771.88Skamil			trigger_fpe();
7781.88Skamil			break;
7791.88Skamil		case SIGBUS:
7801.88Skamil			trigger_bus();
7811.88Skamil			break;
7821.88Skamil		default:
7831.88Skamil			/* NOTREACHED */
7841.88Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
7851.88Skamil		}
7861.88Skamil
7871.88Skamil		/* NOTREACHED */
7881.88Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
7891.88Skamil	}
7901.88Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
7911.88Skamil
7921.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
7931.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
7941.88Skamil
7951.90Skamil	validate_status_stopped(status, sigval);
7961.90Skamil
7971.90Skamil	name[0] = CTL_KERN,
7981.90Skamil	name[1] = KERN_PROC2,
7991.90Skamil	name[2] = KERN_PROC_PID;
8001.90Skamil	name[3] = child;
8011.90Skamil	name[4] = sizeof(kp);
8021.90Skamil	name[5] = 1;
8031.90Skamil
8041.90Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
8051.90Skamil
8061.90Skamil	kp_sigignore = kp.p_sigignore;
8071.90Skamil
8081.90Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
8091.90Skamil	SYSCALL_REQUIRE(
8101.90Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
8111.90Skamil
8121.90Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
8131.90Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
8141.90Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
8151.90Skamil	    info.psi_siginfo.si_errno);
8161.90Skamil
8171.90Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
8181.90Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
8191.90Skamil
8201.90Skamil	DPRINTF("Before resuming the child process where it left off and "
8211.90Skamil	    "without signal to be sent\n");
8221.90Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
8231.90Skamil
8241.90Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8251.90Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8261.90Skamil
8271.88Skamil	validate_status_stopped(status, sig);
8281.88Skamil
8291.88Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
8301.88Skamil	SYSCALL_REQUIRE(
8311.88Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
8321.88Skamil
8331.88Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
8341.88Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
8351.88Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
8361.88Skamil	    info.psi_siginfo.si_errno);
8371.88Skamil
8381.90Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
8391.90Skamil
8401.90Skamil	DPRINTF("kp_sigignore="
8411.90Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
8421.90Skamil	    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
8431.90Skamil	    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
8441.90Skamil
8451.90Skamil	DPRINTF("kp.p_sigignore="
8461.90Skamil	    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
8471.90Skamil	    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
8481.90Skamil	    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
8491.90Skamil
8501.90Skamil	ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore, sizeof(kp_sigignore)));
8511.90Skamil
8521.88Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
8531.88Skamil	switch (sig) {
8541.88Skamil	case SIGTRAP:
8551.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
8561.88Skamil		break;
8571.88Skamil	case SIGSEGV:
8581.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
8591.88Skamil		break;
8601.88Skamil	case SIGILL:
8611.113Skamil		ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
8621.112Skamil		            info.psi_siginfo.si_code <= ILL_BADSTK);
8631.88Skamil		break;
8641.88Skamil	case SIGFPE:
8651.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
8661.88Skamil		break;
8671.88Skamil	case SIGBUS:
8681.88Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
8691.88Skamil		break;
8701.88Skamil	}
8711.88Skamil
8721.88Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
8731.88Skamil
8741.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8751.88Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8761.88Skamil
8771.88Skamil	validate_status_signaled(status, SIGKILL, 0);
8781.88Skamil
8791.88Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8801.88Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
8811.88Skamil}
8821.88Skamil
8831.88Skamil#define TRACEME_SIGNALIGNORED_CRASH(test, sig)				\
8841.88SkamilATF_TC(test);								\
8851.88SkamilATF_TC_HEAD(test, tc)							\
8861.88Skamil{									\
8871.88Skamil	atf_tc_set_md_var(tc, "descr",					\
8881.88Skamil	    "Verify ignored crash signal " #sig " in a child after "	\
8891.88Skamil	    "PT_TRACE_ME is delivered to its tracer"); 			\
8901.88Skamil}									\
8911.88Skamil									\
8921.88SkamilATF_TC_BODY(test, tc)							\
8931.88Skamil{									\
8941.88Skamil									\
8951.88Skamil	traceme_signalignored_crash(sig);				\
8961.88Skamil}
8971.88Skamil
8981.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_trap, SIGTRAP)
8991.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_segv, SIGSEGV)
9001.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_ill, SIGILL)
9011.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_fpe, SIGFPE)
9021.88SkamilTRACEME_SIGNALIGNORED_CRASH(traceme_signalignored_crash_bus, SIGBUS)
9031.88Skamil
9041.88Skamil/// ----------------------------------------------------------------------------
9051.88Skamil
9061.88Skamilstatic void
9071.50Skamiltraceme_sendsignal_handle(int sigsent, void (*sah)(int a), int *traceme_caught)
9081.1Skamil{
9091.1Skamil	const int exitval = 5;
9101.34Skamil	const int sigval = SIGSTOP;
9111.1Skamil	pid_t child, wpid;
9121.1Skamil	struct sigaction sa;
9131.1Skamil#if defined(TWAIT_HAVE_STATUS)
9141.1Skamil	int status;
9151.1Skamil#endif
9161.61Skre	struct ptrace_siginfo info;
9171.1Skamil
9181.45Skamil	memset(&info, 0, sizeof(info));
9191.45Skamil
9201.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
9211.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
9221.1Skamil	if (child == 0) {
9231.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
9241.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
9251.1Skamil
9261.34Skamil		sa.sa_handler = sah;
9271.1Skamil		sa.sa_flags = SA_SIGINFO;
9281.1Skamil		sigemptyset(&sa.sa_mask);
9291.1Skamil
9301.1Skamil		FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
9311.1Skamil
9321.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
9331.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
9341.1Skamil
9351.34Skamil		FORKEE_ASSERT_EQ(*traceme_caught, 1);
9361.1Skamil
9371.13Schristos		DPRINTF("Before exiting of the child process\n");
9381.1Skamil		_exit(exitval);
9391.1Skamil	}
9401.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
9411.1Skamil
9421.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9431.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9441.1Skamil
9451.1Skamil	validate_status_stopped(status, sigval);
9461.1Skamil
9471.45Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
9481.61Skre	SYSCALL_REQUIRE(
9491.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
9501.45Skamil
9511.45Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
9521.45Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
9531.45Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
9541.45Skamil	    info.psi_siginfo.si_errno);
9551.45Skamil
9561.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
9571.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
9581.45Skamil
9591.13Schristos	DPRINTF("Before resuming the child process where it left off and with "
9601.1Skamil	    "signal %s to be sent\n", strsignal(sigsent));
9611.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
9621.1Skamil
9631.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9641.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9651.1Skamil
9661.1Skamil	validate_status_exited(status, exitval);
9671.1Skamil
9681.13Schristos	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
9691.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
9701.1Skamil}
9711.1Skamil
9721.61Skre#define TRACEME_SENDSIGNAL_HANDLE(test, sig)				\
9731.61SkreATF_TC(test);								\
9741.61SkreATF_TC_HEAD(test, tc)							\
9751.61Skre{									\
9761.61Skre	atf_tc_set_md_var(tc, "descr",					\
9771.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
9781.61Skre	    "handled correctly and caught by a signal handler");	\
9791.61Skre}									\
9801.61Skre									\
9811.61Skrestatic int test##_caught = 0;						\
9821.61Skre									\
9831.61Skrestatic void								\
9841.61Skretest##_sighandler(int arg)						\
9851.61Skre{									\
9861.61Skre	FORKEE_ASSERT_EQ(arg, sig);					\
9871.61Skre									\
9881.61Skre	++ test##_caught;						\
9891.61Skre}									\
9901.61Skre									\
9911.61SkreATF_TC_BODY(test, tc)							\
9921.61Skre{									\
9931.61Skre									\
9941.61Skre	traceme_sendsignal_handle(sig, test##_sighandler, & test##_caught); \
9951.34Skamil}
9961.34Skamil
9971.34Skamil// A signal handler for SIGKILL and SIGSTOP cannot be registered.
9981.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle1, SIGABRT) /* abort trap */
9991.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle2, SIGHUP)  /* hangup */
10001.50SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle3, SIGCONT) /* continued? */
10011.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle4, SIGTRAP) /* crash sig. */
10021.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle5, SIGBUS) /* crash sig. */
10031.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle6, SIGILL) /* crash sig. */
10041.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle7, SIGFPE) /* crash sig. */
10051.85SkamilTRACEME_SENDSIGNAL_HANDLE(traceme_sendsignal_handle8, SIGSEGV) /* crash sig. */
10061.34Skamil
10071.34Skamil/// ----------------------------------------------------------------------------
10081.34Skamil
10091.35Skamilstatic void
10101.50Skamiltraceme_sendsignal_masked(int sigsent)
10111.50Skamil{
10121.50Skamil	const int exitval = 5;
10131.50Skamil	const int sigval = SIGSTOP;
10141.50Skamil	pid_t child, wpid;
10151.50Skamil	sigset_t set;
10161.50Skamil#if defined(TWAIT_HAVE_STATUS)
10171.50Skamil	int status;
10181.50Skamil#endif
10191.61Skre	struct ptrace_siginfo info;
10201.50Skamil
10211.50Skamil	memset(&info, 0, sizeof(info));
10221.50Skamil
10231.50Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
10241.50Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
10251.50Skamil	if (child == 0) {
10261.50Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
10271.50Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
10281.50Skamil
10291.50Skamil		sigemptyset(&set);
10301.50Skamil		sigaddset(&set, sigsent);
10311.50Skamil		FORKEE_ASSERT(sigprocmask(SIG_BLOCK, &set, NULL) != -1);
10321.50Skamil
10331.50Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
10341.50Skamil		FORKEE_ASSERT(raise(sigval) == 0);
10351.50Skamil
10361.50Skamil		_exit(exitval);
10371.50Skamil	}
10381.50Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
10391.50Skamil
10401.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10411.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
10421.50Skamil
10431.50Skamil	validate_status_stopped(status, sigval);
10441.50Skamil
10451.50Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
10461.61Skre	SYSCALL_REQUIRE(
10471.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
10481.50Skamil
10491.50Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
10501.50Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
10511.50Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
10521.50Skamil	    info.psi_siginfo.si_errno);
10531.50Skamil
10541.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
10551.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
10561.50Skamil
10571.50Skamil	DPRINTF("Before resuming the child process where it left off and with "
10581.50Skamil	    "signal %s to be sent\n", strsignal(sigsent));
10591.50Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
10601.50Skamil
10611.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10621.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
10631.50Skamil
10641.50Skamil	validate_status_exited(status, exitval);
10651.50Skamil
10661.50Skamil	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
10671.50Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
10681.50Skamil}
10691.50Skamil
10701.61Skre#define TRACEME_SENDSIGNAL_MASKED(test, sig)				\
10711.61SkreATF_TC(test);								\
10721.61SkreATF_TC_HEAD(test, tc)							\
10731.61Skre{									\
10741.61Skre	atf_tc_set_md_var(tc, "descr",					\
10751.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
10761.61Skre	    "handled correctly and the signal is masked by SIG_BLOCK");	\
10771.61Skre}									\
10781.61Skre									\
10791.61SkreATF_TC_BODY(test, tc)							\
10801.61Skre{									\
10811.61Skre									\
10821.61Skre	traceme_sendsignal_masked(sig);					\
10831.50Skamil}
10841.50Skamil
10851.50Skamil// A signal handler for SIGKILL and SIGSTOP cannot be masked.
10861.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked1, SIGABRT) /* abort trap */
10871.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked2, SIGHUP)  /* hangup */
10881.50SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked3, SIGCONT) /* continued? */
10891.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked4, SIGTRAP) /* crash sig. */
10901.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked5, SIGBUS) /* crash sig. */
10911.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked6, SIGILL) /* crash sig. */
10921.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked7, SIGFPE) /* crash sig. */
10931.85SkamilTRACEME_SENDSIGNAL_MASKED(traceme_sendsignal_masked8, SIGSEGV) /* crash sig. */
10941.50Skamil
10951.50Skamil/// ----------------------------------------------------------------------------
10961.50Skamil
10971.50Skamilstatic void
10981.50Skamiltraceme_sendsignal_ignored(int sigsent)
10991.50Skamil{
11001.50Skamil	const int exitval = 5;
11011.50Skamil	const int sigval = SIGSTOP;
11021.50Skamil	pid_t child, wpid;
11031.50Skamil	struct sigaction sa;
11041.50Skamil#if defined(TWAIT_HAVE_STATUS)
11051.50Skamil	int status;
11061.50Skamil#endif
11071.61Skre	struct ptrace_siginfo info;
11081.50Skamil
11091.50Skamil	memset(&info, 0, sizeof(info));
11101.50Skamil
11111.50Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
11121.50Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
11131.50Skamil	if (child == 0) {
11141.50Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
11151.61Skre
11161.50Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
11171.50Skamil
11181.50Skamil		memset(&sa, 0, sizeof(sa));
11191.50Skamil		sa.sa_handler = SIG_IGN;
11201.50Skamil		sigemptyset(&sa.sa_mask);
11211.50Skamil		FORKEE_ASSERT(sigaction(sigsent, &sa, NULL) != -1);
11221.50Skamil
11231.50Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
11241.50Skamil		FORKEE_ASSERT(raise(sigval) == 0);
11251.50Skamil
11261.50Skamil		_exit(exitval);
11271.50Skamil	}
11281.50Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
11291.50Skamil
11301.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11311.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11321.50Skamil
11331.50Skamil	validate_status_stopped(status, sigval);
11341.50Skamil
11351.50Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
11361.61Skre	SYSCALL_REQUIRE(
11371.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
11381.50Skamil
11391.50Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
11401.50Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
11411.50Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
11421.50Skamil	    info.psi_siginfo.si_errno);
11431.50Skamil
11441.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
11451.50Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
11461.50Skamil
11471.50Skamil	DPRINTF("Before resuming the child process where it left off and with "
11481.50Skamil	    "signal %s to be sent\n", strsignal(sigsent));
11491.50Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
11501.50Skamil
11511.50Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11521.50Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11531.50Skamil
11541.50Skamil	validate_status_exited(status, exitval);
11551.50Skamil
11561.50Skamil	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
11571.50Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
11581.50Skamil}
11591.50Skamil
11601.61Skre#define TRACEME_SENDSIGNAL_IGNORED(test, sig)				\
11611.61SkreATF_TC(test);								\
11621.61SkreATF_TC_HEAD(test, tc)							\
11631.61Skre{									\
11641.61Skre	atf_tc_set_md_var(tc, "descr",					\
11651.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
11661.61Skre	    "handled correctly and the signal is masked by SIG_IGN");	\
11671.61Skre}									\
11681.61Skre									\
11691.61SkreATF_TC_BODY(test, tc)							\
11701.61Skre{									\
11711.61Skre									\
11721.61Skre	traceme_sendsignal_ignored(sig);				\
11731.50Skamil}
11741.50Skamil
11751.50Skamil// A signal handler for SIGKILL and SIGSTOP cannot be ignored.
11761.61SkreTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored1, SIGABRT) /* abort */
11771.50SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored2, SIGHUP)  /* hangup */
11781.61SkreTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored3, SIGCONT) /* continued */
11791.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored4, SIGTRAP) /* crash s. */
11801.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored5, SIGBUS) /* crash s. */
11811.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored6, SIGILL) /* crash s. */
11821.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored7, SIGFPE) /* crash s. */
11831.85SkamilTRACEME_SENDSIGNAL_IGNORED(traceme_sendsignal_ignored8, SIGSEGV) /* crash s. */
11841.50Skamil
11851.50Skamil/// ----------------------------------------------------------------------------
11861.50Skamil
11871.50Skamilstatic void
11881.50Skamiltraceme_sendsignal_simple(int sigsent)
11891.1Skamil{
11901.35Skamil	const int sigval = SIGSTOP;
11911.35Skamil	int exitval = 0;
11921.1Skamil	pid_t child, wpid;
11931.1Skamil#if defined(TWAIT_HAVE_STATUS)
11941.1Skamil	int status;
11951.85Skamil	int expect_core;
11961.85Skamil
11971.85Skamil	switch (sigsent) {
11981.85Skamil	case SIGABRT:
11991.85Skamil	case SIGTRAP:
12001.85Skamil	case SIGBUS:
12011.85Skamil	case SIGILL:
12021.85Skamil	case SIGFPE:
12031.85Skamil	case SIGSEGV:
12041.85Skamil		expect_core = 1;
12051.85Skamil		break;
12061.85Skamil	default:
12071.85Skamil		expect_core = 0;
12081.85Skamil		break;
12091.85Skamil	}
12101.1Skamil#endif
12111.61Skre	struct ptrace_siginfo info;
12121.1Skamil
12131.45Skamil	memset(&info, 0, sizeof(info));
12141.45Skamil
12151.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
12161.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
12171.1Skamil	if (child == 0) {
12181.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
12191.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
12201.1Skamil
12211.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
12221.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
12231.1Skamil
12241.35Skamil		switch (sigsent) {
12251.35Skamil		case SIGCONT:
12261.48Skamil		case SIGSTOP:
12271.35Skamil			_exit(exitval);
12281.35Skamil		default:
12291.35Skamil			/* NOTREACHED */
12301.35Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
12311.35Skamil		}
12321.1Skamil	}
12331.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
12341.1Skamil
12351.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12361.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
12371.1Skamil
12381.1Skamil	validate_status_stopped(status, sigval);
12391.1Skamil
12401.45Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
12411.61Skre	SYSCALL_REQUIRE(
12421.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
12431.45Skamil
12441.45Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12451.45Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
12461.45Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12471.45Skamil	    info.psi_siginfo.si_errno);
12481.45Skamil
12491.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
12501.45Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
12511.45Skamil
12521.13Schristos	DPRINTF("Before resuming the child process where it left off and with "
12531.1Skamil	    "signal %s to be sent\n", strsignal(sigsent));
12541.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, sigsent) != -1);
12551.1Skamil
12561.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12571.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
12581.1Skamil
12591.35Skamil	switch (sigsent) {
12601.48Skamil	case SIGSTOP:
12611.48Skamil		validate_status_stopped(status, sigsent);
12621.48Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
12631.61Skre		    "child\n");
12641.48Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
12651.61Skre		    sizeof(info)) != -1);
12661.48Skamil
12671.48Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12681.48Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
12691.61Skre		    "si_errno=%#x\n",
12701.61Skre		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12711.61Skre		    info.psi_siginfo.si_errno);
12721.48Skamil
12731.48Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
12741.48Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
12751.48Skamil
12761.48Skamil		DPRINTF("Before resuming the child process where it left off "
12771.61Skre		    "and with signal %s to be sent\n", strsignal(sigsent));
12781.48Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
12791.48Skamil
12801.48Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12811.48Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
12821.61Skre		    child);
12831.48Skamil		/* FALLTHROUGH */
12841.35Skamil	case SIGCONT:
12851.35Skamil		validate_status_exited(status, exitval);
12861.35Skamil		break;
12871.35Skamil	default:
12881.35Skamil		validate_status_signaled(status, sigsent, expect_core);
12891.35Skamil		break;
12901.35Skamil	}
12911.1Skamil
12921.13Schristos	DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
12931.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
12941.1Skamil}
12951.1Skamil
12961.61Skre#define TRACEME_SENDSIGNAL_SIMPLE(test, sig)				\
12971.61SkreATF_TC(test);								\
12981.61SkreATF_TC_HEAD(test, tc)							\
12991.61Skre{									\
13001.61Skre	atf_tc_set_md_var(tc, "descr",					\
13011.61Skre	    "Verify that a signal " #sig " emitted by a tracer to a child is " \
13021.61Skre	    "handled correctly in a child without a signal handler");	\
13031.61Skre}									\
13041.61Skre									\
13051.61SkreATF_TC_BODY(test, tc)							\
13061.61Skre{									\
13071.61Skre									\
13081.61Skre	traceme_sendsignal_simple(sig);					\
13091.35Skamil}
13101.35Skamil
13111.61SkreTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple1, SIGKILL) /* non-maskable*/
13121.61SkreTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple2, SIGSTOP) /* non-maskable*/
13131.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple3, SIGABRT) /* abort trap */
13141.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple4, SIGHUP)  /* hangup */
13151.50SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple5, SIGCONT) /* continued? */
13161.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple6, SIGTRAP) /* crash sig. */
13171.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple7, SIGBUS) /* crash sig. */
13181.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple8, SIGILL) /* crash sig. */
13191.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple9, SIGFPE) /* crash sig. */
13201.85SkamilTRACEME_SENDSIGNAL_SIMPLE(traceme_sendsignal_simple10, SIGSEGV) /* crash sig. */
13211.35Skamil
13221.35Skamil/// ----------------------------------------------------------------------------
13231.35Skamil
13241.37SkamilATF_TC(traceme_pid1_parent);
13251.37SkamilATF_TC_HEAD(traceme_pid1_parent, tc)
13261.37Skamil{
13271.37Skamil	atf_tc_set_md_var(tc, "descr",
13281.37Skamil	    "Verify that PT_TRACE_ME is not allowed when our parent is PID1");
13291.37Skamil}
13301.37Skamil
13311.37SkamilATF_TC_BODY(traceme_pid1_parent, tc)
13321.37Skamil{
13331.37Skamil	struct msg_fds parent_child;
13341.37Skamil	int exitval_child1 = 1, exitval_child2 = 2;
13351.37Skamil	pid_t child1, child2, wpid;
13361.37Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
13371.37Skamil#if defined(TWAIT_HAVE_STATUS)
13381.37Skamil	int status;
13391.37Skamil#endif
13401.37Skamil
13411.37Skamil	SYSCALL_REQUIRE(msg_open(&parent_child) == 0);
13421.37Skamil
13431.37Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
13441.37Skamil	SYSCALL_REQUIRE((child1 = fork()) != -1);
13451.37Skamil	if (child1 == 0) {
13461.37Skamil		DPRINTF("Before forking process PID=%d\n", getpid());
13471.37Skamil		SYSCALL_REQUIRE((child2 = fork()) != -1);
13481.37Skamil		if (child2 != 0) {
13491.37Skamil			DPRINTF("Parent process PID=%d, child2's PID=%d\n",
13501.61Skre			    getpid(), child2);
13511.37Skamil			_exit(exitval_child1);
13521.37Skamil		}
13531.37Skamil		CHILD_FROM_PARENT("exit child1", parent_child, msg);
13541.37Skamil
13551.37Skamil		DPRINTF("Assert that our parent is PID1 (initproc)\n");
13561.37Skamil		FORKEE_ASSERT_EQ(getppid(), 1);
13571.37Skamil
13581.37Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
13591.37Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) == -1);
13601.37Skamil		SYSCALL_REQUIRE_ERRNO(errno, EPERM);
13611.37Skamil
13621.37Skamil		CHILD_TO_PARENT("child2 exiting", parent_child, msg);
13631.37Skamil
13641.37Skamil		_exit(exitval_child2);
13651.37Skamil	}
13661.37Skamil	DPRINTF("Parent process PID=%d, child1's PID=%d\n", getpid(), child1);
13671.37Skamil
13681.37Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
13691.61Skre	TWAIT_REQUIRE_SUCCESS(
13701.61Skre	    wpid = TWAIT_GENERIC(child1, &status, WEXITED), child1);
13711.37Skamil
13721.37Skamil	validate_status_exited(status, exitval_child1);
13731.37Skamil
13741.37Skamil	DPRINTF("Notify that child1 is dead\n");
13751.37Skamil	PARENT_TO_CHILD("exit child1", parent_child, msg);
13761.37Skamil
13771.37Skamil	DPRINTF("Wait for exiting of child2\n");
13781.37Skamil	PARENT_FROM_CHILD("child2 exiting", parent_child, msg);
13791.37Skamil}
13801.37Skamil
13811.37Skamil/// ----------------------------------------------------------------------------
13821.37Skamil
13831.40Skamilstatic void
13841.40Skamiltraceme_vfork_raise(int sigval)
13851.40Skamil{
13861.46Skamil	const int exitval = 5, exitval_watcher = 10;
13871.46Skamil	pid_t child, parent, watcher, wpid;
13881.46Skamil	int rv;
13891.40Skamil#if defined(TWAIT_HAVE_STATUS)
13901.40Skamil	int status;
13911.85Skamil
13921.85Skamil	/* volatile workarounds GCC -Werror=clobbered */
13931.85Skamil	volatile int expect_core;
13941.85Skamil
13951.85Skamil	switch (sigval) {
13961.85Skamil	case SIGABRT:
13971.85Skamil	case SIGTRAP:
13981.85Skamil	case SIGBUS:
13991.85Skamil	case SIGILL:
14001.85Skamil	case SIGFPE:
14011.85Skamil	case SIGSEGV:
14021.85Skamil		expect_core = 1;
14031.85Skamil		break;
14041.85Skamil	default:
14051.85Skamil		expect_core = 0;
14061.85Skamil		break;
14071.85Skamil	}
14081.40Skamil#endif
14091.40Skamil
14101.46Skamil	/*
14111.46Skamil	 * Spawn a dedicated thread to watch for a stopped child and emit
14121.46Skamil	 * the SIGKILL signal to it.
14131.46Skamil	 *
14141.46Skamil	 * vfork(2) might clobber watcher, this means that it's safer and
14151.46Skamil	 * simpler to reparent this process to initproc and forget about it.
14161.46Skamil	 */
14171.46Skamil	if (sigval == SIGSTOP) {
14181.46Skamil		parent = getpid();
14191.46Skamil
14201.46Skamil		watcher = fork();
14211.46Skamil		ATF_REQUIRE(watcher != 1);
14221.46Skamil		if (watcher == 0) {
14231.46Skamil			/* Double fork(2) trick to reparent to initproc */
14241.46Skamil			watcher = fork();
14251.46Skamil			FORKEE_ASSERT_NEQ(watcher, -1);
14261.46Skamil			if (watcher != 0)
14271.46Skamil				_exit(exitval_watcher);
14281.46Skamil
14291.46Skamil			child = await_stopped_child(parent);
14301.46Skamil
14311.46Skamil			errno = 0;
14321.46Skamil			rv = kill(child, SIGKILL);
14331.46Skamil			FORKEE_ASSERT_EQ(rv, 0);
14341.46Skamil			FORKEE_ASSERT_EQ(errno, 0);
14351.46Skamil
14361.46Skamil			/* This exit value will be collected by initproc */
14371.46Skamil			_exit(0);
14381.46Skamil		}
14391.46Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14401.46Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(watcher, &status, 0),
14411.61Skre		    watcher);
14421.46Skamil
14431.46Skamil		validate_status_exited(status, exitval_watcher);
14441.46Skamil
14451.46Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14461.61Skre		TWAIT_REQUIRE_FAILURE(ECHILD,
14471.61Skre		    wpid = TWAIT_GENERIC(watcher, &status, 0));
14481.46Skamil	}
14491.46Skamil
14501.40Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
14511.40Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
14521.40Skamil	if (child == 0) {
14531.40Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
14541.40Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
14551.40Skamil
14561.40Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
14571.40Skamil		FORKEE_ASSERT(raise(sigval) == 0);
14581.40Skamil
14591.40Skamil		switch (sigval) {
14601.46Skamil		case SIGSTOP:
14611.40Skamil		case SIGKILL:
14621.40Skamil		case SIGABRT:
14631.40Skamil		case SIGHUP:
14641.85Skamil		case SIGTRAP:
14651.85Skamil		case SIGBUS:
14661.85Skamil		case SIGILL:
14671.85Skamil		case SIGFPE:
14681.85Skamil		case SIGSEGV:
14691.40Skamil			/* NOTREACHED */
14701.40Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
14711.70Smrg			__unreachable();
14721.40Skamil		default:
14731.40Skamil			DPRINTF("Before exiting of the child process\n");
14741.40Skamil			_exit(exitval);
14751.40Skamil		}
14761.40Skamil	}
14771.40Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
14781.40Skamil
14791.40Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14801.40Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
14811.40Skamil
14821.40Skamil	switch (sigval) {
14831.40Skamil	case SIGKILL:
14841.40Skamil	case SIGABRT:
14851.40Skamil	case SIGHUP:
14861.85Skamil	case SIGTRAP:
14871.85Skamil	case SIGBUS:
14881.85Skamil	case SIGILL:
14891.85Skamil	case SIGFPE:
14901.85Skamil	case SIGSEGV:
14911.40Skamil		validate_status_signaled(status, sigval, expect_core);
14921.40Skamil		break;
14931.40Skamil	case SIGSTOP:
14941.46Skamil		validate_status_signaled(status, SIGKILL, 0);
14951.46Skamil		break;
14961.40Skamil	case SIGCONT:
14971.47Skamil	case SIGTSTP:
14981.47Skamil	case SIGTTIN:
14991.47Skamil	case SIGTTOU:
15001.40Skamil		validate_status_exited(status, exitval);
15011.40Skamil		break;
15021.40Skamil	default:
15031.40Skamil		/* NOTREACHED */
15041.40Skamil		ATF_REQUIRE(0 && "NOT IMPLEMENTED");
15051.40Skamil		break;
15061.40Skamil	}
15071.40Skamil
15081.40Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15091.40Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
15101.40Skamil}
15111.40Skamil
15121.61Skre#define TRACEME_VFORK_RAISE(test, sig)					\
15131.61SkreATF_TC(test);								\
15141.61SkreATF_TC_HEAD(test, tc)							\
15151.61Skre{									\
15161.61Skre	atf_tc_set_md_var(tc, "descr",					\
15171.61Skre	    "Verify PT_TRACE_ME followed by raise of " #sig " in a "	\
15181.61Skre	    "vfork(2)ed child");					\
15191.61Skre}									\
15201.61Skre									\
15211.61SkreATF_TC_BODY(test, tc)							\
15221.61Skre{									\
15231.61Skre									\
15241.61Skre	traceme_vfork_raise(sig);					\
15251.40Skamil}
15261.40Skamil
15271.40SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise1, SIGKILL) /* non-maskable */
15281.46SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise2, SIGSTOP) /* non-maskable */
15291.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise3, SIGTSTP) /* ignored in vfork(2) */
15301.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise4, SIGTTIN) /* ignored in vfork(2) */
15311.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise5, SIGTTOU) /* ignored in vfork(2) */
15321.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise6, SIGABRT) /* regular abort trap */
15331.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise7, SIGHUP)  /* hangup */
15341.47SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise8, SIGCONT) /* continued? */
15351.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise9, SIGTRAP) /* crash signal */
15361.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise10, SIGBUS) /* crash signal */
15371.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise11, SIGILL) /* crash signal */
15381.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise12, SIGFPE) /* crash signal */
15391.85SkamilTRACEME_VFORK_RAISE(traceme_vfork_raise13, SIGSEGV) /* crash signal */
15401.40Skamil
15411.40Skamil/// ----------------------------------------------------------------------------
15421.40Skamil
15431.52Skamilstatic void
15441.52Skamiltraceme_vfork_crash(int sig)
15451.41Skamil{
15461.41Skamil	pid_t child, wpid;
15471.41Skamil#if defined(TWAIT_HAVE_STATUS)
15481.41Skamil	int status;
15491.41Skamil#endif
15501.41Skamil
15511.71Skamil#ifndef PTRACE_ILLEGAL_ASM
15521.71Skamil	if (sig == SIGILL)
15531.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
15541.71Skamil#endif
15551.71Skamil
15561.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
15571.114Skamil		atf_tc_skip("FP exceptions are not supported");
15581.114Skamil
15591.41Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
15601.41Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
15611.41Skamil	if (child == 0) {
15621.41Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
15631.41Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
15641.41Skamil
15651.52Skamil		DPRINTF("Before executing a trap\n");
15661.52Skamil		switch (sig) {
15671.52Skamil		case SIGTRAP:
15681.52Skamil			trigger_trap();
15691.52Skamil			break;
15701.52Skamil		case SIGSEGV:
15711.52Skamil			trigger_segv();
15721.52Skamil			break;
15731.52Skamil		case SIGILL:
15741.52Skamil			trigger_ill();
15751.52Skamil			break;
15761.52Skamil		case SIGFPE:
15771.52Skamil			trigger_fpe();
15781.52Skamil			break;
15791.52Skamil		case SIGBUS:
15801.52Skamil			trigger_bus();
15811.52Skamil			break;
15821.52Skamil		default:
15831.52Skamil			/* NOTREACHED */
15841.52Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
15851.52Skamil		}
15861.41Skamil
15871.41Skamil		/* NOTREACHED */
15881.41Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
15891.41Skamil	}
15901.41Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
15911.41Skamil
15921.41Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15931.41Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
15941.41Skamil
15951.52Skamil	validate_status_signaled(status, sig, 1);
15961.41Skamil
15971.41Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15981.41Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
15991.41Skamil}
16001.41Skamil
16011.61Skre#define TRACEME_VFORK_CRASH(test, sig)					\
16021.61SkreATF_TC(test);								\
16031.61SkreATF_TC_HEAD(test, tc)							\
16041.61Skre{									\
16051.61Skre	atf_tc_set_md_var(tc, "descr",					\
16061.61Skre	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
16071.61Skre	    "vfork(2)ed child");					\
16081.61Skre}									\
16091.61Skre									\
16101.61SkreATF_TC_BODY(test, tc)							\
16111.61Skre{									\
16121.61Skre									\
16131.61Skre	traceme_vfork_crash(sig);					\
16141.52Skamil}
16151.52Skamil
16161.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_trap, SIGTRAP)
16171.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_segv, SIGSEGV)
16181.71SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_ill, SIGILL)
16191.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_fpe, SIGFPE)
16201.52SkamilTRACEME_VFORK_CRASH(traceme_vfork_crash_bus, SIGBUS)
16211.52Skamil
16221.41Skamil/// ----------------------------------------------------------------------------
16231.41Skamil
16241.92Skamilstatic void
16251.92Skamiltraceme_vfork_signalmasked_crash(int sig)
16261.92Skamil{
16271.92Skamil	pid_t child, wpid;
16281.92Skamil#if defined(TWAIT_HAVE_STATUS)
16291.92Skamil	int status;
16301.92Skamil#endif
16311.92Skamil	sigset_t intmask;
16321.92Skamil
16331.92Skamil#ifndef PTRACE_ILLEGAL_ASM
16341.92Skamil	if (sig == SIGILL)
16351.92Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
16361.92Skamil#endif
16371.92Skamil
16381.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
16391.114Skamil		atf_tc_skip("FP exceptions are not supported");
16401.114Skamil
16411.92Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
16421.92Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
16431.92Skamil	if (child == 0) {
16441.92Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
16451.92Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
16461.92Skamil
16471.92Skamil		sigemptyset(&intmask);
16481.92Skamil		sigaddset(&intmask, sig);
16491.92Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
16501.92Skamil
16511.92Skamil		DPRINTF("Before executing a trap\n");
16521.92Skamil		switch (sig) {
16531.92Skamil		case SIGTRAP:
16541.92Skamil			trigger_trap();
16551.92Skamil			break;
16561.92Skamil		case SIGSEGV:
16571.92Skamil			trigger_segv();
16581.92Skamil			break;
16591.92Skamil		case SIGILL:
16601.92Skamil			trigger_ill();
16611.92Skamil			break;
16621.92Skamil		case SIGFPE:
16631.92Skamil			trigger_fpe();
16641.92Skamil			break;
16651.92Skamil		case SIGBUS:
16661.92Skamil			trigger_bus();
16671.92Skamil			break;
16681.92Skamil		default:
16691.92Skamil			/* NOTREACHED */
16701.92Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
16711.92Skamil		}
16721.92Skamil
16731.92Skamil		/* NOTREACHED */
16741.92Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
16751.92Skamil	}
16761.92Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
16771.92Skamil
16781.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16791.92Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
16801.92Skamil
16811.92Skamil	validate_status_signaled(status, sig, 1);
16821.92Skamil
16831.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16841.92Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
16851.92Skamil}
16861.92Skamil
16871.92Skamil#define TRACEME_VFORK_SIGNALMASKED_CRASH(test, sig)			\
16881.92SkamilATF_TC(test);								\
16891.92SkamilATF_TC_HEAD(test, tc)							\
16901.92Skamil{									\
16911.92Skamil	atf_tc_set_md_var(tc, "descr",					\
16921.92Skamil	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
16931.92Skamil	    "vfork(2)ed child with a masked signal");			\
16941.92Skamil}									\
16951.92Skamil									\
16961.92SkamilATF_TC_BODY(test, tc)							\
16971.92Skamil{									\
16981.92Skamil									\
16991.92Skamil	traceme_vfork_signalmasked_crash(sig);				\
17001.92Skamil}
17011.92Skamil
17021.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_trap, SIGTRAP)
17031.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_segv, SIGSEGV)
17041.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_ill, SIGILL)
17051.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_fpe, SIGFPE)
17061.92SkamilTRACEME_VFORK_SIGNALMASKED_CRASH(traceme_vfork_signalmasked_crash_bus, SIGBUS)
17071.92Skamil
17081.92Skamil/// ----------------------------------------------------------------------------
17091.92Skamil
17101.92Skamilstatic void
17111.92Skamiltraceme_vfork_signalignored_crash(int sig)
17121.92Skamil{
17131.92Skamil	pid_t child, wpid;
17141.92Skamil#if defined(TWAIT_HAVE_STATUS)
17151.92Skamil	int status;
17161.92Skamil#endif
17171.92Skamil	struct sigaction sa;
17181.92Skamil
17191.92Skamil#ifndef PTRACE_ILLEGAL_ASM
17201.92Skamil	if (sig == SIGILL)
17211.92Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
17221.92Skamil#endif
17231.92Skamil
17241.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
17251.114Skamil		atf_tc_skip("FP exceptions are not supported");
17261.114Skamil
17271.92Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
17281.92Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
17291.92Skamil	if (child == 0) {
17301.92Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
17311.92Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
17321.92Skamil
17331.92Skamil		memset(&sa, 0, sizeof(sa));
17341.92Skamil		sa.sa_handler = SIG_IGN;
17351.92Skamil		sigemptyset(&sa.sa_mask);
17361.92Skamil
17371.92Skamil		FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
17381.92Skamil
17391.92Skamil		DPRINTF("Before executing a trap\n");
17401.92Skamil		switch (sig) {
17411.92Skamil		case SIGTRAP:
17421.92Skamil			trigger_trap();
17431.92Skamil			break;
17441.92Skamil		case SIGSEGV:
17451.92Skamil			trigger_segv();
17461.92Skamil			break;
17471.92Skamil		case SIGILL:
17481.92Skamil			trigger_ill();
17491.92Skamil			break;
17501.92Skamil		case SIGFPE:
17511.92Skamil			trigger_fpe();
17521.92Skamil			break;
17531.92Skamil		case SIGBUS:
17541.92Skamil			trigger_bus();
17551.92Skamil			break;
17561.92Skamil		default:
17571.92Skamil			/* NOTREACHED */
17581.92Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
17591.92Skamil		}
17601.92Skamil
17611.92Skamil		/* NOTREACHED */
17621.92Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
17631.92Skamil	}
17641.92Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
17651.92Skamil
17661.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17671.92Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17681.92Skamil
17691.92Skamil	validate_status_signaled(status, sig, 1);
17701.92Skamil
17711.92Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17721.92Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
17731.92Skamil}
17741.92Skamil
17751.92Skamil#define TRACEME_VFORK_SIGNALIGNORED_CRASH(test, sig)			\
17761.92SkamilATF_TC(test);								\
17771.92SkamilATF_TC_HEAD(test, tc)							\
17781.92Skamil{									\
17791.92Skamil	atf_tc_set_md_var(tc, "descr",					\
17801.92Skamil	    "Verify PT_TRACE_ME followed by a crash signal " #sig " in a " \
17811.92Skamil	    "vfork(2)ed child with ignored signal");			\
17821.92Skamil}									\
17831.92Skamil									\
17841.92SkamilATF_TC_BODY(test, tc)							\
17851.92Skamil{									\
17861.92Skamil									\
17871.92Skamil	traceme_vfork_signalignored_crash(sig);				\
17881.92Skamil}
17891.92Skamil
17901.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_trap,
17911.92Skamil    SIGTRAP)
17921.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_segv,
17931.92Skamil    SIGSEGV)
17941.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_ill,
17951.92Skamil    SIGILL)
17961.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_fpe,
17971.92Skamil    SIGFPE)
17981.92SkamilTRACEME_VFORK_SIGNALIGNORED_CRASH(traceme_vfork_signalignored_crash_bus,
17991.92Skamil    SIGBUS)
18001.92Skamil
18011.92Skamil/// ----------------------------------------------------------------------------
18021.92Skamil
18031.96Skamilstatic void
18041.96Skamiltraceme_vfork_exec(bool masked, bool ignored)
18051.43Skamil{
18061.43Skamil	const int sigval = SIGTRAP;
18071.43Skamil	pid_t child, wpid;
18081.43Skamil#if defined(TWAIT_HAVE_STATUS)
18091.43Skamil	int status;
18101.43Skamil#endif
18111.96Skamil	struct sigaction sa;
18121.61Skre	struct ptrace_siginfo info;
18131.96Skamil	sigset_t intmask;
18141.96Skamil	struct kinfo_proc2 kp;
18151.96Skamil	size_t len = sizeof(kp);
18161.96Skamil
18171.96Skamil	int name[6];
18181.96Skamil	const size_t namelen = __arraycount(name);
18191.96Skamil	ki_sigset_t kp_sigmask;
18201.96Skamil	ki_sigset_t kp_sigignore;
18211.43Skamil
18221.43Skamil	memset(&info, 0, sizeof(info));
18231.43Skamil
18241.43Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
18251.43Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
18261.43Skamil	if (child == 0) {
18271.43Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
18281.43Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
18291.43Skamil
18301.96Skamil		if (masked) {
18311.96Skamil			sigemptyset(&intmask);
18321.96Skamil			sigaddset(&intmask, sigval);
18331.96Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
18341.96Skamil		}
18351.96Skamil
18361.96Skamil		if (ignored) {
18371.96Skamil			memset(&sa, 0, sizeof(sa));
18381.96Skamil			sa.sa_handler = SIG_IGN;
18391.96Skamil			sigemptyset(&sa.sa_mask);
18401.96Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
18411.96Skamil		}
18421.96Skamil
18431.43Skamil		DPRINTF("Before calling execve(2) from child\n");
18441.43Skamil		execlp("/bin/echo", "/bin/echo", NULL);
18451.43Skamil
18461.43Skamil		/* NOTREACHED */
18471.43Skamil		FORKEE_ASSERTX(0 && "Not reached");
18481.43Skamil	}
18491.43Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
18501.43Skamil
18511.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18521.43Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
18531.43Skamil
18541.43Skamil	validate_status_stopped(status, sigval);
18551.43Skamil
18561.96Skamil	name[0] = CTL_KERN,
18571.96Skamil	name[1] = KERN_PROC2,
18581.96Skamil	name[2] = KERN_PROC_PID;
18591.96Skamil	name[3] = getpid();
18601.96Skamil	name[4] = sizeof(kp);
18611.96Skamil	name[5] = 1;
18621.96Skamil
18631.96Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
18641.96Skamil
18651.96Skamil	if (masked)
18661.96Skamil		kp_sigmask = kp.p_sigmask;
18671.96Skamil
18681.96Skamil	if (ignored)
18691.96Skamil		kp_sigignore = kp.p_sigignore;
18701.96Skamil
18711.96Skamil	name[3] = getpid();
18721.96Skamil
18731.96Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
18741.96Skamil
18751.96Skamil	if (masked) {
18761.96Skamil		DPRINTF("kp_sigmask="
18771.96Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
18781.96Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
18791.96Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
18801.96Skamil
18811.96Skamil	        DPRINTF("kp.p_sigmask="
18821.96Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
18831.96Skamil	            kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
18841.96Skamil	            kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
18851.96Skamil
18861.96Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
18871.96Skamil		    sizeof(kp_sigmask)));
18881.96Skamil	}
18891.96Skamil
18901.96Skamil	if (ignored) {
18911.96Skamil		DPRINTF("kp_sigignore="
18921.96Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
18931.96Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
18941.96Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
18951.96Skamil
18961.96Skamil	        DPRINTF("kp.p_sigignore="
18971.96Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
18981.96Skamil	            kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
18991.96Skamil	            kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
19001.96Skamil
19011.96Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
19021.96Skamil		    sizeof(kp_sigignore)));
19031.96Skamil	}
19041.96Skamil
19051.43Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
19061.61Skre	SYSCALL_REQUIRE(
19071.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
19081.43Skamil
19091.43Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
19101.43Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
19111.43Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
19121.43Skamil	    info.psi_siginfo.si_errno);
19131.43Skamil
19141.43Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
19151.43Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
19161.43Skamil
19171.43Skamil	DPRINTF("Before resuming the child process where it left off and "
19181.43Skamil	    "without signal to be sent\n");
19191.43Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
19201.43Skamil
19211.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
19221.43Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
19231.43Skamil
19241.43Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
19251.43Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
19261.43Skamil}
19271.43Skamil
19281.96Skamil#define TRACEME_VFORK_EXEC(test, masked, ignored)			\
19291.96SkamilATF_TC(test);								\
19301.96SkamilATF_TC_HEAD(test, tc)							\
19311.96Skamil{									\
19321.96Skamil	atf_tc_set_md_var(tc, "descr",					\
19331.96Skamil	    "Verify PT_TRACE_ME followed by exec(3) in a vfork(2)ed "	\
19341.96Skamil	    "child%s%s", masked ? " with masked signal" : "",		\
19351.96Skamil	    masked ? " with ignored signal" : "");			\
19361.96Skamil}									\
19371.96Skamil									\
19381.96SkamilATF_TC_BODY(test, tc)							\
19391.96Skamil{									\
19401.96Skamil									\
19411.96Skamil	traceme_vfork_exec(masked, ignored);				\
19421.96Skamil}
19431.96Skamil
19441.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_exec, false, false)
19451.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalmasked_exec, true, false)
19461.96SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalignored_exec, false, true)
19471.96Skamil
19481.43Skamil/// ----------------------------------------------------------------------------
19491.43Skamil
19501.1Skamil#if defined(TWAIT_HAVE_PID)
19511.51Skamilstatic void
19521.94Skamilunrelated_tracer_sees_crash(int sig, bool masked, bool ignored)
19531.59Skamil{
19541.94Skamil	const int sigval = SIGSTOP;
19551.59Skamil	struct msg_fds parent_tracee, parent_tracer;
19561.59Skamil	const int exitval = 10;
19571.59Skamil	pid_t tracee, tracer, wpid;
19581.59Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
19591.59Skamil#if defined(TWAIT_HAVE_STATUS)
19601.59Skamil	int status;
19611.59Skamil#endif
19621.94Skamil	struct sigaction sa;
19631.59Skamil	struct ptrace_siginfo info;
19641.94Skamil	sigset_t intmask;
19651.94Skamil	struct kinfo_proc2 kp;
19661.94Skamil	size_t len = sizeof(kp);
19671.94Skamil
19681.94Skamil	int name[6];
19691.94Skamil	const size_t namelen = __arraycount(name);
19701.94Skamil	ki_sigset_t kp_sigmask;
19711.94Skamil	ki_sigset_t kp_sigignore;
19721.61Skre
19731.71Skamil#ifndef PTRACE_ILLEGAL_ASM
19741.71Skamil	if (sig == SIGILL)
19751.71Skamil		atf_tc_skip("PTRACE_ILLEGAL_ASM not defined");
19761.71Skamil#endif
19771.71Skamil
19781.114Skamil	if (sig == SIGFPE && !are_fpu_exceptions_supported())
19791.114Skamil		atf_tc_skip("FP exceptions are not supported");
19801.114Skamil
19811.59Skamil	memset(&info, 0, sizeof(info));
19821.59Skamil
19831.59Skamil	DPRINTF("Spawn tracee\n");
19841.59Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
19851.59Skamil	tracee = atf_utils_fork();
19861.59Skamil	if (tracee == 0) {
19871.59Skamil		// Wait for parent to let us crash
19881.59Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
19891.61Skre
19901.94Skamil		if (masked) {
19911.94Skamil			sigemptyset(&intmask);
19921.94Skamil			sigaddset(&intmask, sig);
19931.94Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
19941.94Skamil		}
19951.94Skamil
19961.94Skamil		if (ignored) {
19971.94Skamil			memset(&sa, 0, sizeof(sa));
19981.94Skamil			sa.sa_handler = SIG_IGN;
19991.94Skamil			sigemptyset(&sa.sa_mask);
20001.94Skamil			FORKEE_ASSERT(sigaction(sig, &sa, NULL) != -1);
20011.94Skamil		}
20021.94Skamil
20031.94Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
20041.94Skamil		FORKEE_ASSERT(raise(sigval) == 0);
20051.94Skamil
20061.59Skamil		DPRINTF("Before executing a trap\n");
20071.59Skamil		switch (sig) {
20081.59Skamil		case SIGTRAP:
20091.59Skamil			trigger_trap();
20101.59Skamil			break;
20111.59Skamil		case SIGSEGV:
20121.59Skamil			trigger_segv();
20131.59Skamil			break;
20141.59Skamil		case SIGILL:
20151.59Skamil			trigger_ill();
20161.59Skamil			break;
20171.59Skamil		case SIGFPE:
20181.59Skamil			trigger_fpe();
20191.59Skamil			break;
20201.59Skamil		case SIGBUS:
20211.59Skamil			trigger_bus();
20221.59Skamil			break;
20231.59Skamil		default:
20241.59Skamil			/* NOTREACHED */
20251.59Skamil			FORKEE_ASSERTX(0 && "This shall not be reached");
20261.59Skamil		}
20271.59Skamil
20281.59Skamil		/* NOTREACHED */
20291.59Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
20301.59Skamil	}
20311.59Skamil
20321.59Skamil	DPRINTF("Spawn debugger\n");
20331.59Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
20341.59Skamil	tracer = atf_utils_fork();
20351.59Skamil	if (tracer == 0) {
20361.59Skamil		/* Fork again and drop parent to reattach to PID 1 */
20371.59Skamil		tracer = atf_utils_fork();
20381.59Skamil		if (tracer != 0)
20391.61Skre			_exit(exitval);
20401.59Skamil
20411.59Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
20421.59Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
20431.59Skamil
20441.59Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
20451.59Skamil		FORKEE_REQUIRE_SUCCESS(
20461.59Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
20471.59Skamil
20481.59Skamil		forkee_status_stopped(status, SIGSTOP);
20491.59Skamil
20501.94Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
20511.94Skamil		    "traced process\n");
20521.94Skamil		SYSCALL_REQUIRE(
20531.94Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
20541.94Skamil
20551.94Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
20561.94Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
20571.94Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
20581.94Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
20591.94Skamil
20601.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
20611.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
20621.94Skamil
20631.59Skamil		/* Resume tracee with PT_CONTINUE */
20641.59Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
20651.59Skamil
20661.59Skamil		/* Inform parent that tracer has attached to tracee */
20671.59Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
20681.59Skamil
20691.59Skamil		/* Wait for parent to tell use that tracee should have exited */
20701.59Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
20711.59Skamil
20721.59Skamil		/* Wait for tracee and assert that it exited */
20731.59Skamil		FORKEE_REQUIRE_SUCCESS(
20741.59Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
20751.59Skamil
20761.94Skamil		forkee_status_stopped(status, sigval);
20771.94Skamil
20781.94Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
20791.94Skamil		    "traced process\n");
20801.94Skamil		SYSCALL_REQUIRE(
20811.94Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
20821.94Skamil
20831.94Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
20841.94Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
20851.94Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
20861.94Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
20871.94Skamil
20881.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
20891.94Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
20901.94Skamil
20911.94Skamil		name[0] = CTL_KERN,
20921.94Skamil		name[1] = KERN_PROC2,
20931.94Skamil		name[2] = KERN_PROC_PID;
20941.94Skamil		name[3] = tracee;
20951.94Skamil		name[4] = sizeof(kp);
20961.94Skamil		name[5] = 1;
20971.94Skamil
20981.94Skamil		FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
20991.94Skamil
21001.94Skamil		if (masked)
21011.94Skamil			kp_sigmask = kp.p_sigmask;
21021.94Skamil
21031.94Skamil		if (ignored)
21041.94Skamil			kp_sigignore = kp.p_sigignore;
21051.94Skamil
21061.94Skamil		/* Resume tracee with PT_CONTINUE */
21071.94Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
21081.94Skamil
21091.94Skamil		/* Wait for tracee and assert that it exited */
21101.94Skamil		FORKEE_REQUIRE_SUCCESS(
21111.94Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
21121.94Skamil
21131.93Skamil		forkee_status_stopped(status, sig);
21141.59Skamil
21151.59Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
21161.61Skre		    "traced process\n");
21171.61Skre		SYSCALL_REQUIRE(
21181.61Skre		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
21191.59Skamil
21201.59Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
21211.59Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
21221.61Skre		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
21231.61Skre		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
21241.59Skamil
21251.93Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sig);
21261.94Skamil
21271.94Skamil		FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
21281.94Skamil
21291.94Skamil		if (masked) {
21301.94Skamil			DPRINTF("kp_sigmask="
21311.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21321.94Skamil			    PRIx32 "\n",
21331.94Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
21341.94Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
21351.94Skamil
21361.94Skamil			DPRINTF("kp.p_sigmask="
21371.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21381.94Skamil			    PRIx32 "\n",
21391.94Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
21401.94Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
21411.94Skamil
21421.94Skamil			FORKEE_ASSERTX(!memcmp(&kp_sigmask, &kp.p_sigmask,
21431.94Skamil			    sizeof(kp_sigmask)));
21441.94Skamil		}
21451.94Skamil
21461.94Skamil		if (ignored) {
21471.94Skamil			DPRINTF("kp_sigignore="
21481.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21491.94Skamil			    PRIx32 "\n",
21501.94Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
21511.94Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
21521.94Skamil
21531.94Skamil			DPRINTF("kp.p_sigignore="
21541.94Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
21551.94Skamil			    PRIx32 "\n",
21561.94Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
21571.94Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
21581.94Skamil
21591.94Skamil			FORKEE_ASSERTX(!memcmp(&kp_sigignore, &kp.p_sigignore,
21601.94Skamil			    sizeof(kp_sigignore)));
21611.94Skamil		}
21621.94Skamil
21631.59Skamil		switch (sig) {
21641.59Skamil		case SIGTRAP:
21651.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
21661.59Skamil			break;
21671.59Skamil		case SIGSEGV:
21681.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
21691.59Skamil			break;
21701.71Skamil		case SIGILL:
21711.113Skamil			FORKEE_ASSERT(info.psi_siginfo.si_code >= ILL_ILLOPC &&
21721.112Skamil			            info.psi_siginfo.si_code <= ILL_BADSTK);
21731.71Skamil			break;
21741.59Skamil		case SIGFPE:
21751.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, FPE_INTDIV);
21761.59Skamil			break;
21771.59Skamil		case SIGBUS:
21781.93Skamil			FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
21791.59Skamil			break;
21801.59Skamil		}
21811.59Skamil
21821.59Skamil		FORKEE_ASSERT(ptrace(PT_KILL, tracee, NULL, 0) != -1);
21831.59Skamil		DPRINTF("Before calling %s() for the tracee\n", TWAIT_FNAME);
21841.93Skamil		FORKEE_REQUIRE_SUCCESS(
21851.61Skre		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
21861.59Skamil
21871.93Skamil		forkee_status_signaled(status, SIGKILL, 0);
21881.59Skamil
21891.71Skamil		/* Inform parent that tracer is exiting normally */
21901.71Skamil		CHILD_TO_PARENT("tracer done", parent_tracer, msg);
21911.71Skamil
21921.59Skamil		DPRINTF("Before exiting of the tracer process\n");
21931.59Skamil		_exit(0 /* collect by initproc */);
21941.59Skamil	}
21951.59Skamil
21961.59Skamil	DPRINTF("Wait for the tracer process (direct child) to exit "
21971.59Skamil	    "calling %s()\n", TWAIT_FNAME);
21981.59Skamil	TWAIT_REQUIRE_SUCCESS(
21991.59Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
22001.59Skamil
22011.59Skamil	validate_status_exited(status, exitval);
22021.59Skamil
22031.59Skamil	DPRINTF("Wait for the non-exited tracee process with %s()\n",
22041.59Skamil	    TWAIT_FNAME);
22051.59Skamil	TWAIT_REQUIRE_SUCCESS(
22061.59Skamil	    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
22071.59Skamil
22081.59Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
22091.59Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
22101.59Skamil
22111.59Skamil	DPRINTF("Resume the tracee and let it crash\n");
22121.59Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
22131.59Skamil
22141.59Skamil	DPRINTF("Resume the tracer and let it detect crashed tracee\n");
22151.59Skamil	PARENT_TO_CHILD("Message 2", parent_tracer, msg);
22161.59Skamil
22171.59Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
22181.59Skamil	    TWAIT_FNAME);
22191.59Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
22201.59Skamil
22211.59Skamil	validate_status_signaled(status, SIGKILL, 0);
22221.59Skamil
22231.71Skamil	DPRINTF("Await normal exit of tracer\n");
22241.71Skamil	PARENT_FROM_CHILD("tracer done", parent_tracer, msg);
22251.71Skamil
22261.59Skamil	msg_close(&parent_tracer);
22271.59Skamil	msg_close(&parent_tracee);
22281.59Skamil}
22291.59Skamil
22301.61Skre#define UNRELATED_TRACER_SEES_CRASH(test, sig)				\
22311.61SkreATF_TC(test);								\
22321.61SkreATF_TC_HEAD(test, tc)							\
22331.61Skre{									\
22341.61Skre	atf_tc_set_md_var(tc, "descr",					\
22351.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
22361.94Skamil	    "the debuggee");						\
22371.61Skre}									\
22381.61Skre									\
22391.61SkreATF_TC_BODY(test, tc)							\
22401.61Skre{									\
22411.61Skre									\
22421.94Skamil	unrelated_tracer_sees_crash(sig, false, false);			\
22431.59Skamil}
22441.59Skamil
22451.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_trap, SIGTRAP)
22461.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_segv, SIGSEGV)
22471.71SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_ill, SIGILL)
22481.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_fpe, SIGFPE)
22491.59SkamilUNRELATED_TRACER_SEES_CRASH(unrelated_tracer_sees_crash_bus, SIGBUS)
22501.94Skamil
22511.94Skamil#define UNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(test, sig)		\
22521.94SkamilATF_TC(test);								\
22531.94SkamilATF_TC_HEAD(test, tc)							\
22541.94Skamil{									\
22551.94Skamil	atf_tc_set_md_var(tc, "descr",					\
22561.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
22571.94Skamil	    "the debuggee with masked signal");				\
22581.94Skamil}									\
22591.94Skamil									\
22601.94SkamilATF_TC_BODY(test, tc)							\
22611.94Skamil{									\
22621.94Skamil									\
22631.94Skamil	unrelated_tracer_sees_crash(sig, true, false);			\
22641.94Skamil}
22651.94Skamil
22661.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22671.94Skamil    unrelated_tracer_sees_signalmasked_crash_trap, SIGTRAP)
22681.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22691.94Skamil    unrelated_tracer_sees_signalmasked_crash_segv, SIGSEGV)
22701.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22711.94Skamil    unrelated_tracer_sees_signalmasked_crash_ill, SIGILL)
22721.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22731.94Skamil    unrelated_tracer_sees_signalmasked_crash_fpe, SIGFPE)
22741.94SkamilUNRELATED_TRACER_SEES_SIGNALMASKED_CRASH(
22751.94Skamil    unrelated_tracer_sees_signalmasked_crash_bus, SIGBUS)
22761.94Skamil
22771.94Skamil#define UNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(test, sig)		\
22781.94SkamilATF_TC(test);								\
22791.94SkamilATF_TC_HEAD(test, tc)							\
22801.94Skamil{									\
22811.94Skamil	atf_tc_set_md_var(tc, "descr",					\
22821.94Skamil	    "Assert that an unrelated tracer sees crash signal from "	\
22831.94Skamil	    "the debuggee with signal ignored");			\
22841.94Skamil}									\
22851.94Skamil									\
22861.94SkamilATF_TC_BODY(test, tc)							\
22871.94Skamil{									\
22881.94Skamil									\
22891.94Skamil	unrelated_tracer_sees_crash(sig, false, true);			\
22901.94Skamil}
22911.94Skamil
22921.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
22931.94Skamil    unrelated_tracer_sees_signalignored_crash_trap, SIGTRAP)
22941.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
22951.94Skamil    unrelated_tracer_sees_signalignored_crash_segv, SIGSEGV)
22961.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
22971.94Skamil    unrelated_tracer_sees_signalignored_crash_ill, SIGILL)
22981.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
22991.94Skamil    unrelated_tracer_sees_signalignored_crash_fpe, SIGFPE)
23001.94SkamilUNRELATED_TRACER_SEES_SIGNALIGNORED_CRASH(
23011.94Skamil    unrelated_tracer_sees_signalignored_crash_bus, SIGBUS)
23021.59Skamil#endif
23031.59Skamil
23041.59Skamil/// ----------------------------------------------------------------------------
23051.59Skamil
23061.59Skamil#if defined(TWAIT_HAVE_PID)
23071.59Skamilstatic void
23081.67Skamiltracer_sees_terminaton_before_the_parent_raw(bool notimeout, bool unrelated,
23091.67Skamil                                             bool stopped)
23101.1Skamil{
23111.51Skamil	/*
23121.51Skamil	 * notimeout - disable timeout in await zombie function
23131.51Skamil	 * unrelated - attach from unrelated tracer reparented to initproc
23141.67Skamil	 * stopped - attach to a stopped process
23151.51Skamil	 */
23161.1Skamil
23171.1Skamil	struct msg_fds parent_tracee, parent_tracer;
23181.1Skamil	const int exitval_tracee = 5;
23191.1Skamil	const int exitval_tracer = 10;
23201.1Skamil	pid_t tracee, tracer, wpid;
23211.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
23221.1Skamil#if defined(TWAIT_HAVE_STATUS)
23231.1Skamil	int status;
23241.1Skamil#endif
23251.1Skamil
23261.67Skamil	/*
23271.67Skamil	 * Only a subset of options are supported.
23281.67Skamil	 */
23291.67Skamil	ATF_REQUIRE((!notimeout && !unrelated && !stopped) ||
23301.67Skamil	            (!notimeout && unrelated && !stopped) ||
23311.67Skamil	            (notimeout && !unrelated && !stopped) ||
23321.67Skamil	            (!notimeout && unrelated && stopped));
23331.67Skamil
23341.13Schristos	DPRINTF("Spawn tracee\n");
23351.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
23361.1Skamil	tracee = atf_utils_fork();
23371.1Skamil	if (tracee == 0) {
23381.67Skamil		if (stopped) {
23391.67Skamil			DPRINTF("Stop self PID %d\n", getpid());
23401.67Skamil			raise(SIGSTOP);
23411.67Skamil		}
23421.67Skamil
23431.1Skamil		// Wait for parent to let us exit
23441.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
23451.1Skamil		_exit(exitval_tracee);
23461.1Skamil	}
23471.1Skamil
23481.13Schristos	DPRINTF("Spawn debugger\n");
23491.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
23501.1Skamil	tracer = atf_utils_fork();
23511.1Skamil	if (tracer == 0) {
23521.51Skamil		if(unrelated) {
23531.51Skamil			/* Fork again and drop parent to reattach to PID 1 */
23541.51Skamil			tracer = atf_utils_fork();
23551.51Skamil			if (tracer != 0)
23561.51Skamil				_exit(exitval_tracer);
23571.51Skamil		}
23581.51Skamil
23591.67Skamil		if (stopped) {
23601.67Skamil			DPRINTF("Await for a stopped parent PID %d\n", tracee);
23611.67Skamil			await_stopped(tracee);
23621.67Skamil		}
23631.67Skamil
23641.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
23651.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
23661.1Skamil
23671.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
23681.1Skamil		FORKEE_REQUIRE_SUCCESS(
23691.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
23701.1Skamil
23711.1Skamil		forkee_status_stopped(status, SIGSTOP);
23721.1Skamil
23731.1Skamil		/* Resume tracee with PT_CONTINUE */
23741.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
23751.1Skamil
23761.1Skamil		/* Inform parent that tracer has attached to tracee */
23771.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
23781.1Skamil
23791.1Skamil		/* Wait for parent to tell use that tracee should have exited */
23801.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
23811.1Skamil
23821.1Skamil		/* Wait for tracee and assert that it exited */
23831.1Skamil		FORKEE_REQUIRE_SUCCESS(
23841.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
23851.1Skamil
23861.1Skamil		forkee_status_exited(status, exitval_tracee);
23871.13Schristos		DPRINTF("Tracee %d exited with %d\n", tracee, exitval_tracee);
23881.1Skamil
23891.13Schristos		DPRINTF("Before exiting of the tracer process\n");
23901.51Skamil		_exit(unrelated ? 0 /* collect by initproc */ : exitval_tracer);
23911.51Skamil	}
23921.51Skamil
23931.51Skamil	if (unrelated) {
23941.51Skamil		DPRINTF("Wait for the tracer process (direct child) to exit "
23951.51Skamil		    "calling %s()\n", TWAIT_FNAME);
23961.51Skamil		TWAIT_REQUIRE_SUCCESS(
23971.51Skamil		    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
23981.51Skamil
23991.51Skamil		validate_status_exited(status, exitval_tracer);
24001.51Skamil
24011.51Skamil		DPRINTF("Wait for the non-exited tracee process with %s()\n",
24021.51Skamil		    TWAIT_FNAME);
24031.51Skamil		TWAIT_REQUIRE_SUCCESS(
24041.51Skamil		    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
24051.1Skamil	}
24061.1Skamil
24071.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
24081.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
24091.1Skamil
24101.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
24111.1Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
24121.1Skamil
24131.13Schristos	DPRINTF("Detect that tracee is zombie\n");
24141.51Skamil	if (notimeout)
24151.26Skamil		await_zombie_raw(tracee, 0);
24161.26Skamil	else
24171.26Skamil		await_zombie(tracee);
24181.1Skamil
24191.13Schristos	DPRINTF("Assert that there is no status about tracee %d - "
24201.1Skamil	    "Tracer must detect zombie first - calling %s()\n", tracee,
24211.1Skamil	    TWAIT_FNAME);
24221.1Skamil	TWAIT_REQUIRE_SUCCESS(
24231.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
24241.1Skamil
24251.51Skamil	if (unrelated) {
24261.51Skamil		DPRINTF("Resume the tracer and let it detect exited tracee\n");
24271.51Skamil		PARENT_TO_CHILD("Message 2", parent_tracer, msg);
24281.51Skamil	} else {
24291.51Skamil		DPRINTF("Tell the tracer child should have exited\n");
24301.51Skamil		PARENT_TO_CHILD("wait for tracee exit", parent_tracer,  msg);
24311.51Skamil		DPRINTF("Wait for tracer to finish its job and exit - calling "
24321.59Skamil			"%s()\n", TWAIT_FNAME);
24331.51Skamil
24341.51Skamil		DPRINTF("Wait from tracer child to complete waiting for "
24351.59Skamil			"tracee\n");
24361.51Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
24371.51Skamil		    tracer);
24381.1Skamil
24391.51Skamil		validate_status_exited(status, exitval_tracer);
24401.51Skamil	}
24411.1Skamil
24421.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
24431.1Skamil	    TWAIT_FNAME);
24441.51Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
24451.1Skamil
24461.1Skamil	validate_status_exited(status, exitval_tracee);
24471.1Skamil
24481.1Skamil	msg_close(&parent_tracer);
24491.1Skamil	msg_close(&parent_tracee);
24501.1Skamil}
24511.26Skamil
24521.51SkamilATF_TC(tracer_sees_terminaton_before_the_parent);
24531.51SkamilATF_TC_HEAD(tracer_sees_terminaton_before_the_parent, tc)
24541.51Skamil{
24551.51Skamil	atf_tc_set_md_var(tc, "descr",
24561.51Skamil	    "Assert that tracer sees process termination before the parent");
24571.51Skamil}
24581.51Skamil
24591.51SkamilATF_TC_BODY(tracer_sees_terminaton_before_the_parent, tc)
24601.26Skamil{
24611.26Skamil
24621.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, false, false);
24631.26Skamil}
24641.26Skamil
24651.51SkamilATF_TC(tracer_sysctl_lookup_without_duplicates);
24661.51SkamilATF_TC_HEAD(tracer_sysctl_lookup_without_duplicates, tc)
24671.1Skamil{
24681.164Skamil	atf_tc_set_md_var(tc, "timeout", "15");
24691.1Skamil	atf_tc_set_md_var(tc, "descr",
24701.51Skamil	    "Assert that await_zombie() in attach1 always finds a single "
24711.51Skamil	    "process and no other error is reported");
24721.1Skamil}
24731.1Skamil
24741.51SkamilATF_TC_BODY(tracer_sysctl_lookup_without_duplicates, tc)
24751.1Skamil{
24761.51Skamil	time_t start, end;
24771.51Skamil	double diff;
24781.51Skamil	unsigned long N = 0;
24791.1Skamil
24801.51Skamil	/*
24811.51Skamil	 * Reuse this test with tracer_sees_terminaton_before_the_parent_raw().
24821.51Skamil	 * This test body isn't specific to this race, however it's just good
24831.51Skamil	 * enough for this purposes, no need to invent a dedicated code flow.
24841.51Skamil	 */
24851.1Skamil
24861.51Skamil	start = time(NULL);
24871.51Skamil	while (true) {
24881.51Skamil		DPRINTF("Step: %lu\n", N);
24891.67Skamil		tracer_sees_terminaton_before_the_parent_raw(true, false,
24901.67Skamil		                                             false);
24911.51Skamil		end = time(NULL);
24921.51Skamil		diff = difftime(end, start);
24931.51Skamil		if (diff >= 5.0)
24941.51Skamil			break;
24951.51Skamil		++N;
24961.1Skamil	}
24971.51Skamil	DPRINTF("Iterations: %lu\n", N);
24981.51Skamil}
24991.1Skamil
25001.51SkamilATF_TC(unrelated_tracer_sees_terminaton_before_the_parent);
25011.51SkamilATF_TC_HEAD(unrelated_tracer_sees_terminaton_before_the_parent, tc)
25021.51Skamil{
25031.51Skamil	atf_tc_set_md_var(tc, "descr",
25041.51Skamil	    "Assert that tracer sees process termination before the parent");
25051.51Skamil}
25061.1Skamil
25071.51SkamilATF_TC_BODY(unrelated_tracer_sees_terminaton_before_the_parent, tc)
25081.51Skamil{
25091.1Skamil
25101.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, false);
25111.67Skamil}
25121.67Skamil
25131.67SkamilATF_TC(tracer_attach_to_unrelated_stopped_process);
25141.67SkamilATF_TC_HEAD(tracer_attach_to_unrelated_stopped_process, tc)
25151.67Skamil{
25161.67Skamil	atf_tc_set_md_var(tc, "descr",
25171.67Skamil	    "Assert that tracer can attach to an unrelated stopped process");
25181.67Skamil}
25191.67Skamil
25201.67SkamilATF_TC_BODY(tracer_attach_to_unrelated_stopped_process, tc)
25211.67Skamil{
25221.67Skamil
25231.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, true);
25241.1Skamil}
25251.1Skamil#endif
25261.1Skamil
25271.51Skamil/// ----------------------------------------------------------------------------
25281.51Skamil
25291.66Skamilstatic void
25301.66Skamilparent_attach_to_its_child(bool stopped)
25311.1Skamil{
25321.1Skamil	struct msg_fds parent_tracee;
25331.1Skamil	const int exitval_tracee = 5;
25341.1Skamil	pid_t tracee, wpid;
25351.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
25361.1Skamil#if defined(TWAIT_HAVE_STATUS)
25371.1Skamil	int status;
25381.1Skamil#endif
25391.1Skamil
25401.13Schristos	DPRINTF("Spawn tracee\n");
25411.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
25421.1Skamil	tracee = atf_utils_fork();
25431.1Skamil	if (tracee == 0) {
25441.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
25451.13Schristos		DPRINTF("Parent should now attach to tracee\n");
25461.1Skamil
25471.66Skamil		if (stopped) {
25481.66Skamil			DPRINTF("Stop self PID %d\n", getpid());
25491.66Skamil			SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
25501.66Skamil		}
25511.66Skamil
25521.1Skamil		CHILD_FROM_PARENT("Message 2", parent_tracee, msg);
25531.1Skamil		/* Wait for message from the parent */
25541.1Skamil		_exit(exitval_tracee);
25551.1Skamil	}
25561.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
25571.57Skamil
25581.66Skamil	if (stopped) {
25591.66Skamil		DPRINTF("Await for a stopped tracee PID %d\n", tracee);
25601.66Skamil		await_stopped(tracee);
25611.66Skamil	}
25621.66Skamil
25631.13Schristos	DPRINTF("Before calling PT_ATTACH for tracee %d\n", tracee);
25641.13Schristos	SYSCALL_REQUIRE(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
25651.1Skamil
25661.13Schristos	DPRINTF("Wait for the stopped tracee process with %s()\n",
25671.1Skamil	    TWAIT_FNAME);
25681.1Skamil	TWAIT_REQUIRE_SUCCESS(
25691.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
25701.1Skamil
25711.1Skamil	validate_status_stopped(status, SIGSTOP);
25721.1Skamil
25731.13Schristos	DPRINTF("Resume tracee with PT_CONTINUE\n");
25741.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
25751.1Skamil
25761.13Schristos	DPRINTF("Let the tracee exit now\n");
25771.1Skamil	PARENT_TO_CHILD("Message 2", parent_tracee, msg);
25781.1Skamil
25791.13Schristos	DPRINTF("Wait for tracee to exit with %s()\n", TWAIT_FNAME);
25801.1Skamil	TWAIT_REQUIRE_SUCCESS(
25811.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
25821.1Skamil
25831.1Skamil	validate_status_exited(status, exitval_tracee);
25841.1Skamil
25851.13Schristos	DPRINTF("Before calling %s() for tracee\n", TWAIT_FNAME);
25861.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
25871.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0));
25881.1Skamil
25891.1Skamil	msg_close(&parent_tracee);
25901.1Skamil}
25911.1Skamil
25921.66SkamilATF_TC(parent_attach_to_its_child);
25931.66SkamilATF_TC_HEAD(parent_attach_to_its_child, tc)
25941.66Skamil{
25951.66Skamil	atf_tc_set_md_var(tc, "descr",
25961.66Skamil	    "Assert that tracer parent can PT_ATTACH to its child");
25971.66Skamil}
25981.66Skamil
25991.66SkamilATF_TC_BODY(parent_attach_to_its_child, tc)
26001.66Skamil{
26011.66Skamil
26021.66Skamil	parent_attach_to_its_child(false);
26031.66Skamil}
26041.66Skamil
26051.66SkamilATF_TC(parent_attach_to_its_stopped_child);
26061.66SkamilATF_TC_HEAD(parent_attach_to_its_stopped_child, tc)
26071.66Skamil{
26081.66Skamil	atf_tc_set_md_var(tc, "descr",
26091.66Skamil	    "Assert that tracer parent can PT_ATTACH to its stopped child");
26101.66Skamil}
26111.66Skamil
26121.66SkamilATF_TC_BODY(parent_attach_to_its_stopped_child, tc)
26131.66Skamil{
26141.66Skamil
26151.66Skamil	parent_attach_to_its_child(true);
26161.66Skamil}
26171.66Skamil
26181.51Skamil/// ----------------------------------------------------------------------------
26191.51Skamil
26201.65Skamilstatic void
26211.65Skamilchild_attach_to_its_parent(bool stopped)
26221.1Skamil{
26231.1Skamil	struct msg_fds parent_tracee;
26241.1Skamil	const int exitval_tracer = 5;
26251.1Skamil	pid_t tracer, wpid;
26261.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
26271.1Skamil#if defined(TWAIT_HAVE_STATUS)
26281.1Skamil	int status;
26291.1Skamil#endif
26301.1Skamil
26311.13Schristos	DPRINTF("Spawn tracer\n");
26321.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
26331.1Skamil	tracer = atf_utils_fork();
26341.1Skamil	if (tracer == 0) {
26351.1Skamil		/* Wait for message from the parent */
26361.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
26371.1Skamil
26381.65Skamil		if (stopped) {
26391.65Skamil			DPRINTF("Await for a stopped parent PID %d\n",
26401.65Skamil			        getppid());
26411.65Skamil			await_stopped(getppid());
26421.65Skamil		}
26431.65Skamil
26441.13Schristos		DPRINTF("Attach to parent PID %d with PT_ATTACH from child\n",
26451.1Skamil		    getppid());
26461.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, getppid(), NULL, 0) != -1);
26471.1Skamil
26481.13Schristos		DPRINTF("Wait for the stopped parent process with %s()\n",
26491.1Skamil		    TWAIT_FNAME);
26501.1Skamil		FORKEE_REQUIRE_SUCCESS(
26511.1Skamil		    wpid = TWAIT_GENERIC(getppid(), &status, 0), getppid());
26521.1Skamil
26531.1Skamil		forkee_status_stopped(status, SIGSTOP);
26541.1Skamil
26551.13Schristos		DPRINTF("Resume parent with PT_DETACH\n");
26561.1Skamil		FORKEE_ASSERT(ptrace(PT_DETACH, getppid(), (void *)1, 0)
26571.1Skamil		    != -1);
26581.1Skamil
26591.1Skamil		/* Tell parent we are ready */
26601.1Skamil		CHILD_TO_PARENT("Message 1", parent_tracee, msg);
26611.1Skamil
26621.1Skamil		_exit(exitval_tracer);
26631.1Skamil	}
26641.1Skamil
26651.13Schristos	DPRINTF("Wait for the tracer to become ready\n");
26661.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
26671.65Skamil
26681.65Skamil	if (stopped) {
26691.65Skamil		DPRINTF("Stop self PID %d\n", getpid());
26701.65Skamil		SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
26711.65Skamil	}
26721.65Skamil
26731.13Schristos	DPRINTF("Allow the tracer to exit now\n");
26741.1Skamil	PARENT_FROM_CHILD("Message 1", parent_tracee, msg);
26751.1Skamil
26761.13Schristos	DPRINTF("Wait for tracer to exit with %s()\n", TWAIT_FNAME);
26771.1Skamil	TWAIT_REQUIRE_SUCCESS(
26781.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
26791.1Skamil
26801.1Skamil	validate_status_exited(status, exitval_tracer);
26811.1Skamil
26821.13Schristos	DPRINTF("Before calling %s() for tracer\n", TWAIT_FNAME);
26831.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
26841.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0));
26851.1Skamil
26861.1Skamil	msg_close(&parent_tracee);
26871.1Skamil}
26881.1Skamil
26891.65SkamilATF_TC(child_attach_to_its_parent);
26901.65SkamilATF_TC_HEAD(child_attach_to_its_parent, tc)
26911.65Skamil{
26921.65Skamil	atf_tc_set_md_var(tc, "descr",
26931.65Skamil	    "Assert that tracer child can PT_ATTACH to its parent");
26941.65Skamil}
26951.65Skamil
26961.65SkamilATF_TC_BODY(child_attach_to_its_parent, tc)
26971.65Skamil{
26981.65Skamil
26991.65Skamil	child_attach_to_its_parent(false);
27001.65Skamil}
27011.65Skamil
27021.65SkamilATF_TC(child_attach_to_its_stopped_parent);
27031.65SkamilATF_TC_HEAD(child_attach_to_its_stopped_parent, tc)
27041.65Skamil{
27051.65Skamil	atf_tc_set_md_var(tc, "descr",
27061.65Skamil	    "Assert that tracer child can PT_ATTACH to its stopped parent");
27071.65Skamil}
27081.65Skamil
27091.65SkamilATF_TC_BODY(child_attach_to_its_stopped_parent, tc)
27101.65Skamil{
27111.65Skamil	/*
27121.65Skamil	 * The ATF framework (atf-run) does not tolerate raise(SIGSTOP), as
27131.65Skamil	 * this causes a pipe (established from atf-run) to be broken.
27141.65Skamil	 * atf-run uses this mechanism to monitor whether a test is alive.
27151.65Skamil	 *
27161.65Skamil	 * As a workaround spawn this test as a subprocess.
27171.65Skamil	 */
27181.65Skamil
27191.65Skamil	const int exitval = 15;
27201.65Skamil	pid_t child, wpid;
27211.65Skamil#if defined(TWAIT_HAVE_STATUS)
27221.65Skamil	int status;
27231.65Skamil#endif
27241.65Skamil
27251.65Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
27261.65Skamil	if (child == 0) {
27271.65Skamil		child_attach_to_its_parent(true);
27281.65Skamil		_exit(exitval);
27291.65Skamil	} else {
27301.65Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
27311.65Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
27321.65Skamil
27331.65Skamil		validate_status_exited(status, exitval);
27341.65Skamil
27351.65Skamil		DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
27361.65Skamil		TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
27371.65Skamil	}
27381.65Skamil}
27391.65Skamil
27401.51Skamil/// ----------------------------------------------------------------------------
27411.51Skamil
27421.1Skamil#if defined(TWAIT_HAVE_PID)
27431.1Skamil
27441.51Skamilenum tracee_sees_its_original_parent_type {
27451.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
27461.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
27471.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS
27481.51Skamil};
27491.51Skamil
27501.51Skamilstatic void
27511.51Skamiltracee_sees_its_original_parent(enum tracee_sees_its_original_parent_type type)
27521.1Skamil{
27531.1Skamil	struct msg_fds parent_tracer, parent_tracee;
27541.1Skamil	const int exitval_tracee = 5;
27551.1Skamil	const int exitval_tracer = 10;
27561.1Skamil	pid_t parent, tracee, tracer, wpid;
27571.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
27581.1Skamil#if defined(TWAIT_HAVE_STATUS)
27591.1Skamil	int status;
27601.1Skamil#endif
27611.51Skamil	/* sysctl(3) - kinfo_proc2 */
27621.51Skamil	int name[CTL_MAXNAME];
27631.51Skamil	struct kinfo_proc2 kp;
27641.51Skamil	size_t len = sizeof(kp);
27651.51Skamil	unsigned int namelen;
27661.51Skamil
27671.51Skamil	/* procfs - status  */
27681.51Skamil	FILE *fp;
27691.51Skamil	struct stat st;
27701.51Skamil	const char *fname = "/proc/curproc/status";
27711.51Skamil	char s_executable[MAXPATHLEN];
27721.51Skamil	int s_pid, s_ppid;
27731.51Skamil	int rv;
27741.51Skamil
27751.51Skamil	if (type == TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS) {
27761.61Skre		SYSCALL_REQUIRE(
27771.61Skre		    (rv = stat(fname, &st)) == 0 || (errno == ENOENT));
27781.61Skre		if (rv != 0)
27791.51Skamil			atf_tc_skip("/proc/curproc/status not found");
27801.51Skamil	}
27811.1Skamil
27821.13Schristos	DPRINTF("Spawn tracee\n");
27831.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
27841.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
27851.1Skamil	tracee = atf_utils_fork();
27861.1Skamil	if (tracee == 0) {
27871.1Skamil		parent = getppid();
27881.1Skamil
27891.1Skamil		/* Emit message to the parent */
27901.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
27911.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
27921.1Skamil
27931.51Skamil		switch (type) {
27941.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID:
27951.51Skamil			FORKEE_ASSERT_EQ(parent, getppid());
27961.51Skamil			break;
27971.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2:
27981.51Skamil			namelen = 0;
27991.51Skamil			name[namelen++] = CTL_KERN;
28001.51Skamil			name[namelen++] = KERN_PROC2;
28011.51Skamil			name[namelen++] = KERN_PROC_PID;
28021.51Skamil			name[namelen++] = getpid();
28031.51Skamil			name[namelen++] = len;
28041.51Skamil			name[namelen++] = 1;
28051.51Skamil
28061.61Skre			FORKEE_ASSERT_EQ(
28071.61Skre			    sysctl(name, namelen, &kp, &len, NULL, 0), 0);
28081.51Skamil			FORKEE_ASSERT_EQ(parent, kp.p_ppid);
28091.51Skamil			break;
28101.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS:
28111.51Skamil			/*
28121.51Skamil			 * Format:
28131.51Skamil			 *  EXECUTABLE PID PPID ...
28141.51Skamil			 */
28151.51Skamil			FORKEE_ASSERT((fp = fopen(fname, "r")) != NULL);
28161.51Skamil			fscanf(fp, "%s %d %d", s_executable, &s_pid, &s_ppid);
28171.51Skamil			FORKEE_ASSERT_EQ(fclose(fp), 0);
28181.51Skamil			FORKEE_ASSERT_EQ(parent, s_ppid);
28191.51Skamil			break;
28201.51Skamil		}
28211.1Skamil
28221.1Skamil		_exit(exitval_tracee);
28231.1Skamil	}
28241.13Schristos	DPRINTF("Wait for child to record its parent identifier (pid)\n");
28251.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
28261.1Skamil
28271.13Schristos	DPRINTF("Spawn debugger\n");
28281.1Skamil	tracer = atf_utils_fork();
28291.1Skamil	if (tracer == 0) {
28301.1Skamil		/* No IPC to communicate with the child */
28311.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
28321.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
28331.1Skamil
28341.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
28351.1Skamil		FORKEE_REQUIRE_SUCCESS(
28361.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
28371.1Skamil
28381.1Skamil		forkee_status_stopped(status, SIGSTOP);
28391.1Skamil
28401.1Skamil		/* Resume tracee with PT_CONTINUE */
28411.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
28421.1Skamil
28431.1Skamil		/* Inform parent that tracer has attached to tracee */
28441.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
28451.1Skamil
28461.1Skamil		/* Wait for parent to tell use that tracee should have exited */
28471.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
28481.1Skamil
28491.1Skamil		/* Wait for tracee and assert that it exited */
28501.1Skamil		FORKEE_REQUIRE_SUCCESS(
28511.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
28521.1Skamil
28531.1Skamil		forkee_status_exited(status, exitval_tracee);
28541.1Skamil
28551.13Schristos		DPRINTF("Before exiting of the tracer process\n");
28561.1Skamil		_exit(exitval_tracer);
28571.1Skamil	}
28581.1Skamil
28591.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
28601.1Skamil	PARENT_FROM_CHILD("tracer ready",  parent_tracer, msg);
28611.1Skamil
28621.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
28631.1Skamil	PARENT_TO_CHILD("exit tracee",  parent_tracee, msg);
28641.1Skamil
28651.13Schristos	DPRINTF("Detect that tracee is zombie\n");
28661.1Skamil	await_zombie(tracee);
28671.1Skamil
28681.13Schristos	DPRINTF("Assert that there is no status about tracee - "
28691.1Skamil	    "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
28701.1Skamil	TWAIT_REQUIRE_SUCCESS(
28711.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
28721.1Skamil
28731.13Schristos	DPRINTF("Tell the tracer child should have exited\n");
28741.1Skamil	PARENT_TO_CHILD("wait for tracee exit",  parent_tracer, msg);
28751.1Skamil
28761.13Schristos	DPRINTF("Wait from tracer child to complete waiting for tracee\n");
28771.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
28781.1Skamil	    tracer);
28791.1Skamil
28801.1Skamil	validate_status_exited(status, exitval_tracer);
28811.1Skamil
28821.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
28831.1Skamil	    TWAIT_FNAME);
28841.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
28851.1Skamil	    tracee);
28861.1Skamil
28871.1Skamil	validate_status_exited(status, exitval_tracee);
28881.1Skamil
28891.1Skamil	msg_close(&parent_tracer);
28901.1Skamil	msg_close(&parent_tracee);
28911.1Skamil}
28921.1Skamil
28931.61Skre#define TRACEE_SEES_ITS_ORIGINAL_PARENT(test, type, descr)		\
28941.61SkreATF_TC(test);								\
28951.61SkreATF_TC_HEAD(test, tc)							\
28961.61Skre{									\
28971.61Skre	atf_tc_set_md_var(tc, "descr",					\
28981.61Skre	    "Assert that tracee sees its original parent when being traced " \
28991.61Skre	    "(check " descr ")");					\
29001.61Skre}									\
29011.61Skre									\
29021.61SkreATF_TC_BODY(test, tc)							\
29031.61Skre{									\
29041.61Skre									\
29051.61Skre	tracee_sees_its_original_parent(type);				\
29061.1Skamil}
29071.1Skamil
29081.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29091.51Skamil	tracee_sees_its_original_parent_getppid,
29101.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
29111.51Skamil	"getppid(2)");
29121.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29131.51Skamil	tracee_sees_its_original_parent_sysctl_kinfo_proc2,
29141.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
29151.51Skamil	"sysctl(3) and kinfo_proc2");
29161.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
29171.51Skamil	tracee_sees_its_original_parent_procfs_status,
29181.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS,
29191.51Skamil	"the status file in procfs");
29201.1Skamil#endif
29211.1Skamil
29221.51Skamil/// ----------------------------------------------------------------------------
29231.1Skamil
29241.53Skamilstatic void
29251.53Skamileventmask_preserved(int event)
29261.1Skamil{
29271.1Skamil	const int exitval = 5;
29281.1Skamil	const int sigval = SIGSTOP;
29291.1Skamil	pid_t child, wpid;
29301.1Skamil#if defined(TWAIT_HAVE_STATUS)
29311.1Skamil	int status;
29321.1Skamil#endif
29331.1Skamil	ptrace_event_t set_event, get_event;
29341.1Skamil	const int len = sizeof(ptrace_event_t);
29351.1Skamil
29361.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
29371.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
29381.1Skamil	if (child == 0) {
29391.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
29401.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
29411.1Skamil
29421.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
29431.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
29441.1Skamil
29451.13Schristos		DPRINTF("Before exiting of the child process\n");
29461.1Skamil		_exit(exitval);
29471.1Skamil	}
29481.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
29491.1Skamil
29501.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29511.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
29521.1Skamil
29531.1Skamil	validate_status_stopped(status, sigval);
29541.1Skamil
29551.53Skamil	set_event.pe_set_event = event;
29561.61Skre	SYSCALL_REQUIRE(
29571.61Skre	    ptrace(PT_SET_EVENT_MASK, child, &set_event, len) != -1);
29581.61Skre	SYSCALL_REQUIRE(
29591.61Skre	    ptrace(PT_GET_EVENT_MASK, child, &get_event, len) != -1);
29601.125Skamil	DPRINTF("set_event=%#x get_event=%#x\n", set_event.pe_set_event,
29611.125Skamil	    get_event.pe_set_event);
29621.1Skamil	ATF_REQUIRE(memcmp(&set_event, &get_event, len) == 0);
29631.1Skamil
29641.13Schristos	DPRINTF("Before resuming the child process where it left off and "
29651.1Skamil	    "without signal to be sent\n");
29661.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
29671.1Skamil
29681.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29691.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
29701.1Skamil
29711.1Skamil	validate_status_exited(status, exitval);
29721.1Skamil
29731.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
29741.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
29751.1Skamil}
29761.1Skamil
29771.61Skre#define EVENTMASK_PRESERVED(test, event)				\
29781.61SkreATF_TC(test);								\
29791.61SkreATF_TC_HEAD(test, tc)							\
29801.61Skre{									\
29811.61Skre	atf_tc_set_md_var(tc, "descr",					\
29821.61Skre	    "Verify that eventmask " #event " is preserved");		\
29831.61Skre}									\
29841.61Skre									\
29851.61SkreATF_TC_BODY(test, tc)							\
29861.61Skre{									\
29871.61Skre									\
29881.61Skre	eventmask_preserved(event);					\
29891.1Skamil}
29901.1Skamil
29911.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_empty, 0)
29921.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_fork, PTRACE_FORK)
29931.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_vfork, PTRACE_VFORK)
29941.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_vfork_done, PTRACE_VFORK_DONE)
29951.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_lwp_create, PTRACE_LWP_CREATE)
29961.53SkamilEVENTMASK_PRESERVED(eventmask_preserved_lwp_exit, PTRACE_LWP_EXIT)
29971.125SkamilEVENTMASK_PRESERVED(eventmask_preserved_posix_spawn, PTRACE_POSIX_SPAWN)
29981.1Skamil
29991.53Skamil/// ----------------------------------------------------------------------------
30001.1Skamil
30011.28Skamilstatic void
30021.125Skamilfork_body(const char *fn, bool trackspawn, bool trackfork, bool trackvfork,
30031.105Skamil    bool trackvforkdone)
30041.1Skamil{
30051.1Skamil	const int exitval = 5;
30061.125Skamil	const int exitval2 = 0; /* This matched exit status from /bin/echo */
30071.1Skamil	const int sigval = SIGSTOP;
30081.31Skamil	pid_t child, child2 = 0, wpid;
30091.1Skamil#if defined(TWAIT_HAVE_STATUS)
30101.1Skamil	int status;
30111.1Skamil#endif
30121.1Skamil	ptrace_state_t state;
30131.1Skamil	const int slen = sizeof(state);
30141.1Skamil	ptrace_event_t event;
30151.1Skamil	const int elen = sizeof(event);
30161.1Skamil
30171.124Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
30181.124Skamil
30191.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
30201.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
30211.1Skamil	if (child == 0) {
30221.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
30231.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
30241.1Skamil
30251.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
30261.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
30271.1Skamil
30281.125Skamil		if (strcmp(fn, "spawn") == 0) {
30291.124Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
30301.124Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
30311.125Skamil		} else {
30321.125Skamil			if (strcmp(fn, "fork") == 0) {
30331.125Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
30341.125Skamil			} else if (strcmp(fn, "vfork") == 0) {
30351.125Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
30361.125Skamil			}
30371.1Skamil
30381.124Skamil			if (child2 == 0)
30391.124Skamil				_exit(exitval2);
30401.124Skamil		}
30411.1Skamil		FORKEE_REQUIRE_SUCCESS
30421.1Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
30431.1Skamil
30441.1Skamil		forkee_status_exited(status, exitval2);
30451.1Skamil
30461.13Schristos		DPRINTF("Before exiting of the child process\n");
30471.1Skamil		_exit(exitval);
30481.1Skamil	}
30491.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
30501.1Skamil
30511.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
30521.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
30531.1Skamil
30541.1Skamil	validate_status_stopped(status, sigval);
30551.1Skamil
30561.125Skamil	DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
30571.125Skamil	    trackspawn ? "|PTRACE_POSIX_SPAWN" : "",
30581.61Skre	    trackfork ? "|PTRACE_FORK" : "",
30591.61Skre	    trackvfork ? "|PTRACE_VFORK" : "",
30601.61Skre	    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", child);
30611.30Skamil	event.pe_set_event = 0;
30621.125Skamil	if (trackspawn)
30631.125Skamil		event.pe_set_event |= PTRACE_POSIX_SPAWN;
30641.30Skamil	if (trackfork)
30651.30Skamil		event.pe_set_event |= PTRACE_FORK;
30661.30Skamil	if (trackvfork)
30671.30Skamil		event.pe_set_event |= PTRACE_VFORK;
30681.30Skamil	if (trackvforkdone)
30691.30Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
30701.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
30711.1Skamil
30721.13Schristos	DPRINTF("Before resuming the child process where it left off and "
30731.1Skamil	    "without signal to be sent\n");
30741.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
30751.1Skamil
30761.29Skamil#if defined(TWAIT_HAVE_PID)
30771.125Skamil	if ((trackspawn && strcmp(fn, "spawn") == 0) ||
30781.125Skamil	    (trackfork && strcmp(fn, "fork") == 0) ||
30791.125Skamil	    (trackvfork && strcmp(fn, "vfork") == 0)) {
30801.29Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
30811.61Skre		    child);
30821.29Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
30831.61Skre		    child);
30841.1Skamil
30851.29Skamil		validate_status_stopped(status, SIGTRAP);
30861.1Skamil
30871.61Skre		SYSCALL_REQUIRE(
30881.61Skre		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
30891.125Skamil		if (trackspawn && strcmp(fn, "spawn") == 0) {
30901.125Skamil			ATF_REQUIRE_EQ(
30911.125Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
30921.125Skamil			       PTRACE_POSIX_SPAWN);
30931.125Skamil		}
30941.125Skamil		if (trackfork && strcmp(fn, "fork") == 0) {
30951.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
30961.30Skamil			       PTRACE_FORK);
30971.30Skamil		}
30981.125Skamil		if (trackvfork && strcmp(fn, "vfork") == 0) {
30991.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
31001.30Skamil			       PTRACE_VFORK);
31011.30Skamil		}
31021.29Skamil
31031.29Skamil		child2 = state.pe_other_pid;
31041.30Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
31051.29Skamil
31061.29Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
31071.61Skre		    "%d\n", TWAIT_FNAME, child2, child);
31081.29Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
31091.29Skamil		    child2);
31101.1Skamil
31111.29Skamil		validate_status_stopped(status, SIGTRAP);
31121.1Skamil
31131.61Skre		SYSCALL_REQUIRE(
31141.61Skre		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
31151.125Skamil		if (trackspawn && strcmp(fn, "spawn") == 0) {
31161.125Skamil			ATF_REQUIRE_EQ(
31171.125Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
31181.125Skamil			       PTRACE_POSIX_SPAWN);
31191.125Skamil		}
31201.125Skamil		if (trackfork && strcmp(fn, "fork") == 0) {
31211.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
31221.30Skamil			       PTRACE_FORK);
31231.30Skamil		}
31241.125Skamil		if (trackvfork && strcmp(fn, "vfork") == 0) {
31251.30Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
31261.30Skamil			       PTRACE_VFORK);
31271.30Skamil		}
31281.30Skamil
31291.29Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
31301.29Skamil
31311.29Skamil		DPRINTF("Before resuming the forkee process where it left off "
31321.29Skamil		    "and without signal to be sent\n");
31331.61Skre		SYSCALL_REQUIRE(
31341.61Skre		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
31351.29Skamil
31361.29Skamil		DPRINTF("Before resuming the child process where it left off "
31371.61Skre		    "and without signal to be sent\n");
31381.29Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31391.30Skamil	}
31401.30Skamil#endif
31411.30Skamil
31421.125Skamil	if (trackvforkdone && strcmp(fn, "vfork") == 0) {
31431.30Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
31441.61Skre		    child);
31451.61Skre		TWAIT_REQUIRE_SUCCESS(
31461.61Skre		    wpid = TWAIT_GENERIC(child, &status, 0), child);
31471.30Skamil
31481.30Skamil		validate_status_stopped(status, SIGTRAP);
31491.30Skamil
31501.61Skre		SYSCALL_REQUIRE(
31511.61Skre		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
31521.30Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
31531.30Skamil
31541.30Skamil		child2 = state.pe_other_pid;
31551.30Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
31561.61Skre		    child2);
31571.30Skamil
31581.30Skamil		DPRINTF("Before resuming the child process where it left off "
31591.61Skre		    "and without signal to be sent\n");
31601.30Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31611.30Skamil	}
31621.29Skamil
31631.30Skamil#if defined(TWAIT_HAVE_PID)
31641.125Skamil	if ((trackspawn && strcmp(fn, "spawn") == 0) ||
31651.125Skamil	    (trackfork && strcmp(fn, "fork") == 0) ||
31661.125Skamil	    (trackvfork && strcmp(fn, "vfork") == 0)) {
31671.29Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
31681.61Skre		    "\n", TWAIT_FNAME);
31691.61Skre		TWAIT_REQUIRE_SUCCESS(
31701.61Skre		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
31711.29Skamil
31721.29Skamil		validate_status_exited(status, exitval2);
31731.29Skamil
31741.29Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
31751.61Skre		    "process\n", TWAIT_FNAME);
31761.29Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
31771.29Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
31781.29Skamil	}
31791.29Skamil#endif
31801.1Skamil
31811.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
31821.1Skamil	    "SIGCHLD\n", TWAIT_FNAME);
31831.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
31841.1Skamil
31851.1Skamil	validate_status_stopped(status, SIGCHLD);
31861.1Skamil
31871.13Schristos	DPRINTF("Before resuming the child process where it left off and "
31881.1Skamil	    "without signal to be sent\n");
31891.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31901.1Skamil
31911.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
31921.1Skamil	    TWAIT_FNAME);
31931.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
31941.1Skamil
31951.1Skamil	validate_status_exited(status, exitval);
31961.1Skamil
31971.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
31981.1Skamil	    TWAIT_FNAME);
31991.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
32001.1Skamil}
32011.28Skamil
32021.125Skamil#define FORK_TEST(name,fun,tspawn,tfork,tvfork,tvforkdone)		\
32031.61SkreATF_TC(name);								\
32041.61SkreATF_TC_HEAD(name, tc)							\
32051.61Skre{									\
32061.125Skamil	atf_tc_set_md_var(tc, "descr", "Verify " fun "() "		\
32071.125Skamil	    "called with 0%s%s%s%s in EVENT_MASK",			\
32081.126Skamil	    tspawn ? "|PTRACE_POSIX_SPAWN" : "",			\
32091.105Skamil	    tfork ? "|PTRACE_FORK" : "",				\
32101.105Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
32111.105Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
32121.61Skre}									\
32131.61Skre									\
32141.61SkreATF_TC_BODY(name, tc)							\
32151.61Skre{									\
32161.61Skre									\
32171.125Skamil	fork_body(fun, tspawn, tfork, tvfork, tvforkdone);		\
32181.32Skamil}
32191.32Skamil
32201.125SkamilFORK_TEST(fork1, "fork", false, false, false, false)
32211.31Skamil#if defined(TWAIT_HAVE_PID)
32221.125SkamilFORK_TEST(fork2, "fork", false, true, false, false)
32231.125SkamilFORK_TEST(fork3, "fork", false, false, true, false)
32241.125SkamilFORK_TEST(fork4, "fork", false, true, true, false)
32251.31Skamil#endif
32261.125SkamilFORK_TEST(fork5, "fork", false, false, false, true)
32271.31Skamil#if defined(TWAIT_HAVE_PID)
32281.125SkamilFORK_TEST(fork6, "fork", false, true, false, true)
32291.125SkamilFORK_TEST(fork7, "fork", false, false, true, true)
32301.125SkamilFORK_TEST(fork8, "fork", false, true, true, true)
32311.125Skamil#endif
32321.125SkamilFORK_TEST(fork9, "fork", true, false, false, false)
32331.125Skamil#if defined(TWAIT_HAVE_PID)
32341.125SkamilFORK_TEST(fork10, "fork", true, true, false, false)
32351.125SkamilFORK_TEST(fork11, "fork", true, false, true, false)
32361.125SkamilFORK_TEST(fork12, "fork", true, true, true, false)
32371.125Skamil#endif
32381.125SkamilFORK_TEST(fork13, "fork", true, false, false, true)
32391.125Skamil#if defined(TWAIT_HAVE_PID)
32401.125SkamilFORK_TEST(fork14, "fork", true, true, false, true)
32411.125SkamilFORK_TEST(fork15, "fork", true, false, true, true)
32421.125SkamilFORK_TEST(fork16, "fork", true, true, true, true)
32431.31Skamil#endif
32441.1Skamil
32451.125SkamilFORK_TEST(vfork1, "vfork", false, false, false, false)
32461.31Skamil#if defined(TWAIT_HAVE_PID)
32471.125SkamilFORK_TEST(vfork2, "vfork", false, true, false, false)
32481.125SkamilFORK_TEST(vfork3, "vfork", false, false, true, false)
32491.125SkamilFORK_TEST(vfork4, "vfork", false, true, true, false)
32501.31Skamil#endif
32511.125SkamilFORK_TEST(vfork5, "vfork", false, false, false, true)
32521.31Skamil#if defined(TWAIT_HAVE_PID)
32531.125SkamilFORK_TEST(vfork6, "vfork", false, true, false, true)
32541.125SkamilFORK_TEST(vfork7, "vfork", false, false, true, true)
32551.125SkamilFORK_TEST(vfork8, "vfork", false, true, true, true)
32561.31Skamil#endif
32571.125SkamilFORK_TEST(vfork9, "vfork", true, false, false, false)
32581.125Skamil#if defined(TWAIT_HAVE_PID)
32591.125SkamilFORK_TEST(vfork10, "vfork", true, true, false, false)
32601.125SkamilFORK_TEST(vfork11, "vfork", true, false, true, false)
32611.125SkamilFORK_TEST(vfork12, "vfork", true, true, true, false)
32621.110Skamil#endif
32631.125SkamilFORK_TEST(vfork13, "vfork", true, false, false, true)
32641.124Skamil#if defined(TWAIT_HAVE_PID)
32651.125SkamilFORK_TEST(vfork14, "vfork", true, true, false, true)
32661.125SkamilFORK_TEST(vfork15, "vfork", true, false, true, true)
32671.125SkamilFORK_TEST(vfork16, "vfork", true, true, true, true)
32681.124Skamil#endif
32691.125Skamil
32701.125SkamilFORK_TEST(posix_spawn1, "spawn", false, false, false, false)
32711.125SkamilFORK_TEST(posix_spawn2, "spawn", false, true, false, false)
32721.125SkamilFORK_TEST(posix_spawn3, "spawn", false, false, true, false)
32731.125SkamilFORK_TEST(posix_spawn4, "spawn", false, true, true, false)
32741.125SkamilFORK_TEST(posix_spawn5, "spawn", false, false, false, true)
32751.125SkamilFORK_TEST(posix_spawn6, "spawn", false, true, false, true)
32761.125SkamilFORK_TEST(posix_spawn7, "spawn", false, false, true, true)
32771.125SkamilFORK_TEST(posix_spawn8, "spawn", false, true, true, true)
32781.124Skamil#if defined(TWAIT_HAVE_PID)
32791.125SkamilFORK_TEST(posix_spawn9, "spawn", true, false, false, false)
32801.125SkamilFORK_TEST(posix_spawn10, "spawn", true, true, false, false)
32811.125SkamilFORK_TEST(posix_spawn11, "spawn", true, false, true, false)
32821.125SkamilFORK_TEST(posix_spawn12, "spawn", true, true, true, false)
32831.125SkamilFORK_TEST(posix_spawn13, "spawn", true, false, false, true)
32841.125SkamilFORK_TEST(posix_spawn14, "spawn", true, true, false, true)
32851.125SkamilFORK_TEST(posix_spawn15, "spawn", true, false, true, true)
32861.125SkamilFORK_TEST(posix_spawn16, "spawn", true, true, true, true)
32871.124Skamil#endif
32881.124Skamil
32891.54Skamil/// ----------------------------------------------------------------------------
32901.31Skamil
32911.116Skamil#if defined(TWAIT_HAVE_PID)
32921.116Skamilstatic void
32931.149Skamilunrelated_tracer_fork_body(const char *fn, bool trackspawn, bool trackfork,
32941.149Skamil    bool trackvfork, bool trackvforkdone)
32951.149Skamil{
32961.149Skamil	const int sigval = SIGSTOP;
32971.149Skamil	struct msg_fds parent_tracee, parent_tracer;
32981.149Skamil	const int exitval = 10;
32991.149Skamil	const int exitval2 = 0; /* This matched exit status from /bin/echo */
33001.149Skamil	pid_t tracee, tracer, wpid;
33011.149Skamil	pid_t tracee2 = 0;
33021.149Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
33031.149Skamil#if defined(TWAIT_HAVE_STATUS)
33041.149Skamil	int status;
33051.149Skamil#endif
33061.149Skamil
33071.149Skamil	struct ptrace_siginfo info;
33081.149Skamil	ptrace_state_t state;
33091.149Skamil	const int slen = sizeof(state);
33101.149Skamil	ptrace_event_t event;
33111.149Skamil	const int elen = sizeof(event);
33121.149Skamil
33131.149Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
33141.149Skamil
33151.149Skamil	DPRINTF("Spawn tracee\n");
33161.149Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
33171.149Skamil	tracee = atf_utils_fork();
33181.149Skamil	if (tracee == 0) {
33191.149Skamil		// Wait for parent to let us crash
33201.149Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
33211.149Skamil
33221.149Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
33231.149Skamil		FORKEE_ASSERT(raise(sigval) == 0);
33241.149Skamil
33251.149Skamil		if (strcmp(fn, "spawn") == 0) {
33261.149Skamil			FORKEE_ASSERT_EQ(posix_spawn(&tracee2,
33271.149Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
33281.149Skamil		} else {
33291.149Skamil			if (strcmp(fn, "fork") == 0) {
33301.149Skamil				FORKEE_ASSERT((tracee2 = fork()) != -1);
33311.149Skamil			} else if (strcmp(fn, "vfork") == 0) {
33321.149Skamil				FORKEE_ASSERT((tracee2 = vfork()) != -1);
33331.149Skamil			}
33341.149Skamil
33351.149Skamil			if (tracee2 == 0)
33361.149Skamil				_exit(exitval2);
33371.149Skamil		}
33381.149Skamil		FORKEE_REQUIRE_SUCCESS
33391.149Skamil		    (wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
33401.149Skamil
33411.149Skamil		forkee_status_exited(status, exitval2);
33421.149Skamil
33431.149Skamil		DPRINTF("Before exiting of the child process\n");
33441.149Skamil		_exit(exitval);
33451.149Skamil	}
33461.149Skamil
33471.149Skamil	DPRINTF("Spawn debugger\n");
33481.149Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
33491.149Skamil	tracer = atf_utils_fork();
33501.149Skamil	if (tracer == 0) {
33511.149Skamil		/* Fork again and drop parent to reattach to PID 1 */
33521.149Skamil		tracer = atf_utils_fork();
33531.149Skamil		if (tracer != 0)
33541.149Skamil			_exit(exitval);
33551.149Skamil
33561.149Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
33571.149Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
33581.149Skamil
33591.149Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
33601.149Skamil		FORKEE_REQUIRE_SUCCESS(
33611.149Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
33621.149Skamil
33631.149Skamil		forkee_status_stopped(status, SIGSTOP);
33641.149Skamil
33651.149Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
33661.149Skamil		    "traced process\n");
33671.149Skamil		SYSCALL_REQUIRE(
33681.149Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
33691.149Skamil
33701.149Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
33711.149Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
33721.149Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
33731.149Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
33741.149Skamil
33751.149Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
33761.149Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
33771.149Skamil
33781.149Skamil		/* Resume tracee with PT_CONTINUE */
33791.149Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
33801.149Skamil
33811.149Skamil		/* Inform parent that tracer has attached to tracee */
33821.149Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
33831.149Skamil
33841.149Skamil		/* Wait for parent to tell use that tracee should have exited */
33851.149Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
33861.149Skamil
33871.149Skamil		/* Wait for tracee and assert that it exited */
33881.149Skamil		FORKEE_REQUIRE_SUCCESS(
33891.149Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
33901.149Skamil
33911.149Skamil		forkee_status_stopped(status, sigval);
33921.149Skamil
33931.149Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
33941.149Skamil		    "traced process\n");
33951.149Skamil		SYSCALL_REQUIRE(
33961.149Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
33971.149Skamil
33981.149Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
33991.149Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
34001.149Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
34011.149Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
34021.149Skamil
34031.149Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
34041.149Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
34051.149Skamil
34061.149Skamil		DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
34071.149Skamil		    trackspawn ? "|PTRACE_POSIX_SPAWN" : "",
34081.149Skamil		    trackfork ? "|PTRACE_FORK" : "",
34091.149Skamil		    trackvfork ? "|PTRACE_VFORK" : "",
34101.149Skamil		    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", tracee);
34111.149Skamil		event.pe_set_event = 0;
34121.149Skamil		if (trackspawn)
34131.149Skamil			event.pe_set_event |= PTRACE_POSIX_SPAWN;
34141.149Skamil		if (trackfork)
34151.149Skamil			event.pe_set_event |= PTRACE_FORK;
34161.149Skamil		if (trackvfork)
34171.149Skamil			event.pe_set_event |= PTRACE_VFORK;
34181.149Skamil		if (trackvforkdone)
34191.149Skamil			event.pe_set_event |= PTRACE_VFORK_DONE;
34201.149Skamil		SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, tracee, &event, elen)
34211.149Skamil		    != -1);
34221.149Skamil
34231.149Skamil		DPRINTF("Before resuming the child process where it left off "
34241.149Skamil		    "and without signal to be sent\n");
34251.149Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
34261.149Skamil
34271.149Skamil		if ((trackspawn && strcmp(fn, "spawn") == 0) ||
34281.149Skamil		    (trackfork && strcmp(fn, "fork") == 0) ||
34291.149Skamil		    (trackvfork && strcmp(fn, "vfork") == 0)) {
34301.149Skamil			DPRINTF("Before calling %s() for the tracee %d\n", TWAIT_FNAME,
34311.149Skamil			    tracee);
34321.149Skamil			TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0),
34331.149Skamil			    tracee);
34341.149Skamil
34351.149Skamil			validate_status_stopped(status, SIGTRAP);
34361.149Skamil
34371.149Skamil			SYSCALL_REQUIRE(
34381.149Skamil			    ptrace(PT_GET_PROCESS_STATE, tracee, &state, slen) != -1);
34391.149Skamil			if (trackspawn && strcmp(fn, "spawn") == 0) {
34401.149Skamil				ATF_REQUIRE_EQ(
34411.149Skamil				    state.pe_report_event & PTRACE_POSIX_SPAWN,
34421.149Skamil				       PTRACE_POSIX_SPAWN);
34431.149Skamil			}
34441.149Skamil			if (trackfork && strcmp(fn, "fork") == 0) {
34451.149Skamil				ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
34461.149Skamil				       PTRACE_FORK);
34471.149Skamil			}
34481.149Skamil			if (trackvfork && strcmp(fn, "vfork") == 0) {
34491.149Skamil				ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
34501.149Skamil				       PTRACE_VFORK);
34511.149Skamil			}
34521.149Skamil
34531.149Skamil			tracee2 = state.pe_other_pid;
34541.149Skamil			DPRINTF("Reported ptrace event with forkee %d\n", tracee2);
34551.149Skamil
34561.149Skamil			DPRINTF("Before calling %s() for the forkee %d of the tracee "
34571.149Skamil			    "%d\n", TWAIT_FNAME, tracee2, tracee);
34581.149Skamil			TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee2, &status, 0),
34591.149Skamil			    tracee2);
34601.149Skamil
34611.149Skamil			validate_status_stopped(status, SIGTRAP);
34621.149Skamil
34631.149Skamil			SYSCALL_REQUIRE(
34641.149Skamil			    ptrace(PT_GET_PROCESS_STATE, tracee2, &state, slen) != -1);
34651.149Skamil			if (trackspawn && strcmp(fn, "spawn") == 0) {
34661.149Skamil				ATF_REQUIRE_EQ(
34671.149Skamil				    state.pe_report_event & PTRACE_POSIX_SPAWN,
34681.149Skamil				       PTRACE_POSIX_SPAWN);
34691.149Skamil			}
34701.149Skamil			if (trackfork && strcmp(fn, "fork") == 0) {
34711.149Skamil				ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
34721.149Skamil				       PTRACE_FORK);
34731.149Skamil			}
34741.149Skamil			if (trackvfork && strcmp(fn, "vfork") == 0) {
34751.149Skamil				ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
34761.149Skamil				       PTRACE_VFORK);
34771.149Skamil			}
34781.149Skamil
34791.149Skamil			ATF_REQUIRE_EQ(state.pe_other_pid, tracee);
34801.149Skamil
34811.149Skamil			DPRINTF("Before resuming the forkee process where it left off "
34821.149Skamil			    "and without signal to be sent\n");
34831.149Skamil			SYSCALL_REQUIRE(
34841.149Skamil			    ptrace(PT_CONTINUE, tracee2, (void *)1, 0) != -1);
34851.149Skamil
34861.149Skamil			DPRINTF("Before resuming the tracee process where it left off "
34871.149Skamil			    "and without signal to be sent\n");
34881.149Skamil			SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
34891.149Skamil		}
34901.149Skamil
34911.149Skamil		if (trackvforkdone && strcmp(fn, "vfork") == 0) {
34921.149Skamil			DPRINTF("Before calling %s() for the tracee %d\n", TWAIT_FNAME,
34931.149Skamil			    tracee);
34941.149Skamil			TWAIT_REQUIRE_SUCCESS(
34951.149Skamil			    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
34961.149Skamil
34971.149Skamil			validate_status_stopped(status, SIGTRAP);
34981.149Skamil
34991.149Skamil			SYSCALL_REQUIRE(
35001.149Skamil			    ptrace(PT_GET_PROCESS_STATE, tracee, &state, slen) != -1);
35011.149Skamil			ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
35021.149Skamil
35031.149Skamil			tracee2 = state.pe_other_pid;
35041.149Skamil			DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
35051.149Skamil			    tracee2);
35061.149Skamil
35071.149Skamil			DPRINTF("Before resuming the tracee process where it left off "
35081.149Skamil			    "and without signal to be sent\n");
35091.149Skamil			SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
35101.149Skamil		}
35111.149Skamil
35121.149Skamil
35131.149Skamil		if ((trackspawn && strcmp(fn, "spawn") == 0) ||
35141.149Skamil		    (trackfork && strcmp(fn, "fork") == 0) ||
35151.149Skamil		    (trackvfork && strcmp(fn, "vfork") == 0)) {
35161.149Skamil			DPRINTF("Before calling %s() for the forkee - expected exited"
35171.149Skamil			    "\n", TWAIT_FNAME);
35181.149Skamil			TWAIT_REQUIRE_SUCCESS(
35191.149Skamil			    wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
35201.149Skamil
35211.149Skamil			validate_status_exited(status, exitval2);
35221.149Skamil
35231.149Skamil			DPRINTF("Before calling %s() for the forkee - expected no "
35241.149Skamil			    "process\n", TWAIT_FNAME);
35251.149Skamil			TWAIT_REQUIRE_FAILURE(ECHILD,
35261.149Skamil			    wpid = TWAIT_GENERIC(tracee2, &status, 0));
35271.149Skamil		}
35281.149Skamil
35291.149Skamil		DPRINTF("Before calling %s() for the tracee - expected stopped "
35301.149Skamil		    "SIGCHLD\n", TWAIT_FNAME);
35311.149Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
35321.149Skamil
35331.149Skamil		validate_status_stopped(status, SIGCHLD);
35341.149Skamil
35351.149Skamil		DPRINTF("Before resuming the tracee process where it left off and "
35361.149Skamil		    "without signal to be sent\n");
35371.149Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
35381.149Skamil
35391.149Skamil		DPRINTF("Before calling %s() for the tracee - expected exited\n",
35401.149Skamil		    TWAIT_FNAME);
35411.149Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
35421.149Skamil
35431.149Skamil		validate_status_exited(status, exitval);
35441.149Skamil
35451.149Skamil		/* Inform parent that tracer is exiting normally */
35461.149Skamil		CHILD_TO_PARENT("tracer done", parent_tracer, msg);
35471.149Skamil
35481.149Skamil		DPRINTF("Before exiting of the tracer process\n");
35491.149Skamil		_exit(0 /* collect by initproc */);
35501.149Skamil	}
35511.149Skamil
35521.149Skamil	DPRINTF("Wait for the tracer process (direct child) to exit "
35531.149Skamil	    "calling %s()\n", TWAIT_FNAME);
35541.149Skamil	TWAIT_REQUIRE_SUCCESS(
35551.149Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
35561.149Skamil
35571.149Skamil	validate_status_exited(status, exitval);
35581.149Skamil
35591.149Skamil	DPRINTF("Wait for the non-exited tracee process with %s()\n",
35601.149Skamil	    TWAIT_FNAME);
35611.149Skamil	TWAIT_REQUIRE_SUCCESS(
35621.149Skamil	    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
35631.149Skamil
35641.149Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
35651.149Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
35661.149Skamil
35671.149Skamil	DPRINTF("Resume the tracee and let it crash\n");
35681.149Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
35691.149Skamil
35701.149Skamil	DPRINTF("Resume the tracer and let it detect crashed tracee\n");
35711.149Skamil	PARENT_TO_CHILD("Message 2", parent_tracer, msg);
35721.149Skamil
35731.149Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
35741.149Skamil	    TWAIT_FNAME);
35751.149Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
35761.149Skamil
35771.149Skamil	validate_status_exited(status, exitval);
35781.149Skamil
35791.149Skamil	DPRINTF("Await normal exit of tracer\n");
35801.149Skamil	PARENT_FROM_CHILD("tracer done", parent_tracer, msg);
35811.149Skamil
35821.149Skamil	msg_close(&parent_tracer);
35831.149Skamil	msg_close(&parent_tracee);
35841.149Skamil}
35851.149Skamil
35861.149Skamil#define UNRELATED_TRACER_FORK_TEST(name,fun,tspawn,tfork,tvfork,tvforkdone)\
35871.149SkamilATF_TC(name);								\
35881.149SkamilATF_TC_HEAD(name, tc)							\
35891.149Skamil{									\
35901.149Skamil	atf_tc_set_md_var(tc, "descr", "Verify " fun "() "		\
35911.149Skamil	    "called with 0%s%s%s%s in EVENT_MASK",			\
35921.149Skamil	    tspawn ? "|PTRACE_POSIX_SPAWN" : "",			\
35931.149Skamil	    tfork ? "|PTRACE_FORK" : "",				\
35941.149Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
35951.149Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
35961.149Skamil}									\
35971.149Skamil									\
35981.149SkamilATF_TC_BODY(name, tc)							\
35991.149Skamil{									\
36001.149Skamil									\
36011.149Skamil	unrelated_tracer_fork_body(fun, tspawn, tfork, tvfork,		\
36021.149Skamil	    tvforkdone);						\
36031.149Skamil}
36041.149Skamil
36051.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork1, "fork", false, false, false, false)
36061.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork2, "fork", false, true, false, false)
36071.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork3, "fork", false, false, true, false)
36081.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork4, "fork", false, true, true, false)
36091.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork5, "fork", false, false, false, true)
36101.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork6, "fork", false, true, false, true)
36111.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork7, "fork", false, false, true, true)
36121.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork8, "fork", false, true, true, true)
36131.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork9, "fork", true, false, false, false)
36141.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork10, "fork", true, true, false, false)
36151.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork11, "fork", true, false, true, false)
36161.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork12, "fork", true, true, true, false)
36171.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork13, "fork", true, false, false, true)
36181.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork14, "fork", true, true, false, true)
36191.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork15, "fork", true, false, true, true)
36201.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_fork16, "fork", true, true, true, true)
36211.149Skamil
36221.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork1, "vfork", false, false, false, false)
36231.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork2, "vfork", false, true, false, false)
36241.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork3, "vfork", false, false, true, false)
36251.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork4, "vfork", false, true, true, false)
36261.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork5, "vfork", false, false, false, true)
36271.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork6, "vfork", false, true, false, true)
36281.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork7, "vfork", false, false, true, true)
36291.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork8, "vfork", false, true, true, true)
36301.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork9, "vfork", true, false, false, false)
36311.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork10, "vfork", true, true, false, false)
36321.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork11, "vfork", true, false, true, false)
36331.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork12, "vfork", true, true, true, false)
36341.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork13, "vfork", true, false, false, true)
36351.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork14, "vfork", true, true, false, true)
36361.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork15, "vfork", true, false, true, true)
36371.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_vfork16, "vfork", true, true, true, true)
36381.149Skamil
36391.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn1, "spawn", false, false, false, false)
36401.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn2, "spawn", false, true, false, false)
36411.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn3, "spawn", false, false, true, false)
36421.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn4, "spawn", false, true, true, false)
36431.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn5, "spawn", false, false, false, true)
36441.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn6, "spawn", false, true, false, true)
36451.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn7, "spawn", false, false, true, true)
36461.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn8, "spawn", false, true, true, true)
36471.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn9, "spawn", true, false, false, false)
36481.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn10, "spawn", true, true, false, false)
36491.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn11, "spawn", true, false, true, false)
36501.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn12, "spawn", true, true, true, false)
36511.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn13, "spawn", true, false, false, true)
36521.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn14, "spawn", true, true, false, true)
36531.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn15, "spawn", true, false, true, true)
36541.149SkamilUNRELATED_TRACER_FORK_TEST(unrelated_tracer_posix_spawn16, "spawn", true, true, true, true)
36551.149Skamil#endif
36561.149Skamil
36571.149Skamil/// ----------------------------------------------------------------------------
36581.149Skamil
36591.149Skamil#if defined(TWAIT_HAVE_PID)
36601.149Skamilstatic void
36611.126Skamilfork_detach_forker_body(const char *fn, bool kill_process)
36621.116Skamil{
36631.116Skamil	const int exitval = 5;
36641.126Skamil	const int exitval2 = 0; /* Matches exit value from /bin/echo */
36651.116Skamil	const int sigval = SIGSTOP;
36661.116Skamil	pid_t child, child2 = 0, wpid;
36671.116Skamil#if defined(TWAIT_HAVE_STATUS)
36681.116Skamil	int status;
36691.116Skamil#endif
36701.116Skamil	ptrace_state_t state;
36711.116Skamil	const int slen = sizeof(state);
36721.116Skamil	ptrace_event_t event;
36731.116Skamil	const int elen = sizeof(event);
36741.116Skamil
36751.116Skamil	int op;
36761.116Skamil
36771.126Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
36781.116Skamil
36791.116Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
36801.116Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
36811.116Skamil	if (child == 0) {
36821.116Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
36831.116Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
36841.116Skamil
36851.116Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
36861.116Skamil		FORKEE_ASSERT(raise(sigval) == 0);
36871.116Skamil
36881.126Skamil		if (strcmp(fn, "spawn") == 0) {
36891.126Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
36901.126Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
36911.126Skamil		} else  {
36921.126Skamil			if (strcmp(fn, "fork") == 0) {
36931.126Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
36941.126Skamil			} else {
36951.126Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
36961.126Skamil			}
36971.116Skamil
36981.126Skamil			if (child2 == 0)
36991.126Skamil				_exit(exitval2);
37001.126Skamil		}
37011.116Skamil
37021.116Skamil		FORKEE_REQUIRE_SUCCESS
37031.116Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
37041.116Skamil
37051.116Skamil		forkee_status_exited(status, exitval2);
37061.116Skamil
37071.116Skamil		DPRINTF("Before exiting of the child process\n");
37081.116Skamil		_exit(exitval);
37091.116Skamil	}
37101.116Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
37111.116Skamil
37121.116Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
37131.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
37141.116Skamil
37151.116Skamil	validate_status_stopped(status, sigval);
37161.116Skamil
37171.116Skamil	DPRINTF("Set EVENT_MASK for the child %d\n", child);
37181.126Skamil	event.pe_set_event = PTRACE_POSIX_SPAWN | PTRACE_FORK | PTRACE_VFORK
37191.126Skamil		| PTRACE_VFORK_DONE;
37201.116Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
37211.116Skamil
37221.116Skamil	DPRINTF("Before resuming the child process where it left off and "
37231.116Skamil	    "without signal to be sent\n");
37241.116Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
37251.116Skamil
37261.116Skamil	DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME, child);
37271.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
37281.116Skamil
37291.116Skamil	validate_status_stopped(status, SIGTRAP);
37301.116Skamil
37311.116Skamil	SYSCALL_REQUIRE(
37321.116Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
37331.126Skamil
37341.126Skamil	if (strcmp(fn, "spawn") == 0)
37351.126Skamil		op = PTRACE_POSIX_SPAWN;
37361.126Skamil	else if (strcmp(fn, "fork") == 0)
37371.126Skamil		op = PTRACE_FORK;
37381.126Skamil	else
37391.126Skamil		op = PTRACE_VFORK;
37401.126Skamil
37411.116Skamil	ATF_REQUIRE_EQ(state.pe_report_event & op, op);
37421.116Skamil
37431.116Skamil	child2 = state.pe_other_pid;
37441.116Skamil	DPRINTF("Reported ptrace event with forkee %d\n", child2);
37451.116Skamil
37461.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
37471.126Skamil	    strcmp(fn, "vfork") == 0)
37481.116Skamil		op = kill_process ? PT_KILL : PT_DETACH;
37491.116Skamil	else
37501.116Skamil		op = PT_CONTINUE;
37511.116Skamil	SYSCALL_REQUIRE(ptrace(op, child, (void *)1, 0) != -1);
37521.116Skamil
37531.116Skamil	DPRINTF("Before calling %s() for the forkee %d of the child %d\n",
37541.116Skamil	    TWAIT_FNAME, child2, child);
37551.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0), child2);
37561.116Skamil
37571.116Skamil	validate_status_stopped(status, SIGTRAP);
37581.116Skamil
37591.116Skamil	SYSCALL_REQUIRE(
37601.116Skamil	    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
37611.126Skamil	if (strcmp(fn, "spawn") == 0)
37621.126Skamil		op = PTRACE_POSIX_SPAWN;
37631.126Skamil	else if (strcmp(fn, "fork") == 0)
37641.126Skamil		op = PTRACE_FORK;
37651.126Skamil	else
37661.126Skamil		op = PTRACE_VFORK;
37671.126Skamil
37681.116Skamil	ATF_REQUIRE_EQ(state.pe_report_event & op, op);
37691.116Skamil	ATF_REQUIRE_EQ(state.pe_other_pid, child);
37701.116Skamil
37711.116Skamil	DPRINTF("Before resuming the forkee process where it left off "
37721.116Skamil	    "and without signal to be sent\n");
37731.116Skamil 	SYSCALL_REQUIRE(
37741.116Skamil	    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
37751.116Skamil
37761.126Skamil	if (strcmp(fn, "vforkdone") == 0) {
37771.116Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
37781.116Skamil		    child);
37791.116Skamil		TWAIT_REQUIRE_SUCCESS(
37801.116Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
37811.116Skamil
37821.116Skamil		validate_status_stopped(status, SIGTRAP);
37831.116Skamil
37841.116Skamil		SYSCALL_REQUIRE(
37851.116Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
37861.116Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
37871.116Skamil
37881.116Skamil		child2 = state.pe_other_pid;
37891.116Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
37901.116Skamil		    child2);
37911.116Skamil
37921.116Skamil		op = kill_process ? PT_KILL : PT_DETACH;
37931.116Skamil		DPRINTF("Before resuming the child process where it left off "
37941.116Skamil		    "and without signal to be sent\n");
37951.116Skamil		SYSCALL_REQUIRE(ptrace(op, child, (void *)1, 0) != -1);
37961.116Skamil	}
37971.116Skamil
37981.116Skamil	DPRINTF("Before calling %s() for the forkee - expected exited\n",
37991.116Skamil	    TWAIT_FNAME);
38001.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0), child2);
38011.116Skamil
38021.116Skamil	validate_status_exited(status, exitval2);
38031.116Skamil
38041.116Skamil	DPRINTF("Before calling %s() for the forkee - expected no process\n",
38051.116Skamil	    TWAIT_FNAME);
38061.116Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child2, &status, 0));
38071.116Skamil
38081.116Skamil	DPRINTF("Before calling %s() for the forkee - expected exited\n",
38091.116Skamil	    TWAIT_FNAME);
38101.116Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
38111.116Skamil
38121.116Skamil	if (kill_process) {
38131.116Skamil		validate_status_signaled(status, SIGKILL, 0);
38141.116Skamil	} else {
38151.116Skamil		validate_status_exited(status, exitval);
38161.116Skamil	}
38171.116Skamil
38181.116Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
38191.116Skamil	    TWAIT_FNAME);
38201.116Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
38211.116Skamil}
38221.116Skamil
38231.126Skamil#define FORK_DETACH_FORKER(name,event,kprocess)				\
38241.116SkamilATF_TC(name);								\
38251.116SkamilATF_TC_HEAD(name, tc)							\
38261.116Skamil{									\
38271.126Skamil	atf_tc_set_md_var(tc, "descr", "Verify %s " event,		\
38281.126Skamil	    kprocess ? "killed" : "detached");				\
38291.116Skamil}									\
38301.116Skamil									\
38311.116SkamilATF_TC_BODY(name, tc)							\
38321.116Skamil{									\
38331.116Skamil									\
38341.126Skamil	fork_detach_forker_body(event, kprocess);			\
38351.116Skamil}
38361.116Skamil
38371.126SkamilFORK_DETACH_FORKER(posix_spawn_detach_spawner, "spawn", false)
38381.126SkamilFORK_DETACH_FORKER(fork_detach_forker, "fork", false)
38391.126SkamilFORK_DETACH_FORKER(vfork_detach_vforker, "vfork", false)
38401.126SkamilFORK_DETACH_FORKER(vfork_detach_vforkerdone, "vforkdone", false)
38411.126Skamil
38421.126SkamilFORK_DETACH_FORKER(posix_spawn_kill_spawner, "spawn", true)
38431.126SkamilFORK_DETACH_FORKER(fork_kill_forker, "fork", true)
38441.126SkamilFORK_DETACH_FORKER(vfork_kill_vforker, "vfork", true)
38451.126SkamilFORK_DETACH_FORKER(vfork_kill_vforkerdone, "vforkdone", true)
38461.116Skamil#endif
38471.116Skamil
38481.116Skamil/// ----------------------------------------------------------------------------
38491.116Skamil
38501.150Skamil#if defined(TWAIT_HAVE_PID)
38511.150Skamilstatic void
38521.150Skamilunrelated_tracer_fork_detach_forker_body(const char *fn, bool kill_process)
38531.150Skamil{
38541.150Skamil	const int sigval = SIGSTOP;
38551.150Skamil	struct msg_fds parent_tracee, parent_tracer;
38561.150Skamil	const int exitval = 10;
38571.150Skamil	const int exitval2 = 0; /* This matched exit status from /bin/echo */
38581.150Skamil	pid_t tracee, tracer, wpid;
38591.150Skamil	pid_t tracee2 = 0;
38601.150Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
38611.150Skamil#if defined(TWAIT_HAVE_STATUS)
38621.150Skamil	int status;
38631.150Skamil#endif
38641.150Skamil	int op;
38651.150Skamil
38661.150Skamil	struct ptrace_siginfo info;
38671.150Skamil	ptrace_state_t state;
38681.150Skamil	const int slen = sizeof(state);
38691.150Skamil	ptrace_event_t event;
38701.150Skamil	const int elen = sizeof(event);
38711.150Skamil
38721.150Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
38731.150Skamil
38741.150Skamil	DPRINTF("Spawn tracee\n");
38751.150Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
38761.150Skamil	tracee = atf_utils_fork();
38771.150Skamil	if (tracee == 0) {
38781.150Skamil		// Wait for parent to let us crash
38791.150Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
38801.150Skamil
38811.150Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
38821.150Skamil		FORKEE_ASSERT(raise(sigval) == 0);
38831.150Skamil
38841.150Skamil		if (strcmp(fn, "spawn") == 0) {
38851.150Skamil			FORKEE_ASSERT_EQ(posix_spawn(&tracee2,
38861.150Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
38871.150Skamil		} else  {
38881.150Skamil			if (strcmp(fn, "fork") == 0) {
38891.150Skamil				FORKEE_ASSERT((tracee2 = fork()) != -1);
38901.150Skamil			} else {
38911.150Skamil				FORKEE_ASSERT((tracee2 = vfork()) != -1);
38921.150Skamil			}
38931.150Skamil
38941.150Skamil			if (tracee2 == 0)
38951.150Skamil				_exit(exitval2);
38961.150Skamil		}
38971.150Skamil
38981.150Skamil		FORKEE_REQUIRE_SUCCESS
38991.150Skamil		    (wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
39001.150Skamil
39011.150Skamil		forkee_status_exited(status, exitval2);
39021.150Skamil
39031.150Skamil		DPRINTF("Before exiting of the child process\n");
39041.150Skamil		_exit(exitval);
39051.150Skamil	}
39061.150Skamil
39071.150Skamil	DPRINTF("Spawn debugger\n");
39081.150Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
39091.150Skamil	tracer = atf_utils_fork();
39101.150Skamil	if (tracer == 0) {
39111.150Skamil		/* Fork again and drop parent to reattach to PID 1 */
39121.150Skamil		tracer = atf_utils_fork();
39131.150Skamil		if (tracer != 0)
39141.150Skamil			_exit(exitval);
39151.150Skamil
39161.150Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
39171.150Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
39181.150Skamil
39191.150Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
39201.150Skamil		FORKEE_REQUIRE_SUCCESS(
39211.150Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
39221.150Skamil
39231.150Skamil		forkee_status_stopped(status, SIGSTOP);
39241.150Skamil
39251.150Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
39261.150Skamil		    "traced process\n");
39271.150Skamil		SYSCALL_REQUIRE(
39281.150Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
39291.150Skamil
39301.150Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
39311.150Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
39321.150Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
39331.150Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
39341.150Skamil
39351.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
39361.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
39371.150Skamil
39381.150Skamil		/* Resume tracee with PT_CONTINUE */
39391.150Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
39401.150Skamil
39411.150Skamil		/* Inform parent that tracer has attached to tracee */
39421.150Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
39431.150Skamil
39441.150Skamil		/* Wait for parent to tell use that tracee should have exited */
39451.150Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
39461.150Skamil
39471.150Skamil		/* Wait for tracee and assert that it exited */
39481.150Skamil		FORKEE_REQUIRE_SUCCESS(
39491.150Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
39501.150Skamil
39511.150Skamil		forkee_status_stopped(status, sigval);
39521.150Skamil
39531.150Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for the "
39541.150Skamil		    "traced process\n");
39551.150Skamil		SYSCALL_REQUIRE(
39561.150Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
39571.150Skamil
39581.150Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
39591.150Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
39601.150Skamil		    "si_errno=%#x\n", info.psi_siginfo.si_signo,
39611.150Skamil		    info.psi_siginfo.si_code, info.psi_siginfo.si_errno);
39621.150Skamil
39631.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
39641.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
39651.150Skamil
39661.150Skamil		DPRINTF("Set EVENT_MASK for the child %d\n", tracee);
39671.150Skamil		event.pe_set_event = PTRACE_POSIX_SPAWN | PTRACE_FORK | PTRACE_VFORK
39681.150Skamil			| PTRACE_VFORK_DONE;
39691.150Skamil		SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, tracee, &event, elen) != -1);
39701.150Skamil
39711.150Skamil		DPRINTF("Before resuming the child process where it left off and "
39721.150Skamil		    "without signal to be sent\n");
39731.150Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
39741.150Skamil
39751.150Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME, tracee);
39761.150Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
39771.150Skamil
39781.150Skamil		validate_status_stopped(status, SIGTRAP);
39791.150Skamil
39801.150Skamil		SYSCALL_REQUIRE(
39811.150Skamil		    ptrace(PT_GET_PROCESS_STATE, tracee, &state, slen) != -1);
39821.150Skamil
39831.150Skamil		if (strcmp(fn, "spawn") == 0)
39841.150Skamil			op = PTRACE_POSIX_SPAWN;
39851.150Skamil		else if (strcmp(fn, "fork") == 0)
39861.150Skamil			op = PTRACE_FORK;
39871.150Skamil		else
39881.150Skamil			op = PTRACE_VFORK;
39891.150Skamil
39901.150Skamil		ATF_REQUIRE_EQ(state.pe_report_event & op, op);
39911.150Skamil
39921.150Skamil		tracee2 = state.pe_other_pid;
39931.150Skamil		DPRINTF("Reported ptrace event with forkee %d\n", tracee2);
39941.150Skamil		if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
39951.150Skamil		    strcmp(fn, "vfork") == 0)
39961.150Skamil			op = kill_process ? PT_KILL : PT_DETACH;
39971.150Skamil		else
39981.150Skamil			op = PT_CONTINUE;
39991.150Skamil		SYSCALL_REQUIRE(ptrace(op, tracee, (void *)1, 0) != -1);
40001.150Skamil
40011.150Skamil		DPRINTF("Before calling %s() for the forkee %d of the tracee %d\n",
40021.150Skamil		    TWAIT_FNAME, tracee2, tracee);
40031.150Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
40041.150Skamil
40051.150Skamil		validate_status_stopped(status, SIGTRAP);
40061.150Skamil
40071.150Skamil		SYSCALL_REQUIRE(
40081.150Skamil		    ptrace(PT_GET_PROCESS_STATE, tracee2, &state, slen) != -1);
40091.150Skamil		if (strcmp(fn, "spawn") == 0)
40101.150Skamil			op = PTRACE_POSIX_SPAWN;
40111.150Skamil		else if (strcmp(fn, "fork") == 0)
40121.150Skamil			op = PTRACE_FORK;
40131.150Skamil		else
40141.150Skamil			op = PTRACE_VFORK;
40151.150Skamil
40161.150Skamil		ATF_REQUIRE_EQ(state.pe_report_event & op, op);
40171.150Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, tracee);
40181.150Skamil
40191.150Skamil		DPRINTF("Before resuming the forkee process where it left off "
40201.150Skamil		    "and without signal to be sent\n");
40211.150Skamil		SYSCALL_REQUIRE(
40221.150Skamil		    ptrace(PT_CONTINUE, tracee2, (void *)1, 0) != -1);
40231.150Skamil
40241.150Skamil		if (strcmp(fn, "vforkdone") == 0) {
40251.150Skamil			DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
40261.150Skamil			    tracee);
40271.150Skamil			TWAIT_REQUIRE_SUCCESS(
40281.150Skamil			    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
40291.150Skamil
40301.150Skamil			validate_status_stopped(status, SIGTRAP);
40311.150Skamil
40321.150Skamil			SYSCALL_REQUIRE(
40331.150Skamil			    ptrace(PT_GET_PROCESS_STATE, tracee, &state, slen) != -1);
40341.150Skamil			ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
40351.150Skamil
40361.150Skamil			tracee2 = state.pe_other_pid;
40371.150Skamil			DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
40381.150Skamil			    tracee2);
40391.150Skamil
40401.150Skamil			op = kill_process ? PT_KILL : PT_DETACH;
40411.150Skamil			DPRINTF("Before resuming the child process where it left off "
40421.150Skamil			    "and without signal to be sent\n");
40431.150Skamil			SYSCALL_REQUIRE(ptrace(op, tracee, (void *)1, 0) != -1);
40441.150Skamil		}
40451.150Skamil
40461.150Skamil		DPRINTF("Before calling %s() for the forkee - expected exited\n",
40471.150Skamil		    TWAIT_FNAME);
40481.150Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee2, &status, 0), tracee2);
40491.150Skamil
40501.150Skamil		validate_status_exited(status, exitval2);
40511.150Skamil
40521.150Skamil		DPRINTF("Before calling %s() for the forkee - expected no process\n",
40531.150Skamil		    TWAIT_FNAME);
40541.150Skamil		TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(tracee2, &status, 0));
40551.150Skamil
40561.150Skamil		if (kill_process) {
40571.150Skamil			DPRINTF("Before calling %s() for the forkee - expected signaled\n",
40581.150Skamil			    TWAIT_FNAME);
40591.150Skamil			TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
40601.150Skamil
40611.150Skamil			validate_status_signaled(status, SIGKILL, 0);
40621.150Skamil		}
40631.150Skamil
40641.150Skamil		/* Inform parent that tracer is exiting normally */
40651.150Skamil		CHILD_TO_PARENT("tracer done", parent_tracer, msg);
40661.150Skamil
40671.150Skamil		DPRINTF("Before exiting of the tracer process\n");
40681.150Skamil		_exit(0 /* collect by initproc */);
40691.150Skamil	}
40701.150Skamil
40711.150Skamil	DPRINTF("Wait for the tracer process (direct child) to exit "
40721.150Skamil	    "calling %s()\n", TWAIT_FNAME);
40731.150Skamil	TWAIT_REQUIRE_SUCCESS(
40741.150Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
40751.150Skamil
40761.150Skamil	validate_status_exited(status, exitval);
40771.150Skamil
40781.150Skamil	DPRINTF("Wait for the non-exited tracee process with %s()\n",
40791.150Skamil	    TWAIT_FNAME);
40801.150Skamil	TWAIT_REQUIRE_SUCCESS(
40811.150Skamil	    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
40821.150Skamil
40831.150Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
40841.150Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
40851.150Skamil
40861.150Skamil	DPRINTF("Resume the tracee and let it crash\n");
40871.150Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
40881.150Skamil
40891.150Skamil	DPRINTF("Resume the tracer and let it detect crashed tracee\n");
40901.150Skamil	PARENT_TO_CHILD("Message 2", parent_tracer, msg);
40911.150Skamil
40921.150Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
40931.150Skamil	    TWAIT_FNAME);
40941.150Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
40951.150Skamil
40961.150Skamil	if (kill_process) {
40971.150Skamil		validate_status_signaled(status, SIGKILL, 0);
40981.150Skamil	} else {
40991.150Skamil		validate_status_exited(status, exitval);
41001.150Skamil	}
41011.150Skamil
41021.150Skamil	DPRINTF("Await normal exit of tracer\n");
41031.150Skamil	PARENT_FROM_CHILD("tracer done", parent_tracer, msg);
41041.150Skamil
41051.150Skamil	msg_close(&parent_tracer);
41061.150Skamil	msg_close(&parent_tracee);
41071.150Skamil}
41081.150Skamil
41091.150Skamil#define UNRELATED_TRACER_FORK_DETACH_FORKER(name,event,kprocess)	\
41101.150SkamilATF_TC(name);								\
41111.150SkamilATF_TC_HEAD(name, tc)							\
41121.150Skamil{									\
41131.150Skamil	atf_tc_set_md_var(tc, "descr", "Verify %s " event,		\
41141.150Skamil	    kprocess ? "killed" : "detached");				\
41151.150Skamil}									\
41161.150Skamil									\
41171.150SkamilATF_TC_BODY(name, tc)							\
41181.150Skamil{									\
41191.150Skamil									\
41201.150Skamil	unrelated_tracer_fork_detach_forker_body(event, kprocess);	\
41211.150Skamil}
41221.150Skamil
41231.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_posix_spawn_detach_spawner, "spawn", false)
41241.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_fork_detach_forker, "fork", false)
41251.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_vfork_detach_vforker, "vfork", false)
41261.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_vfork_detach_vforkerdone, "vforkdone", false)
41271.150Skamil
41281.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_posix_spawn_kill_spawner, "spawn", true)
41291.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_fork_kill_forker, "fork", true)
41301.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_vfork_kill_vforker, "vfork", true)
41311.150SkamilUNRELATED_TRACER_FORK_DETACH_FORKER(unrelated_tracer_vfork_kill_vforkerdone, "vforkdone", true)
41321.150Skamil#endif
41331.150Skamil
41341.150Skamil/// ----------------------------------------------------------------------------
41351.150Skamil
41361.108Skamilstatic void
41371.108Skamiltraceme_vfork_fork_body(pid_t (*fn)(void))
41381.108Skamil{
41391.108Skamil	const int exitval = 5;
41401.108Skamil	const int exitval2 = 15;
41411.108Skamil	pid_t child, child2 = 0, wpid;
41421.108Skamil#if defined(TWAIT_HAVE_STATUS)
41431.108Skamil	int status;
41441.108Skamil#endif
41451.108Skamil
41461.108Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
41471.108Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
41481.108Skamil	if (child == 0) {
41491.108Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
41501.108Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
41511.108Skamil
41521.108Skamil		FORKEE_ASSERT((child2 = (fn)()) != -1);
41531.108Skamil
41541.108Skamil		if (child2 == 0)
41551.108Skamil			_exit(exitval2);
41561.108Skamil
41571.108Skamil		FORKEE_REQUIRE_SUCCESS
41581.108Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
41591.108Skamil
41601.108Skamil		forkee_status_exited(status, exitval2);
41611.108Skamil
41621.108Skamil		DPRINTF("Before exiting of the child process\n");
41631.108Skamil		_exit(exitval);
41641.108Skamil	}
41651.108Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
41661.108Skamil
41671.108Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
41681.108Skamil	    TWAIT_FNAME);
41691.108Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
41701.108Skamil
41711.108Skamil	validate_status_exited(status, exitval);
41721.108Skamil
41731.108Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
41741.108Skamil	    TWAIT_FNAME);
41751.108Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
41761.108Skamil}
41771.108Skamil
41781.108Skamil#define TRACEME_VFORK_FORK_TEST(name,fun)				\
41791.108SkamilATF_TC(name);								\
41801.108SkamilATF_TC_HEAD(name, tc)							\
41811.108Skamil{									\
41821.108Skamil	atf_tc_set_md_var(tc, "descr", "Verify " #fun "(2) "		\
41831.108Skamil	    "called from vfork(2)ed child");				\
41841.108Skamil}									\
41851.108Skamil									\
41861.108SkamilATF_TC_BODY(name, tc)							\
41871.108Skamil{									\
41881.108Skamil									\
41891.108Skamil	traceme_vfork_fork_body(fun);					\
41901.108Skamil}
41911.108Skamil
41921.108SkamilTRACEME_VFORK_FORK_TEST(traceme_vfork_fork, fork)
41931.108SkamilTRACEME_VFORK_FORK_TEST(traceme_vfork_vfork, vfork)
41941.108Skamil
41951.108Skamil/// ----------------------------------------------------------------------------
41961.108Skamil
41971.54Skamilenum bytes_transfer_type {
41981.54Skamil	BYTES_TRANSFER_DATA,
41991.54Skamil	BYTES_TRANSFER_DATAIO,
42001.54Skamil	BYTES_TRANSFER_TEXT,
42011.54Skamil	BYTES_TRANSFER_TEXTIO,
42021.54Skamil	BYTES_TRANSFER_AUXV
42031.54Skamil};
42041.31Skamil
42051.54Skamilstatic int __used
42061.54Skamilbytes_transfer_dummy(int a, int b, int c, int d)
42071.54Skamil{
42081.54Skamil	int e, f, g, h;
42091.1Skamil
42101.54Skamil	a *= 4;
42111.54Skamil	b += 3;
42121.54Skamil	c -= 2;
42131.54Skamil	d /= 1;
42141.1Skamil
42151.54Skamil	e = strtol("10", NULL, 10);
42161.54Skamil	f = strtol("20", NULL, 10);
42171.54Skamil	g = strtol("30", NULL, 10);
42181.54Skamil	h = strtol("40", NULL, 10);
42191.1Skamil
42201.54Skamil	return (a + b * c - d) + (e * f - g / h);
42211.1Skamil}
42221.1Skamil
42231.54Skamilstatic void
42241.55Schristosbytes_transfer(int operation, size_t size, enum bytes_transfer_type type)
42251.1Skamil{
42261.1Skamil	const int exitval = 5;
42271.1Skamil	const int sigval = SIGSTOP;
42281.1Skamil	pid_t child, wpid;
42291.54Skamil	bool skip = false;
42301.1Skamil
42311.54Skamil	int lookup_me = 0;
42321.54Skamil	uint8_t lookup_me8 = 0;
42331.54Skamil	uint16_t lookup_me16 = 0;
42341.54Skamil	uint32_t lookup_me32 = 0;
42351.54Skamil	uint64_t lookup_me64 = 0;
42361.1Skamil
42371.54Skamil	int magic = 0x13579246;
42381.54Skamil	uint8_t magic8 = 0xab;
42391.54Skamil	uint16_t magic16 = 0x1234;
42401.54Skamil	uint32_t magic32 = 0x98765432;
42411.54Skamil	uint64_t magic64 = 0xabcdef0123456789;
42421.1Skamil
42431.54Skamil	struct ptrace_io_desc io;
42441.1Skamil#if defined(TWAIT_HAVE_STATUS)
42451.1Skamil	int status;
42461.1Skamil#endif
42471.60Skre	/* 513 is just enough, for the purposes of ATF it's good enough */
42481.60Skre	AuxInfo ai[513], *aip;
42491.55Schristos
42501.55Schristos	ATF_REQUIRE(size < sizeof(ai));
42511.1Skamil
42521.54Skamil	/* Prepare variables for .TEXT transfers */
42531.54Skamil	switch (type) {
42541.54Skamil	case BYTES_TRANSFER_TEXT:
42551.54Skamil		memcpy(&magic, bytes_transfer_dummy, sizeof(magic));
42561.54Skamil		break;
42571.54Skamil	case BYTES_TRANSFER_TEXTIO:
42581.54Skamil		switch (size) {
42591.54Skamil		case 8:
42601.54Skamil			memcpy(&magic8, bytes_transfer_dummy, sizeof(magic8));
42611.54Skamil			break;
42621.54Skamil		case 16:
42631.54Skamil			memcpy(&magic16, bytes_transfer_dummy, sizeof(magic16));
42641.54Skamil			break;
42651.54Skamil		case 32:
42661.54Skamil			memcpy(&magic32, bytes_transfer_dummy, sizeof(magic32));
42671.54Skamil			break;
42681.54Skamil		case 64:
42691.54Skamil			memcpy(&magic64, bytes_transfer_dummy, sizeof(magic64));
42701.54Skamil			break;
42711.54Skamil		}
42721.54Skamil		break;
42731.54Skamil	default:
42741.54Skamil		break;
42751.54Skamil	}
42761.1Skamil
42771.54Skamil	/* Prepare variables for PIOD and AUXV transfers */
42781.54Skamil	switch (type) {
42791.54Skamil	case BYTES_TRANSFER_TEXTIO:
42801.54Skamil	case BYTES_TRANSFER_DATAIO:
42811.54Skamil		io.piod_op = operation;
42821.54Skamil		switch (size) {
42831.54Skamil		case 8:
42841.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
42851.54Skamil			               (void *)bytes_transfer_dummy :
42861.54Skamil			               &lookup_me8;
42871.54Skamil			io.piod_addr = &lookup_me8;
42881.54Skamil			io.piod_len = sizeof(lookup_me8);
42891.54Skamil			break;
42901.54Skamil		case 16:
42911.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
42921.54Skamil			               (void *)bytes_transfer_dummy :
42931.54Skamil			               &lookup_me16;
42941.54Skamil			io.piod_addr = &lookup_me16;
42951.54Skamil			io.piod_len = sizeof(lookup_me16);
42961.54Skamil			break;
42971.54Skamil		case 32:
42981.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
42991.54Skamil			               (void *)bytes_transfer_dummy :
43001.54Skamil			               &lookup_me32;
43011.54Skamil			io.piod_addr = &lookup_me32;
43021.54Skamil			io.piod_len = sizeof(lookup_me32);
43031.54Skamil			break;
43041.54Skamil		case 64:
43051.54Skamil			io.piod_offs = (type == BYTES_TRANSFER_TEXTIO) ?
43061.54Skamil			               (void *)bytes_transfer_dummy :
43071.54Skamil			               &lookup_me64;
43081.54Skamil			io.piod_addr = &lookup_me64;
43091.54Skamil			io.piod_len = sizeof(lookup_me64);
43101.54Skamil			break;
43111.54Skamil		default:
43121.54Skamil			break;
43131.54Skamil		}
43141.54Skamil		break;
43151.54Skamil	case BYTES_TRANSFER_AUXV:
43161.54Skamil		io.piod_op = operation;
43171.54Skamil		io.piod_offs = 0;
43181.54Skamil		io.piod_addr = ai;
43191.54Skamil		io.piod_len = size;
43201.54Skamil		break;
43211.54Skamil	default:
43221.54Skamil		break;
43231.1Skamil	}
43241.1Skamil
43251.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
43261.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
43271.1Skamil	if (child == 0) {
43281.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
43291.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
43301.1Skamil
43311.54Skamil		switch (type) {
43321.54Skamil		case BYTES_TRANSFER_DATA:
43331.54Skamil			switch (operation) {
43341.54Skamil			case PT_READ_D:
43351.54Skamil			case PT_READ_I:
43361.54Skamil				lookup_me = magic;
43371.54Skamil				break;
43381.54Skamil			default:
43391.54Skamil				break;
43401.54Skamil			}
43411.54Skamil			break;
43421.54Skamil		case BYTES_TRANSFER_DATAIO:
43431.54Skamil			switch (operation) {
43441.54Skamil			case PIOD_READ_D:
43451.54Skamil			case PIOD_READ_I:
43461.54Skamil				switch (size) {
43471.54Skamil				case 8:
43481.54Skamil					lookup_me8 = magic8;
43491.54Skamil					break;
43501.54Skamil				case 16:
43511.54Skamil					lookup_me16 = magic16;
43521.54Skamil					break;
43531.54Skamil				case 32:
43541.54Skamil					lookup_me32 = magic32;
43551.54Skamil					break;
43561.54Skamil				case 64:
43571.54Skamil					lookup_me64 = magic64;
43581.54Skamil					break;
43591.54Skamil				default:
43601.54Skamil					break;
43611.54Skamil				}
43621.54Skamil				break;
43631.54Skamil			default:
43641.54Skamil				break;
43651.54Skamil			}
43661.54Skamil		default:
43671.54Skamil			break;
43681.54Skamil		}
43691.54Skamil
43701.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
43711.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
43721.1Skamil
43731.54Skamil		/* Handle PIOD and PT separately as operation values overlap */
43741.54Skamil		switch (type) {
43751.54Skamil		case BYTES_TRANSFER_DATA:
43761.54Skamil			switch (operation) {
43771.54Skamil			case PT_WRITE_D:
43781.54Skamil			case PT_WRITE_I:
43791.54Skamil				FORKEE_ASSERT_EQ(lookup_me, magic);
43801.54Skamil				break;
43811.54Skamil			default:
43821.54Skamil				break;
43831.54Skamil			}
43841.54Skamil			break;
43851.54Skamil		case BYTES_TRANSFER_DATAIO:
43861.54Skamil			switch (operation) {
43871.54Skamil			case PIOD_WRITE_D:
43881.54Skamil			case PIOD_WRITE_I:
43891.54Skamil				switch (size) {
43901.54Skamil				case 8:
43911.54Skamil					FORKEE_ASSERT_EQ(lookup_me8, magic8);
43921.54Skamil					break;
43931.54Skamil				case 16:
43941.54Skamil					FORKEE_ASSERT_EQ(lookup_me16, magic16);
43951.54Skamil					break;
43961.54Skamil				case 32:
43971.54Skamil					FORKEE_ASSERT_EQ(lookup_me32, magic32);
43981.54Skamil					break;
43991.54Skamil				case 64:
44001.54Skamil					FORKEE_ASSERT_EQ(lookup_me64, magic64);
44011.54Skamil					break;
44021.54Skamil				default:
44031.54Skamil					break;
44041.54Skamil				}
44051.54Skamil				break;
44061.54Skamil			default:
44071.54Skamil				break;
44081.54Skamil			}
44091.54Skamil			break;
44101.54Skamil		case BYTES_TRANSFER_TEXT:
44111.54Skamil			FORKEE_ASSERT(memcmp(&magic, bytes_transfer_dummy,
44121.54Skamil			                     sizeof(magic)) == 0);
44131.54Skamil			break;
44141.54Skamil		case BYTES_TRANSFER_TEXTIO:
44151.54Skamil			switch (size) {
44161.54Skamil			case 8:
44171.54Skamil				FORKEE_ASSERT(memcmp(&magic8,
44181.54Skamil				                     bytes_transfer_dummy,
44191.54Skamil				                     sizeof(magic8)) == 0);
44201.54Skamil				break;
44211.54Skamil			case 16:
44221.54Skamil				FORKEE_ASSERT(memcmp(&magic16,
44231.54Skamil				                     bytes_transfer_dummy,
44241.54Skamil				                     sizeof(magic16)) == 0);
44251.54Skamil				break;
44261.54Skamil			case 32:
44271.54Skamil				FORKEE_ASSERT(memcmp(&magic32,
44281.54Skamil				                     bytes_transfer_dummy,
44291.54Skamil				                     sizeof(magic32)) == 0);
44301.54Skamil				break;
44311.54Skamil			case 64:
44321.54Skamil				FORKEE_ASSERT(memcmp(&magic64,
44331.54Skamil				                     bytes_transfer_dummy,
44341.54Skamil				                     sizeof(magic64)) == 0);
44351.54Skamil				break;
44361.54Skamil			}
44371.54Skamil			break;
44381.54Skamil		default:
44391.54Skamil			break;
44401.54Skamil		}
44411.54Skamil
44421.13Schristos		DPRINTF("Before exiting of the child process\n");
44431.1Skamil		_exit(exitval);
44441.1Skamil	}
44451.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
44461.1Skamil
44471.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
44481.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
44491.1Skamil
44501.1Skamil	validate_status_stopped(status, sigval);
44511.1Skamil
44521.54Skamil	/* Check PaX MPROTECT */
44531.54Skamil	if (!can_we_write_to_text(child)) {
44541.54Skamil		switch (type) {
44551.54Skamil		case BYTES_TRANSFER_TEXTIO:
44561.54Skamil			switch (operation) {
44571.54Skamil			case PIOD_WRITE_D:
44581.54Skamil			case PIOD_WRITE_I:
44591.54Skamil				skip = true;
44601.54Skamil				break;
44611.54Skamil			default:
44621.54Skamil				break;
44631.54Skamil			}
44641.54Skamil			break;
44651.54Skamil		case BYTES_TRANSFER_TEXT:
44661.54Skamil			switch (operation) {
44671.54Skamil			case PT_WRITE_D:
44681.54Skamil			case PT_WRITE_I:
44691.54Skamil				skip = true;
44701.54Skamil				break;
44711.54Skamil			default:
44721.54Skamil				break;
44731.54Skamil			}
44741.54Skamil			break;
44751.54Skamil		default:
44761.54Skamil			break;
44771.54Skamil		}
44781.54Skamil	}
44791.1Skamil
44801.54Skamil	/* Bailout cleanly killing the child process */
44811.54Skamil	if (skip) {
44821.54Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
44831.54Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
44841.54Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
44851.54Skamil		                      child);
44861.1Skamil
44871.54Skamil		validate_status_signaled(status, SIGKILL, 0);
44881.1Skamil
44891.54Skamil		atf_tc_skip("PaX MPROTECT setup prevents writes to .text");
44901.54Skamil	}
44911.1Skamil
44921.54Skamil	DPRINTF("Calling operation to transfer bytes between child=%d and "
44931.54Skamil	       "parent=%d\n", child, getpid());
44941.1Skamil
44951.54Skamil	switch (type) {
44961.54Skamil	case BYTES_TRANSFER_TEXTIO:
44971.54Skamil	case BYTES_TRANSFER_DATAIO:
44981.54Skamil	case BYTES_TRANSFER_AUXV:
44991.54Skamil		switch (operation) {
45001.54Skamil		case PIOD_WRITE_D:
45011.54Skamil		case PIOD_WRITE_I:
45021.54Skamil			switch (size) {
45031.54Skamil			case 8:
45041.54Skamil				lookup_me8 = magic8;
45051.54Skamil				break;
45061.54Skamil			case 16:
45071.54Skamil				lookup_me16 = magic16;
45081.54Skamil				break;
45091.54Skamil			case 32:
45101.54Skamil				lookup_me32 = magic32;
45111.54Skamil				break;
45121.54Skamil			case 64:
45131.54Skamil				lookup_me64 = magic64;
45141.54Skamil				break;
45151.54Skamil			default:
45161.54Skamil				break;
45171.54Skamil			}
45181.54Skamil			break;
45191.54Skamil		default:
45201.54Skamil			break;
45211.54Skamil		}
45221.54Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, 0) != -1);
45231.54Skamil		switch (operation) {
45241.54Skamil		case PIOD_READ_D:
45251.54Skamil		case PIOD_READ_I:
45261.54Skamil			switch (size) {
45271.54Skamil			case 8:
45281.54Skamil				ATF_REQUIRE_EQ(lookup_me8, magic8);
45291.54Skamil				break;
45301.54Skamil			case 16:
45311.54Skamil				ATF_REQUIRE_EQ(lookup_me16, magic16);
45321.54Skamil				break;
45331.54Skamil			case 32:
45341.54Skamil				ATF_REQUIRE_EQ(lookup_me32, magic32);
45351.54Skamil				break;
45361.54Skamil			case 64:
45371.54Skamil				ATF_REQUIRE_EQ(lookup_me64, magic64);
45381.54Skamil				break;
45391.54Skamil			default:
45401.54Skamil				break;
45411.54Skamil			}
45421.54Skamil			break;
45431.54Skamil		case PIOD_READ_AUXV:
45441.54Skamil			DPRINTF("Asserting that AUXV length (%zu) is > 0\n",
45451.54Skamil			        io.piod_len);
45461.54Skamil			ATF_REQUIRE(io.piod_len > 0);
45471.54Skamil			for (aip = ai; aip->a_type != AT_NULL; aip++)
45481.54Skamil				DPRINTF("a_type=%#llx a_v=%#llx\n",
45491.54Skamil				    (long long int)aip->a_type,
45501.54Skamil				    (long long int)aip->a_v);
45511.54Skamil			break;
45521.54Skamil		default:
45531.54Skamil			break;
45541.54Skamil		}
45551.54Skamil		break;
45561.54Skamil	case BYTES_TRANSFER_TEXT:
45571.54Skamil		switch (operation) {
45581.54Skamil		case PT_READ_D:
45591.54Skamil		case PT_READ_I:
45601.54Skamil			errno = 0;
45611.54Skamil			lookup_me = ptrace(operation, child,
45621.54Skamil			                   bytes_transfer_dummy, 0);
45631.54Skamil			ATF_REQUIRE_EQ(lookup_me, magic);
45641.54Skamil			SYSCALL_REQUIRE_ERRNO(errno, 0);
45651.54Skamil			break;
45661.54Skamil		case PT_WRITE_D:
45671.54Skamil		case PT_WRITE_I:
45681.54Skamil			SYSCALL_REQUIRE(ptrace(operation, child,
45691.54Skamil			                       bytes_transfer_dummy, magic)
45701.54Skamil			                != -1);
45711.54Skamil			break;
45721.54Skamil		default:
45731.54Skamil			break;
45741.54Skamil		}
45751.54Skamil		break;
45761.54Skamil	case BYTES_TRANSFER_DATA:
45771.54Skamil		switch (operation) {
45781.54Skamil		case PT_READ_D:
45791.54Skamil		case PT_READ_I:
45801.54Skamil			errno = 0;
45811.54Skamil			lookup_me = ptrace(operation, child, &lookup_me, 0);
45821.54Skamil			ATF_REQUIRE_EQ(lookup_me, magic);
45831.54Skamil			SYSCALL_REQUIRE_ERRNO(errno, 0);
45841.54Skamil			break;
45851.54Skamil		case PT_WRITE_D:
45861.54Skamil		case PT_WRITE_I:
45871.54Skamil			lookup_me = magic;
45881.54Skamil			SYSCALL_REQUIRE(ptrace(operation, child, &lookup_me,
45891.54Skamil			                       magic) != -1);
45901.54Skamil			break;
45911.54Skamil		default:
45921.54Skamil			break;
45931.54Skamil		}
45941.54Skamil		break;
45951.54Skamil	default:
45961.54Skamil		break;
45971.54Skamil	}
45981.1Skamil
45991.13Schristos	DPRINTF("Before resuming the child process where it left off and "
46001.1Skamil	    "without signal to be sent\n");
46011.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
46021.1Skamil
46031.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46041.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
46051.1Skamil
46061.1Skamil	validate_status_exited(status, exitval);
46071.1Skamil
46081.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46091.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
46101.1Skamil}
46111.1Skamil
46121.61Skre#define BYTES_TRANSFER(test, operation, size, type)			\
46131.61SkreATF_TC(test);								\
46141.61SkreATF_TC_HEAD(test, tc)							\
46151.61Skre{									\
46161.61Skre	atf_tc_set_md_var(tc, "descr",					\
46171.61Skre	    "Verify bytes transfer operation" #operation " and size " #size \
46181.61Skre	    " of type " #type);						\
46191.61Skre}									\
46201.61Skre									\
46211.61SkreATF_TC_BODY(test, tc)							\
46221.61Skre{									\
46231.61Skre									\
46241.61Skre	bytes_transfer(operation, size, BYTES_TRANSFER_##type);		\
46251.1Skamil}
46261.1Skamil
46271.54Skamil// DATA
46281.1Skamil
46291.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_8, PIOD_READ_D, 8, DATAIO)
46301.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_16, PIOD_READ_D, 16, DATAIO)
46311.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_32, PIOD_READ_D, 32, DATAIO)
46321.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_64, PIOD_READ_D, 64, DATAIO)
46331.54Skamil
46341.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_8, PIOD_READ_I, 8, DATAIO)
46351.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_16, PIOD_READ_I, 16, DATAIO)
46361.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_32, PIOD_READ_I, 32, DATAIO)
46371.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_64, PIOD_READ_I, 64, DATAIO)
46381.54Skamil
46391.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_8, PIOD_WRITE_D, 8, DATAIO)
46401.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_16, PIOD_WRITE_D, 16, DATAIO)
46411.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_32, PIOD_WRITE_D, 32, DATAIO)
46421.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_64, PIOD_WRITE_D, 64, DATAIO)
46431.54Skamil
46441.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_8, PIOD_WRITE_I, 8, DATAIO)
46451.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_16, PIOD_WRITE_I, 16, DATAIO)
46461.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_32, PIOD_WRITE_I, 32, DATAIO)
46471.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_64, PIOD_WRITE_I, 64, DATAIO)
46481.54Skamil
46491.54SkamilBYTES_TRANSFER(bytes_transfer_read_d, PT_READ_D, 32, DATA)
46501.54SkamilBYTES_TRANSFER(bytes_transfer_read_i, PT_READ_I, 32, DATA)
46511.54SkamilBYTES_TRANSFER(bytes_transfer_write_d, PT_WRITE_D, 32, DATA)
46521.54SkamilBYTES_TRANSFER(bytes_transfer_write_i, PT_WRITE_I, 32, DATA)
46531.54Skamil
46541.54Skamil// TEXT
46551.54Skamil
46561.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_8_text, PIOD_READ_D, 8, TEXTIO)
46571.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_16_text, PIOD_READ_D, 16, TEXTIO)
46581.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_32_text, PIOD_READ_D, 32, TEXTIO)
46591.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_d_64_text, PIOD_READ_D, 64, TEXTIO)
46601.54Skamil
46611.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_8_text, PIOD_READ_I, 8, TEXTIO)
46621.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_16_text, PIOD_READ_I, 16, TEXTIO)
46631.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_32_text, PIOD_READ_I, 32, TEXTIO)
46641.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_i_64_text, PIOD_READ_I, 64, TEXTIO)
46651.54Skamil
46661.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_8_text, PIOD_WRITE_D, 8, TEXTIO)
46671.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_16_text, PIOD_WRITE_D, 16, TEXTIO)
46681.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_32_text, PIOD_WRITE_D, 32, TEXTIO)
46691.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_d_64_text, PIOD_WRITE_D, 64, TEXTIO)
46701.54Skamil
46711.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_8_text, PIOD_WRITE_I, 8, TEXTIO)
46721.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_16_text, PIOD_WRITE_I, 16, TEXTIO)
46731.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_32_text, PIOD_WRITE_I, 32, TEXTIO)
46741.54SkamilBYTES_TRANSFER(bytes_transfer_piod_write_i_64_text, PIOD_WRITE_I, 64, TEXTIO)
46751.54Skamil
46761.54SkamilBYTES_TRANSFER(bytes_transfer_read_d_text, PT_READ_D, 32, TEXT)
46771.54SkamilBYTES_TRANSFER(bytes_transfer_read_i_text, PT_READ_I, 32, TEXT)
46781.54SkamilBYTES_TRANSFER(bytes_transfer_write_d_text, PT_WRITE_D, 32, TEXT)
46791.54SkamilBYTES_TRANSFER(bytes_transfer_write_i_text, PT_WRITE_I, 32, TEXT)
46801.1Skamil
46811.54Skamil// AUXV
46821.1Skamil
46831.54SkamilBYTES_TRANSFER(bytes_transfer_piod_read_auxv, PIOD_READ_AUXV, 4096, AUXV)
46841.1Skamil
46851.54Skamil/// ----------------------------------------------------------------------------
46861.1Skamil
46871.101Skamilstatic void
46881.101Skamilbytes_transfer_alignment(const char *operation)
46891.101Skamil{
46901.101Skamil	const int exitval = 5;
46911.101Skamil	const int sigval = SIGSTOP;
46921.101Skamil	pid_t child, wpid;
46931.101Skamil#if defined(TWAIT_HAVE_STATUS)
46941.101Skamil	int status;
46951.101Skamil#endif
46961.101Skamil	char *buffer;
46971.101Skamil	int vector;
46981.101Skamil	size_t len;
46991.101Skamil	size_t i;
47001.101Skamil	int op;
47011.101Skamil
47021.101Skamil	struct ptrace_io_desc io;
47031.101Skamil	struct ptrace_siginfo info;
47041.101Skamil
47051.101Skamil	memset(&io, 0, sizeof(io));
47061.101Skamil	memset(&info, 0, sizeof(info));
47071.101Skamil
47081.101Skamil	/* Testing misaligned byte transfer crossing page boundaries */
47091.101Skamil	len = sysconf(_SC_PAGESIZE) * 2;
47101.101Skamil	buffer = malloc(len);
47111.101Skamil	ATF_REQUIRE(buffer != NULL);
47121.101Skamil
47131.101Skamil	/* Initialize the buffer with random data */
47141.101Skamil	for (i = 0; i < len; i++)
47151.101Skamil		buffer[i] = i & 0xff;
47161.101Skamil
47171.101Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
47181.101Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
47191.101Skamil	if (child == 0) {
47201.101Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
47211.101Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
47221.101Skamil
47231.101Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
47241.101Skamil		FORKEE_ASSERT(raise(sigval) == 0);
47251.101Skamil
47261.101Skamil		DPRINTF("Before exiting of the child process\n");
47271.101Skamil		_exit(exitval);
47281.101Skamil	}
47291.101Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
47301.101Skamil
47311.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
47321.101Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
47331.101Skamil
47341.101Skamil	validate_status_stopped(status, sigval);
47351.101Skamil
47361.101Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
47371.101Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info))
47381.101Skamil		!= -1);
47391.101Skamil
47401.101Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
47411.101Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
47421.101Skamil		"si_errno=%#x\n",
47431.101Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
47441.101Skamil		info.psi_siginfo.si_errno);
47451.101Skamil
47461.101Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
47471.101Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
47481.101Skamil
47491.101Skamil	if (strcmp(operation, "PT_READ_I") == 0 ||
47501.101Skamil	    strcmp(operation, "PT_READ_D") == 0) {
47511.101Skamil		if (strcmp(operation, "PT_READ_I"))
47521.101Skamil			op = PT_READ_I;
47531.101Skamil		else
47541.101Skamil			op = PT_READ_D;
47551.101Skamil
47561.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
47571.101Skamil			errno = 0;
47581.101Skamil			vector = ptrace(op, child, buffer + i, 0);
47591.101Skamil			ATF_REQUIRE_EQ(errno, 0);
47601.101Skamil			ATF_REQUIRE(!memcmp(&vector, buffer + i, sizeof(int)));
47611.101Skamil		}
47621.101Skamil	} else if (strcmp(operation, "PT_WRITE_I") == 0 ||
47631.101Skamil	           strcmp(operation, "PT_WRITE_D") == 0) {
47641.101Skamil		if (strcmp(operation, "PT_WRITE_I"))
47651.101Skamil			op = PT_WRITE_I;
47661.101Skamil		else
47671.101Skamil			op = PT_WRITE_D;
47681.101Skamil
47691.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
47701.101Skamil			memcpy(&vector, buffer + i, sizeof(int));
47711.101Skamil			SYSCALL_REQUIRE(ptrace(op, child, buffer + 1, vector)
47721.101Skamil			    != -1);
47731.101Skamil		}
47741.101Skamil	} else if (strcmp(operation, "PIOD_READ_I") == 0 ||
47751.101Skamil	           strcmp(operation, "PIOD_READ_D") == 0) {
47761.101Skamil		if (strcmp(operation, "PIOD_READ_I"))
47771.101Skamil			op = PIOD_READ_I;
47781.101Skamil		else
47791.101Skamil			op = PIOD_READ_D;
47801.101Skamil
47811.101Skamil		io.piod_op = op;
47821.101Skamil		io.piod_addr = &vector;
47831.101Skamil		io.piod_len = sizeof(int);
47841.101Skamil
47851.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
47861.101Skamil			io.piod_offs = buffer + i;
47871.101Skamil
47881.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
47891.101Skamil			                != -1);
47901.101Skamil			ATF_REQUIRE(!memcmp(&vector, buffer + i, sizeof(int)));
47911.101Skamil		}
47921.101Skamil	} else if (strcmp(operation, "PIOD_WRITE_I") == 0 ||
47931.101Skamil	           strcmp(operation, "PIOD_WRITE_D") == 0) {
47941.101Skamil		if (strcmp(operation, "PIOD_WRITE_I"))
47951.101Skamil			op = PIOD_WRITE_I;
47961.101Skamil		else
47971.101Skamil			op = PIOD_WRITE_D;
47981.101Skamil
47991.101Skamil		io.piod_op = op;
48001.101Skamil		io.piod_addr = &vector;
48011.101Skamil		io.piod_len = sizeof(int);
48021.101Skamil
48031.101Skamil		for (i = 0; i <= (len - sizeof(int)); i++) {
48041.101Skamil			io.piod_offs = buffer + i;
48051.101Skamil
48061.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
48071.101Skamil			                != -1);
48081.101Skamil		}
48091.101Skamil	} else if (strcmp(operation, "PIOD_READ_AUXV") == 0) {
48101.101Skamil		io.piod_op = PIOD_READ_AUXV;
48111.101Skamil		io.piod_addr = &vector;
48121.101Skamil		io.piod_len = sizeof(int);
48131.101Skamil
48141.101Skamil		errno = 0;
48151.101Skamil		i = 0;
48161.101Skamil		/* Read the whole AUXV vector, it has no clear length */
48171.120Skamil		while (io.piod_len > 0) {
48181.101Skamil			io.piod_offs = (void *)(intptr_t)i;
48191.101Skamil			SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io))
48201.120Skamil			                != -1 || (io.piod_len == 0 && i > 0));
48211.101Skamil			++i;
48221.101Skamil		}
48231.101Skamil	}
48241.101Skamil
48251.101Skamil	DPRINTF("Before resuming the child process where it left off "
48261.101Skamil	    "and without signal to be sent\n");
48271.101Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
48281.101Skamil
48291.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48301.101Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
48311.101Skamil	    child);
48321.101Skamil
48331.101Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48341.101Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
48351.101Skamil}
48361.101Skamil
48371.101Skamil#define BYTES_TRANSFER_ALIGNMENT(test, operation)			\
48381.101SkamilATF_TC(test);								\
48391.101SkamilATF_TC_HEAD(test, tc)							\
48401.101Skamil{									\
48411.101Skamil	atf_tc_set_md_var(tc, "descr",					\
48421.101Skamil	    "Verify bytes transfer for potentially misaligned "		\
48431.101Skamil	    "operation " operation);					\
48441.101Skamil}									\
48451.101Skamil									\
48461.101SkamilATF_TC_BODY(test, tc)							\
48471.101Skamil{									\
48481.101Skamil									\
48491.101Skamil	bytes_transfer_alignment(operation);				\
48501.101Skamil}
48511.101Skamil
48521.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_read_i, "PT_READ_I")
48531.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_read_d, "PT_READ_D")
48541.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_write_i, "PT_WRITE_I")
48551.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_pt_write_d, "PT_WRITE_D")
48561.101Skamil
48571.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_i, "PIOD_READ_I")
48581.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_d, "PIOD_READ_D")
48591.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_write_i, "PIOD_WRITE_I")
48601.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_write_d, "PIOD_WRITE_D")
48611.101Skamil
48621.101SkamilBYTES_TRANSFER_ALIGNMENT(bytes_transfer_alignment_piod_read_auxv, "PIOD_READ_AUXV")
48631.101Skamil
48641.101Skamil/// ----------------------------------------------------------------------------
48651.101Skamil
48661.115Skamilstatic void
48671.115Skamilbytes_transfer_eof(const char *operation)
48681.115Skamil{
48691.115Skamil	const int exitval = 5;
48701.115Skamil	const int sigval = SIGSTOP;
48711.115Skamil	pid_t child, wpid;
48721.115Skamil#if defined(TWAIT_HAVE_STATUS)
48731.115Skamil	int status;
48741.115Skamil#endif
48751.115Skamil	FILE *fp;
48761.115Skamil	char *p;
48771.115Skamil	int vector;
48781.115Skamil	int op;
48791.115Skamil
48801.115Skamil	struct ptrace_io_desc io;
48811.115Skamil	struct ptrace_siginfo info;
48821.115Skamil
48831.115Skamil	memset(&io, 0, sizeof(io));
48841.115Skamil	memset(&info, 0, sizeof(info));
48851.115Skamil
48861.115Skamil	vector = 0;
48871.115Skamil
48881.115Skamil	fp = tmpfile();
48891.115Skamil	ATF_REQUIRE(fp != NULL);
48901.115Skamil
48911.115Skamil	p = mmap(0, 1, PROT_READ|PROT_WRITE, MAP_PRIVATE, fileno(fp), 0);
48921.115Skamil	ATF_REQUIRE(p != MAP_FAILED);
48931.115Skamil
48941.115Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
48951.115Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
48961.115Skamil	if (child == 0) {
48971.115Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
48981.115Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
48991.115Skamil
49001.115Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
49011.115Skamil		FORKEE_ASSERT(raise(sigval) == 0);
49021.115Skamil
49031.115Skamil		DPRINTF("Before exiting of the child process\n");
49041.115Skamil		_exit(exitval);
49051.115Skamil	}
49061.115Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
49071.115Skamil
49081.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
49091.115Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
49101.115Skamil
49111.115Skamil	validate_status_stopped(status, sigval);
49121.115Skamil
49131.115Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
49141.115Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info))
49151.115Skamil		!= -1);
49161.115Skamil
49171.115Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
49181.115Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
49191.115Skamil		"si_errno=%#x\n",
49201.115Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
49211.115Skamil		info.psi_siginfo.si_errno);
49221.115Skamil
49231.115Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
49241.115Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
49251.115Skamil
49261.115Skamil	if (strcmp(operation, "PT_READ_I") == 0 ||
49271.115Skamil	    strcmp(operation, "PT_READ_D") == 0) {
49281.115Skamil		if (strcmp(operation, "PT_READ_I"))
49291.115Skamil			op = PT_READ_I;
49301.115Skamil		else
49311.115Skamil			op = PT_READ_D;
49321.115Skamil
49331.115Skamil		errno = 0;
49341.115Skamil		SYSCALL_REQUIRE(ptrace(op, child, p, 0) == -1);
49351.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
49361.115Skamil	} else if (strcmp(operation, "PT_WRITE_I") == 0 ||
49371.115Skamil	           strcmp(operation, "PT_WRITE_D") == 0) {
49381.115Skamil		if (strcmp(operation, "PT_WRITE_I"))
49391.115Skamil			op = PT_WRITE_I;
49401.115Skamil		else
49411.115Skamil			op = PT_WRITE_D;
49421.115Skamil
49431.115Skamil		errno = 0;
49441.115Skamil		SYSCALL_REQUIRE(ptrace(op, child, p, vector) == -1);
49451.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
49461.115Skamil	} else if (strcmp(operation, "PIOD_READ_I") == 0 ||
49471.115Skamil	           strcmp(operation, "PIOD_READ_D") == 0) {
49481.115Skamil		if (strcmp(operation, "PIOD_READ_I"))
49491.115Skamil			op = PIOD_READ_I;
49501.115Skamil		else
49511.115Skamil			op = PIOD_READ_D;
49521.115Skamil
49531.115Skamil		io.piod_op = op;
49541.115Skamil		io.piod_addr = &vector;
49551.115Skamil		io.piod_len = sizeof(int);
49561.115Skamil		io.piod_offs = p;
49571.115Skamil
49581.115Skamil		errno = 0;
49591.115Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io)) == -1);
49601.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
49611.115Skamil	} else if (strcmp(operation, "PIOD_WRITE_I") == 0 ||
49621.115Skamil	           strcmp(operation, "PIOD_WRITE_D") == 0) {
49631.115Skamil		if (strcmp(operation, "PIOD_WRITE_I"))
49641.115Skamil			op = PIOD_WRITE_I;
49651.115Skamil		else
49661.115Skamil			op = PIOD_WRITE_D;
49671.115Skamil
49681.115Skamil		io.piod_op = op;
49691.115Skamil		io.piod_addr = &vector;
49701.115Skamil		io.piod_len = sizeof(int);
49711.115Skamil		io.piod_offs = p;
49721.115Skamil
49731.115Skamil		errno = 0;
49741.115Skamil		SYSCALL_REQUIRE(ptrace(PT_IO, child, &io, sizeof(io)) == -1);
49751.115Skamil		ATF_REQUIRE_EQ(errno, EINVAL);
49761.115Skamil	}
49771.115Skamil
49781.115Skamil	DPRINTF("Before resuming the child process where it left off "
49791.115Skamil	    "and without signal to be sent\n");
49801.115Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
49811.115Skamil
49821.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
49831.115Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
49841.115Skamil	    child);
49851.115Skamil
49861.115Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
49871.115Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
49881.115Skamil}
49891.115Skamil
49901.115Skamil#define BYTES_TRANSFER_EOF(test, operation)				\
49911.115SkamilATF_TC(test);								\
49921.115SkamilATF_TC_HEAD(test, tc)							\
49931.115Skamil{									\
49941.115Skamil	atf_tc_set_md_var(tc, "descr",					\
49951.115Skamil	    "Verify bytes EOF byte transfer for the " operation		\
49961.115Skamil	    " operation");						\
49971.115Skamil}									\
49981.115Skamil									\
49991.115SkamilATF_TC_BODY(test, tc)							\
50001.115Skamil{									\
50011.115Skamil									\
50021.115Skamil	bytes_transfer_eof(operation);					\
50031.115Skamil}
50041.115Skamil
50051.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_read_i, "PT_READ_I")
50061.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_read_d, "PT_READ_D")
50071.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_write_i, "PT_WRITE_I")
50081.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_pt_write_d, "PT_WRITE_D")
50091.115Skamil
50101.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_read_i, "PIOD_READ_I")
50111.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_read_d, "PIOD_READ_D")
50121.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_i, "PIOD_WRITE_I")
50131.115SkamilBYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_d, "PIOD_WRITE_D")
50141.115Skamil
50151.115Skamil/// ----------------------------------------------------------------------------
50161.115Skamil
50171.1Skamil#if defined(PT_STEP)
50181.1Skamilstatic void
50191.95Skamilptrace_step(int N, int setstep, bool masked, bool ignored)
50201.1Skamil{
50211.1Skamil	const int exitval = 5;
50221.1Skamil	const int sigval = SIGSTOP;
50231.1Skamil	pid_t child, wpid;
50241.1Skamil#if defined(TWAIT_HAVE_STATUS)
50251.1Skamil	int status;
50261.1Skamil#endif
50271.1Skamil	int happy;
50281.95Skamil	struct sigaction sa;
50291.81Skamil	struct ptrace_siginfo info;
50301.95Skamil	sigset_t intmask;
50311.95Skamil	struct kinfo_proc2 kp;
50321.95Skamil	size_t len = sizeof(kp);
50331.95Skamil
50341.95Skamil	int name[6];
50351.95Skamil	const size_t namelen = __arraycount(name);
50361.95Skamil	ki_sigset_t kp_sigmask;
50371.95Skamil	ki_sigset_t kp_sigignore;
50381.1Skamil
50391.1Skamil#if defined(__arm__)
50401.1Skamil	/* PT_STEP not supported on arm 32-bit */
50411.1Skamil	atf_tc_expect_fail("PR kern/52119");
50421.1Skamil#endif
50431.1Skamil
50441.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
50451.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
50461.1Skamil	if (child == 0) {
50471.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
50481.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
50491.1Skamil
50501.95Skamil		if (masked) {
50511.95Skamil			sigemptyset(&intmask);
50521.95Skamil			sigaddset(&intmask, SIGTRAP);
50531.95Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
50541.95Skamil		}
50551.95Skamil
50561.95Skamil		if (ignored) {
50571.95Skamil			memset(&sa, 0, sizeof(sa));
50581.95Skamil			sa.sa_handler = SIG_IGN;
50591.95Skamil			sigemptyset(&sa.sa_mask);
50601.95Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
50611.95Skamil		}
50621.95Skamil
50631.1Skamil		happy = check_happy(999);
50641.1Skamil
50651.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
50661.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
50671.1Skamil
50681.1Skamil		FORKEE_ASSERT_EQ(happy, check_happy(999));
50691.1Skamil
50701.13Schristos		DPRINTF("Before exiting of the child process\n");
50711.1Skamil		_exit(exitval);
50721.1Skamil	}
50731.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
50741.1Skamil
50751.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
50761.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
50771.1Skamil
50781.1Skamil	validate_status_stopped(status, sigval);
50791.1Skamil
50801.81Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
50811.81Skamil	SYSCALL_REQUIRE(
50821.81Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
50831.81Skamil
50841.81Skamil	DPRINTF("Before checking siginfo_t\n");
50851.81Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
50861.81Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
50871.81Skamil
50881.95Skamil	name[0] = CTL_KERN,
50891.95Skamil	name[1] = KERN_PROC2,
50901.95Skamil	name[2] = KERN_PROC_PID;
50911.95Skamil	name[3] = child;
50921.95Skamil	name[4] = sizeof(kp);
50931.95Skamil	name[5] = 1;
50941.95Skamil
50951.95Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
50961.95Skamil
50971.95Skamil	if (masked)
50981.95Skamil		kp_sigmask = kp.p_sigmask;
50991.95Skamil
51001.95Skamil	if (ignored)
51011.95Skamil		kp_sigignore = kp.p_sigignore;
51021.95Skamil
51031.1Skamil	while (N --> 0) {
51041.2Skamil		if (setstep) {
51051.13Schristos			DPRINTF("Before resuming the child process where it "
51061.2Skamil			    "left off and without signal to be sent (use "
51071.9Skamil			    "PT_SETSTEP and PT_CONTINUE)\n");
51081.13Schristos			SYSCALL_REQUIRE(ptrace(PT_SETSTEP, child, 0, 0) != -1);
51091.13Schristos			SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0)
51101.2Skamil			    != -1);
51111.2Skamil		} else {
51121.13Schristos			DPRINTF("Before resuming the child process where it "
51131.2Skamil			    "left off and without signal to be sent (use "
51141.2Skamil			    "PT_STEP)\n");
51151.13Schristos			SYSCALL_REQUIRE(ptrace(PT_STEP, child, (void *)1, 0)
51161.2Skamil			    != -1);
51171.2Skamil		}
51181.1Skamil
51191.13Schristos		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
51201.1Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
51211.1Skamil		    child);
51221.1Skamil
51231.1Skamil		validate_status_stopped(status, SIGTRAP);
51241.2Skamil
51251.81Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
51261.81Skamil		SYSCALL_REQUIRE(
51271.81Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
51281.81Skamil
51291.81Skamil		DPRINTF("Before checking siginfo_t\n");
51301.81Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
51311.81Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_TRACE);
51321.81Skamil
51331.2Skamil		if (setstep) {
51341.13Schristos			SYSCALL_REQUIRE(ptrace(PT_CLEARSTEP, child, 0, 0) != -1);
51351.2Skamil		}
51361.95Skamil
51371.95Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
51381.95Skamil
51391.95Skamil		if (masked) {
51401.95Skamil			DPRINTF("kp_sigmask="
51411.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
51421.95Skamil			    PRIx32 "\n",
51431.95Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
51441.95Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
51451.95Skamil
51461.95Skamil			DPRINTF("kp.p_sigmask="
51471.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
51481.95Skamil			    PRIx32 "\n",
51491.95Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
51501.95Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
51511.95Skamil
51521.95Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
51531.95Skamil			    sizeof(kp_sigmask)));
51541.95Skamil		}
51551.95Skamil
51561.95Skamil		if (ignored) {
51571.95Skamil			DPRINTF("kp_sigignore="
51581.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
51591.95Skamil			    PRIx32 "\n",
51601.95Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
51611.95Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
51621.95Skamil
51631.95Skamil			DPRINTF("kp.p_sigignore="
51641.95Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
51651.95Skamil			    PRIx32 "\n",
51661.95Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
51671.95Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
51681.95Skamil
51691.95Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
51701.95Skamil			    sizeof(kp_sigignore)));
51711.95Skamil		}
51721.1Skamil	}
51731.1Skamil
51741.13Schristos	DPRINTF("Before resuming the child process where it left off and "
51751.1Skamil	    "without signal to be sent\n");
51761.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
51771.1Skamil
51781.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
51791.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
51801.1Skamil
51811.1Skamil	validate_status_exited(status, exitval);
51821.1Skamil
51831.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
51841.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
51851.1Skamil}
51861.1Skamil
51871.73Skamil#define PTRACE_STEP(test, N, setstep)					\
51881.73SkamilATF_TC(test);								\
51891.73SkamilATF_TC_HEAD(test, tc)							\
51901.73Skamil{									\
51911.73Skamil        atf_tc_set_md_var(tc, "descr",					\
51921.74Skamil            "Verify " #N " (PT_SETSTEP set to: " #setstep ")");		\
51931.73Skamil}									\
51941.73Skamil									\
51951.73SkamilATF_TC_BODY(test, tc)							\
51961.73Skamil{									\
51971.73Skamil									\
51981.95Skamil        ptrace_step(N, setstep, false, false);				\
51991.1Skamil}
52001.1Skamil
52011.73SkamilPTRACE_STEP(step1, 1, 0)
52021.73SkamilPTRACE_STEP(step2, 2, 0)
52031.73SkamilPTRACE_STEP(step3, 3, 0)
52041.73SkamilPTRACE_STEP(step4, 4, 0)
52051.73SkamilPTRACE_STEP(setstep1, 1, 1)
52061.73SkamilPTRACE_STEP(setstep2, 2, 1)
52071.73SkamilPTRACE_STEP(setstep3, 3, 1)
52081.73SkamilPTRACE_STEP(setstep4, 4, 1)
52091.95Skamil
52101.95SkamilATF_TC(step_signalmasked);
52111.95SkamilATF_TC_HEAD(step_signalmasked, tc)
52121.95Skamil{
52131.95Skamil	atf_tc_set_md_var(tc, "descr", "Verify PT_STEP with masked SIGTRAP");
52141.95Skamil}
52151.95Skamil
52161.95SkamilATF_TC_BODY(step_signalmasked, tc)
52171.95Skamil{
52181.95Skamil
52191.95Skamil	ptrace_step(1, 0, true, false);
52201.95Skamil}
52211.95Skamil
52221.95SkamilATF_TC(step_signalignored);
52231.95SkamilATF_TC_HEAD(step_signalignored, tc)
52241.95Skamil{
52251.95Skamil	atf_tc_set_md_var(tc, "descr", "Verify PT_STEP with ignored SIGTRAP");
52261.95Skamil}
52271.95Skamil
52281.95SkamilATF_TC_BODY(step_signalignored, tc)
52291.95Skamil{
52301.95Skamil
52311.95Skamil	ptrace_step(1, 0, false, true);
52321.95Skamil}
52331.1Skamil#endif
52341.1Skamil
52351.73Skamil/// ----------------------------------------------------------------------------
52361.1Skamil
52371.75Skamilstatic void
52381.75Skamilptrace_kill(const char *type)
52391.1Skamil{
52401.75Skamil	const int sigval = SIGSTOP;
52411.1Skamil	pid_t child, wpid;
52421.1Skamil#if defined(TWAIT_HAVE_STATUS)
52431.1Skamil	int status;
52441.1Skamil#endif
52451.1Skamil
52461.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
52471.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
52481.1Skamil	if (child == 0) {
52491.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
52501.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
52511.1Skamil
52521.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
52531.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
52541.1Skamil
52551.1Skamil		/* NOTREACHED */
52561.1Skamil		FORKEE_ASSERTX(0 &&
52571.1Skamil		    "Child should be terminated by a signal from its parent");
52581.1Skamil	}
52591.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
52601.1Skamil
52611.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
52621.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
52631.1Skamil
52641.1Skamil	validate_status_stopped(status, sigval);
52651.1Skamil
52661.75Skamil	DPRINTF("Before killing the child process with %s\n", type);
52671.75Skamil	if (strcmp(type, "ptrace(PT_KILL)") == 0) {
52681.75Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void*)1, 0) != -1);
52691.75Skamil	} else if (strcmp(type, "kill(SIGKILL)") == 0) {
52701.75Skamil		kill(child, SIGKILL);
52711.75Skamil	} else if (strcmp(type, "killpg(SIGKILL)") == 0) {
52721.75Skamil		setpgid(child, 0);
52731.75Skamil		killpg(getpgid(child), SIGKILL);
52741.75Skamil	}
52751.1Skamil
52761.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
52771.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
52781.1Skamil
52791.75Skamil	validate_status_signaled(status, SIGKILL, 0);
52801.1Skamil
52811.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
52821.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
52831.1Skamil}
52841.1Skamil
52851.75Skamil#define PTRACE_KILL(test, type)						\
52861.75SkamilATF_TC(test);								\
52871.75SkamilATF_TC_HEAD(test, tc)							\
52881.75Skamil{									\
52891.75Skamil        atf_tc_set_md_var(tc, "descr",					\
52901.75Skamil            "Verify killing the child with " type);			\
52911.75Skamil}									\
52921.75Skamil									\
52931.75SkamilATF_TC_BODY(test, tc)							\
52941.75Skamil{									\
52951.75Skamil									\
52961.75Skamil        ptrace_kill(type);						\
52971.1Skamil}
52981.1Skamil
52991.75Skamil// PT_CONTINUE with SIGKILL is covered by traceme_sendsignal_simple1
53001.75SkamilPTRACE_KILL(kill1, "ptrace(PT_KILL)")
53011.75SkamilPTRACE_KILL(kill2, "kill(SIGKILL)")
53021.75SkamilPTRACE_KILL(kill3, "killpg(SIGKILL)")
53031.1Skamil
53041.75Skamil/// ----------------------------------------------------------------------------
53051.1Skamil
53061.143Skamilstatic int lwpinfo_thread_sigmask[] = {SIGXCPU, SIGPIPE, SIGALRM, SIGURG};
53071.143Skamil
53081.143Skamilstatic pthread_mutex_t lwpinfo_thread_mtx = PTHREAD_MUTEX_INITIALIZER;
53091.143Skamilstatic pthread_cond_t lwpinfo_thread_cnd = PTHREAD_COND_INITIALIZER;
53101.143Skamilstatic volatile size_t lwpinfo_thread_done;
53111.143Skamil
53121.143Skamilstatic void *
53131.143Skamillwpinfo_thread(void *arg)
53141.143Skamil{
53151.143Skamil	sigset_t s;
53161.143Skamil	volatile void **tcb;
53171.143Skamil
53181.143Skamil	tcb = (volatile void **)arg;
53191.143Skamil
53201.145Skamil	*tcb = _lwp_getprivate();
53211.143Skamil	DPRINTF("Storing tcb[] = %p from thread %d\n", *tcb, _lwp_self());
53221.143Skamil
53231.143Skamil	pthread_setname_np(pthread_self(), "thread %d",
53241.143Skamil	    (void *)(intptr_t)_lwp_self());
53251.143Skamil
53261.143Skamil	sigemptyset(&s);
53271.143Skamil	pthread_mutex_lock(&lwpinfo_thread_mtx);
53281.143Skamil	sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
53291.143Skamil	lwpinfo_thread_done++;
53301.143Skamil	pthread_sigmask(SIG_BLOCK, &s, NULL);
53311.143Skamil	pthread_cond_signal(&lwpinfo_thread_cnd);
53321.143Skamil	pthread_mutex_unlock(&lwpinfo_thread_mtx);
53331.143Skamil
53341.143Skamil	return infinite_thread(NULL);
53351.143Skamil}
53361.143Skamil
53371.77Skamilstatic void
53381.143Skamiltraceme_lwpinfo(const size_t threads, const char *iter)
53391.1Skamil{
53401.1Skamil	const int sigval = SIGSTOP;
53411.77Skamil	const int sigval2 = SIGINT;
53421.1Skamil	pid_t child, wpid;
53431.1Skamil#if defined(TWAIT_HAVE_STATUS)
53441.1Skamil	int status;
53451.1Skamil#endif
53461.77Skamil	struct ptrace_lwpinfo lwp = {0, 0};
53471.143Skamil	struct ptrace_lwpstatus lwpstatus = {0};
53481.77Skamil	struct ptrace_siginfo info;
53491.143Skamil	void *private;
53501.143Skamil	char *name;
53511.143Skamil	char namebuf[PL_LNAMELEN];
53521.143Skamil	volatile void *tcb[4];
53531.143Skamil	bool found;
53541.143Skamil	sigset_t s;
53551.77Skamil
53561.77Skamil	/* Maximum number of supported threads in this test */
53571.143Skamil	pthread_t t[__arraycount(tcb) - 1];
53581.143Skamil	size_t n, m;
53591.143Skamil	int rv;
53601.143Skamil	size_t bytes_read;
53611.143Skamil
53621.143Skamil	struct ptrace_io_desc io;
53631.143Skamil	sigset_t sigmask;
53641.77Skamil
53651.143Skamil	ATF_REQUIRE(__arraycount(t) >= threads);
53661.143Skamil	memset(tcb, 0, sizeof(tcb));
53671.1Skamil
53681.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
53691.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
53701.1Skamil	if (child == 0) {
53711.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
53721.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
53731.1Skamil
53741.145Skamil		tcb[0] = _lwp_getprivate();
53751.143Skamil		DPRINTF("Storing tcb[0] = %p\n", tcb[0]);
53761.143Skamil
53771.143Skamil		pthread_setname_np(pthread_self(), "thread %d",
53781.143Skamil		    (void *)(intptr_t)_lwp_self());
53791.143Skamil
53801.143Skamil		sigemptyset(&s);
53811.143Skamil		sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
53821.143Skamil		pthread_sigmask(SIG_BLOCK, &s, NULL);
53831.143Skamil
53841.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
53851.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
53861.1Skamil
53871.77Skamil		for (n = 0; n < threads; n++) {
53881.143Skamil			rv = pthread_create(&t[n], NULL, lwpinfo_thread,
53891.143Skamil			    &tcb[n + 1]);
53901.77Skamil			FORKEE_ASSERT(rv == 0);
53911.77Skamil		}
53921.77Skamil
53931.143Skamil		pthread_mutex_lock(&lwpinfo_thread_mtx);
53941.143Skamil		while (lwpinfo_thread_done < threads) {
53951.143Skamil			pthread_cond_wait(&lwpinfo_thread_cnd,
53961.143Skamil			    &lwpinfo_thread_mtx);
53971.143Skamil		}
53981.143Skamil		pthread_mutex_unlock(&lwpinfo_thread_mtx);
53991.143Skamil
54001.77Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval2));
54011.77Skamil		FORKEE_ASSERT(raise(sigval2) == 0);
54021.77Skamil
54031.77Skamil		/* NOTREACHED */
54041.77Skamil		FORKEE_ASSERTX(0 && "Not reached");
54051.1Skamil	}
54061.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
54071.1Skamil
54081.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
54091.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
54101.1Skamil
54111.1Skamil	validate_status_stopped(status, sigval);
54121.1Skamil
54131.77Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
54141.77Skamil	SYSCALL_REQUIRE(
54151.77Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
54161.77Skamil
54171.77Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
54181.77Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
54191.77Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
54201.77Skamil	    info.psi_siginfo.si_errno);
54211.77Skamil
54221.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
54231.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
54241.77Skamil
54251.143Skamil	if (strstr(iter, "LWPINFO") != NULL) {
54261.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
54271.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
54281.143Skamil		    != -1);
54291.1Skamil
54301.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
54311.143Skamil		ATF_REQUIRE(lwp.pl_lwpid > 0);
54321.1Skamil
54331.143Skamil		DPRINTF("Assert that lwp thread %d received event "
54341.143Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
54351.143Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
54361.143Skamil
54371.143Skamil		if (strstr(iter, "LWPSTATUS") != NULL) {
54381.143Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPSTATUS "
54391.143Skamil			    "for child\n");
54401.143Skamil			lwpstatus.pl_lwpid = lwp.pl_lwpid;
54411.143Skamil			SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child, &lwpstatus,
54421.143Skamil			    sizeof(lwpstatus)) != -1);
54431.143Skamil		}
54441.1Skamil
54451.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
54461.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
54471.143Skamil		    != -1);
54481.1Skamil
54491.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
54501.143Skamil		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
54511.143Skamil	} else {
54521.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
54531.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
54541.143Skamil		    sizeof(lwpstatus)) != -1);
54551.143Skamil
54561.143Skamil		DPRINTF("Assert that there exists a single thread only %d\n", lwpstatus.pl_lwpid);
54571.143Skamil		ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
54581.143Skamil
54591.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
54601.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
54611.143Skamil		    sizeof(lwpstatus)) != -1);
54621.143Skamil
54631.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
54641.143Skamil		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
54651.143Skamil	}
54661.1Skamil
54671.13Schristos	DPRINTF("Before resuming the child process where it left off and "
54681.1Skamil	    "without signal to be sent\n");
54691.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
54701.1Skamil
54711.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
54721.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
54731.1Skamil
54741.77Skamil	validate_status_stopped(status, sigval2);
54751.77Skamil
54761.77Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
54771.77Skamil	SYSCALL_REQUIRE(
54781.77Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
54791.77Skamil
54801.77Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
54811.77Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
54821.77Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
54831.77Skamil	    info.psi_siginfo.si_errno);
54841.77Skamil
54851.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval2);
54861.77Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
54871.77Skamil
54881.77Skamil	memset(&lwp, 0, sizeof(lwp));
54891.143Skamil	memset(&lwpstatus, 0, sizeof(lwpstatus));
54901.143Skamil
54911.143Skamil	memset(&io, 0, sizeof(io));
54921.143Skamil
54931.143Skamil	bytes_read = 0;
54941.143Skamil	io.piod_op = PIOD_READ_D;
54951.143Skamil	io.piod_len = sizeof(tcb);
54961.143Skamil
54971.143Skamil	do {
54981.143Skamil		io.piod_addr = (char *)&tcb + bytes_read;
54991.143Skamil		io.piod_offs = io.piod_addr;
55001.143Skamil
55011.143Skamil		rv = ptrace(PT_IO, child, &io, sizeof(io));
55021.143Skamil		ATF_REQUIRE(rv != -1 && io.piod_len != 0);
55031.143Skamil
55041.143Skamil		bytes_read += io.piod_len;
55051.143Skamil		io.piod_len = sizeof(tcb) - bytes_read;
55061.143Skamil	} while (bytes_read < sizeof(tcb));
55071.77Skamil
55081.77Skamil	for (n = 0; n <= threads; n++) {
55091.143Skamil		if (strstr(iter, "LWPINFO") != NULL) {
55101.143Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
55111.143Skamil			    "child\n");
55121.143Skamil			SYSCALL_REQUIRE(
55131.143Skamil			    ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
55141.143Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
55151.143Skamil
55161.143Skamil			DPRINTF("Assert that the thread exists\n");
55171.143Skamil			ATF_REQUIRE(lwp.pl_lwpid > 0);
55181.143Skamil
55191.143Skamil			DPRINTF("Assert that lwp thread %d received expected "
55201.143Skamil			    "event\n", lwp.pl_lwpid);
55211.143Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
55221.143Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
55231.143Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
55241.143Skamil
55251.143Skamil			if (strstr(iter, "LWPSTATUS") != NULL) {
55261.143Skamil				DPRINTF("Before calling ptrace(2) with "
55271.143Skamil				    "PT_LWPSTATUS for child\n");
55281.143Skamil				lwpstatus.pl_lwpid = lwp.pl_lwpid;
55291.143Skamil				SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child,
55301.143Skamil				    &lwpstatus, sizeof(lwpstatus)) != -1);
55311.143Skamil
55321.143Skamil				goto check_lwpstatus;
55331.143Skamil			}
55341.143Skamil		} else {
55351.143Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for "
55361.143Skamil			    "child\n");
55371.143Skamil			SYSCALL_REQUIRE(
55381.143Skamil			    ptrace(PT_LWPNEXT, child, &lwpstatus,
55391.143Skamil			    sizeof(lwpstatus)) != -1);
55401.143Skamil			DPRINTF("LWP=%d\n", lwpstatus.pl_lwpid);
55411.143Skamil
55421.143Skamil			DPRINTF("Assert that the thread exists\n");
55431.143Skamil			ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
55441.143Skamil
55451.143Skamil		check_lwpstatus:
55461.143Skamil
55471.143Skamil			if (strstr(iter, "pl_sigmask") != NULL) {
55481.143Skamil				sigmask = lwpstatus.pl_sigmask;
55491.143Skamil
55501.143Skamil				DPRINTF("Retrieved sigmask: "
55511.143Skamil				    "%02x%02x%02x%02x\n",
55521.143Skamil				    sigmask.__bits[0], sigmask.__bits[1],
55531.143Skamil				    sigmask.__bits[2], sigmask.__bits[3]);
55541.143Skamil
55551.143Skamil				found = false;
55561.143Skamil				for (m = 0;
55571.143Skamil				     m < __arraycount(lwpinfo_thread_sigmask);
55581.143Skamil				     m++) {
55591.143Skamil					if (sigismember(&sigmask,
55601.143Skamil					    lwpinfo_thread_sigmask[m])) {
55611.143Skamil						found = true;
55621.143Skamil						lwpinfo_thread_sigmask[m] = 0;
55631.143Skamil						break;
55641.143Skamil					}
55651.143Skamil				}
55661.143Skamil				ATF_REQUIRE(found == true);
55671.143Skamil			} else if (strstr(iter, "pl_name") != NULL) {
55681.143Skamil				name = lwpstatus.pl_name;
55691.143Skamil
55701.143Skamil				DPRINTF("Retrieved thread name: "
55711.143Skamil				    "%s\n", name);
55721.143Skamil
55731.143Skamil				snprintf(namebuf, sizeof namebuf, "thread %d",
55741.143Skamil				    lwpstatus.pl_lwpid);
55751.143Skamil
55761.143Skamil				ATF_REQUIRE(strcmp(name, namebuf) == 0);
55771.143Skamil			} else if (strstr(iter, "pl_private") != NULL) {
55781.143Skamil				private = lwpstatus.pl_private;
55791.143Skamil
55801.143Skamil				DPRINTF("Retrieved thread private pointer: "
55811.143Skamil				    "%p\n", private);
55821.143Skamil
55831.143Skamil				found = false;
55841.143Skamil				for (m = 0; m < __arraycount(tcb); m++) {
55851.143Skamil					DPRINTF("Comparing %p and %p\n",
55861.143Skamil					    private, tcb[m]);
55871.143Skamil					if (private == tcb[m]) {
55881.143Skamil						found = true;
55891.143Skamil						break;
55901.143Skamil					}
55911.143Skamil				}
55921.143Skamil				ATF_REQUIRE(found == true);
55931.143Skamil			}
55941.143Skamil		}
55951.143Skamil	}
55961.143Skamil
55971.143Skamil	if (strstr(iter, "LWPINFO") != NULL) {
55981.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
55991.143Skamil		    "child\n");
56001.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
56011.143Skamil		    != -1);
56021.77Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
56031.77Skamil
56041.143Skamil		DPRINTF("Assert that there are no more threads\n");
56051.143Skamil		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
56061.143Skamil	} else {
56071.143Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
56081.143Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
56091.143Skamil		    sizeof(lwpstatus)) != -1);
56101.77Skamil
56111.143Skamil		DPRINTF("Assert that there exists a single thread only\n");
56121.143Skamil		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
56131.143Skamil	}
56141.77Skamil
56151.77Skamil	DPRINTF("Before resuming the child process where it left off and "
56161.77Skamil	    "without signal to be sent\n");
56171.77Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, SIGKILL) != -1);
56181.77Skamil
56191.77Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
56201.77Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
56211.77Skamil
56221.77Skamil	validate_status_signaled(status, SIGKILL, 0);
56231.1Skamil
56241.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
56251.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
56261.1Skamil}
56271.1Skamil
56281.143Skamil#define TRACEME_LWPINFO(test, threads, iter)				\
56291.77SkamilATF_TC(test);								\
56301.77SkamilATF_TC_HEAD(test, tc)							\
56311.77Skamil{									\
56321.77Skamil	atf_tc_set_md_var(tc, "descr",					\
56331.143Skamil	    "Verify " iter " with the child with " #threads		\
56341.77Skamil	    " spawned extra threads");					\
56351.77Skamil}									\
56361.77Skamil									\
56371.77SkamilATF_TC_BODY(test, tc)							\
56381.77Skamil{									\
56391.77Skamil									\
56401.143Skamil	traceme_lwpinfo(threads, iter);					\
56411.1Skamil}
56421.1Skamil
56431.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0, 0, "LWPINFO")
56441.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1, 1, "LWPINFO")
56451.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2, 2, "LWPINFO")
56461.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3, 3, "LWPINFO")
56471.143Skamil
56481.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus, 0, "LWPINFO+LWPSTATUS")
56491.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus, 1, "LWPINFO+LWPSTATUS")
56501.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus, 2, "LWPINFO+LWPSTATUS")
56511.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus, 3, "LWPINFO+LWPSTATUS")
56521.143Skamil
56531.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_sigmask, 0,
56541.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
56551.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_sigmask, 1,
56561.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
56571.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_sigmask, 2,
56581.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
56591.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_sigmask, 3,
56601.143Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
56611.143Skamil
56621.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_name, 0,
56631.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
56641.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_name, 1,
56651.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
56661.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_name, 2,
56671.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
56681.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_name, 3,
56691.143Skamil    "LWPINFO+LWPSTATUS+pl_name")
56701.143Skamil
56711.143SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_private, 0,
56721.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
56731.143SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_private, 1,
56741.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
56751.143SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_private, 2,
56761.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
56771.143SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_private, 3,
56781.143Skamil    "LWPINFO+LWPSTATUS+pl_private")
56791.143Skamil
56801.143SkamilTRACEME_LWPINFO(traceme_lwpnext0, 0, "LWPNEXT")
56811.143SkamilTRACEME_LWPINFO(traceme_lwpnext1, 1, "LWPNEXT")
56821.143SkamilTRACEME_LWPINFO(traceme_lwpnext2, 2, "LWPNEXT")
56831.143SkamilTRACEME_LWPINFO(traceme_lwpnext3, 3, "LWPNEXT")
56841.143Skamil
56851.143SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_sigmask, 0, "LWPNEXT+pl_sigmask")
56861.143SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_sigmask, 1, "LWPNEXT+pl_sigmask")
56871.143SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_sigmask, 2, "LWPNEXT+pl_sigmask")
56881.143SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_sigmask, 3, "LWPNEXT+pl_sigmask")
56891.143Skamil
56901.143SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_name, 0, "LWPNEXT+pl_name")
56911.143SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_name, 1, "LWPNEXT+pl_name")
56921.143SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_name, 2, "LWPNEXT+pl_name")
56931.143SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_name, 3, "LWPNEXT+pl_name")
56941.143Skamil
56951.143SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_private, 0, "LWPNEXT+pl_private")
56961.143SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_private, 1, "LWPNEXT+pl_private")
56971.143SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_private, 2, "LWPNEXT+pl_private")
56981.143SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_private, 3, "LWPNEXT+pl_private")
56991.77Skamil
57001.77Skamil/// ----------------------------------------------------------------------------
57011.77Skamil
57021.77Skamil#if defined(TWAIT_HAVE_PID)
57031.77Skamilstatic void
57041.77Skamilattach_lwpinfo(const int threads)
57051.1Skamil{
57061.77Skamil	const int sigval = SIGINT;
57071.1Skamil	struct msg_fds parent_tracee, parent_tracer;
57081.1Skamil	const int exitval_tracer = 10;
57091.1Skamil	pid_t tracee, tracer, wpid;
57101.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
57111.1Skamil#if defined(TWAIT_HAVE_STATUS)
57121.1Skamil	int status;
57131.1Skamil#endif
57141.77Skamil	struct ptrace_lwpinfo lwp = {0, 0};
57151.77Skamil	struct ptrace_siginfo info;
57161.77Skamil
57171.77Skamil	/* Maximum number of supported threads in this test */
57181.77Skamil	pthread_t t[3];
57191.77Skamil	int n, rv;
57201.1Skamil
57211.13Schristos	DPRINTF("Spawn tracee\n");
57221.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
57231.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
57241.1Skamil	tracee = atf_utils_fork();
57251.1Skamil	if (tracee == 0) {
57261.1Skamil		/* Wait for message from the parent */
57271.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
57281.1Skamil
57291.77Skamil		CHILD_FROM_PARENT("spawn threads", parent_tracee, msg);
57301.77Skamil
57311.77Skamil		for (n = 0; n < threads; n++) {
57321.77Skamil			rv = pthread_create(&t[n], NULL, infinite_thread, NULL);
57331.77Skamil			FORKEE_ASSERT(rv == 0);
57341.77Skamil		}
57351.77Skamil
57361.77Skamil		CHILD_TO_PARENT("tracee exit", parent_tracee, msg);
57371.77Skamil
57381.77Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
57391.77Skamil		FORKEE_ASSERT(raise(sigval) == 0);
57401.77Skamil
57411.77Skamil		/* NOTREACHED */
57421.77Skamil		FORKEE_ASSERTX(0 && "Not reached");
57431.1Skamil	}
57441.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
57451.1Skamil
57461.13Schristos	DPRINTF("Spawn debugger\n");
57471.1Skamil	tracer = atf_utils_fork();
57481.1Skamil	if (tracer == 0) {
57491.1Skamil		/* No IPC to communicate with the child */
57501.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
57511.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
57521.1Skamil
57531.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
57541.1Skamil		FORKEE_REQUIRE_SUCCESS(
57551.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
57561.1Skamil
57571.1Skamil		forkee_status_stopped(status, SIGSTOP);
57581.1Skamil
57591.77Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
57601.77Skamil		    "tracee");
57611.77Skamil		FORKEE_ASSERT(
57621.77Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
57631.77Skamil
57641.77Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
57651.77Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
57661.77Skamil		    "si_errno=%#x\n",
57671.77Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
57681.77Skamil		    info.psi_siginfo.si_errno);
57691.77Skamil
57701.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
57711.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
57721.77Skamil
57731.13Schristos		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
57741.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
57751.1Skamil		    != -1);
57761.1Skamil
57771.13Schristos		DPRINTF("Assert that there exists a thread\n");
57781.77Skamil		FORKEE_ASSERTX(lwp.pl_lwpid > 0);
57791.1Skamil
57801.13Schristos		DPRINTF("Assert that lwp thread %d received event "
57811.77Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
57821.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
57831.1Skamil
57841.77Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
57851.77Skamil		    "tracee\n");
57861.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
57871.1Skamil		    != -1);
57881.1Skamil
57891.77Skamil		DPRINTF("Assert that there are no more lwp threads in "
57901.77Skamil		    "tracee\n");
57911.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
57921.1Skamil
57931.1Skamil		/* Resume tracee with PT_CONTINUE */
57941.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
57951.1Skamil
57961.1Skamil		/* Inform parent that tracer has attached to tracee */
57971.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
57981.77Skamil
57991.1Skamil		/* Wait for parent */
58001.1Skamil		CHILD_FROM_PARENT("tracer wait", parent_tracer, msg);
58011.1Skamil
58021.77Skamil		/* Wait for tracee and assert that it raised a signal */
58031.77Skamil		FORKEE_REQUIRE_SUCCESS(
58041.77Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
58051.77Skamil
58061.77Skamil		forkee_status_stopped(status, SIGINT);
58071.77Skamil
58081.77Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
58091.77Skamil		    "child");
58101.77Skamil		FORKEE_ASSERT(
58111.77Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
58121.77Skamil
58131.77Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
58141.77Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
58151.77Skamil		    "si_errno=%#x\n",
58161.77Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
58171.77Skamil		    info.psi_siginfo.si_errno);
58181.77Skamil
58191.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
58201.77Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
58211.77Skamil
58221.77Skamil		memset(&lwp, 0, sizeof(lwp));
58231.77Skamil
58241.77Skamil		for (n = 0; n <= threads; n++) {
58251.77Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
58261.77Skamil			    "child\n");
58271.77Skamil			FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp,
58281.77Skamil			    sizeof(lwp)) != -1);
58291.77Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
58301.77Skamil
58311.77Skamil			DPRINTF("Assert that the thread exists\n");
58321.77Skamil			FORKEE_ASSERT(lwp.pl_lwpid > 0);
58331.77Skamil
58341.77Skamil			DPRINTF("Assert that lwp thread %d received expected "
58351.77Skamil			    "event\n", lwp.pl_lwpid);
58361.77Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
58371.77Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
58381.77Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
58391.77Skamil		}
58401.77Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
58411.77Skamil		    "tracee\n");
58421.77Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
58431.77Skamil		    != -1);
58441.77Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
58451.77Skamil
58461.77Skamil		DPRINTF("Assert that there are no more threads\n");
58471.77Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
58481.77Skamil
58491.77Skamil		DPRINTF("Before resuming the child process where it left off "
58501.77Skamil		    "and without signal to be sent\n");
58511.77Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, SIGKILL)
58521.77Skamil		    != -1);
58531.77Skamil
58541.1Skamil		/* Wait for tracee and assert that it exited */
58551.1Skamil		FORKEE_REQUIRE_SUCCESS(
58561.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
58571.1Skamil
58581.77Skamil		forkee_status_signaled(status, SIGKILL, 0);
58591.1Skamil
58601.13Schristos		DPRINTF("Before exiting of the tracer process\n");
58611.1Skamil		_exit(exitval_tracer);
58621.1Skamil	}
58631.1Skamil
58641.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
58651.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
58661.1Skamil
58671.77Skamil	DPRINTF("Resume the tracee and spawn threads\n");
58681.77Skamil	PARENT_TO_CHILD("spawn threads", parent_tracee, msg);
58691.77Skamil
58701.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
58711.77Skamil	PARENT_FROM_CHILD("tracee exit", parent_tracee, msg);
58721.1Skamil
58731.77Skamil	DPRINTF("Resume the tracer and let it detect multiple threads\n");
58741.1Skamil	PARENT_TO_CHILD("tracer wait", parent_tracer, msg);
58751.1Skamil
58761.13Schristos	DPRINTF("Wait for tracer to finish its job and exit - calling %s()\n",
58771.1Skamil	    TWAIT_FNAME);
58781.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
58791.1Skamil	    tracer);
58801.1Skamil
58811.1Skamil	validate_status_exited(status, exitval_tracer);
58821.1Skamil
58831.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
58841.1Skamil	    TWAIT_FNAME);
58851.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
58861.1Skamil	    tracee);
58871.1Skamil
58881.77Skamil	validate_status_signaled(status, SIGKILL, 0);
58891.1Skamil
58901.1Skamil	msg_close(&parent_tracer);
58911.1Skamil	msg_close(&parent_tracee);
58921.1Skamil}
58931.77Skamil
58941.77Skamil#define ATTACH_LWPINFO(test, threads)					\
58951.77SkamilATF_TC(test);								\
58961.77SkamilATF_TC_HEAD(test, tc)							\
58971.77Skamil{									\
58981.77Skamil	atf_tc_set_md_var(tc, "descr",					\
58991.77Skamil	    "Verify LWPINFO with the child with " #threads		\
59001.77Skamil	    " spawned extra threads (tracer is not the original "	\
59011.77Skamil	    "parent)");							\
59021.77Skamil}									\
59031.77Skamil									\
59041.77SkamilATF_TC_BODY(test, tc)							\
59051.77Skamil{									\
59061.77Skamil									\
59071.77Skamil	attach_lwpinfo(threads);					\
59081.77Skamil}
59091.77Skamil
59101.77SkamilATTACH_LWPINFO(attach_lwpinfo0, 0)
59111.77SkamilATTACH_LWPINFO(attach_lwpinfo1, 1)
59121.77SkamilATTACH_LWPINFO(attach_lwpinfo2, 2)
59131.77SkamilATTACH_LWPINFO(attach_lwpinfo3, 3)
59141.1Skamil#endif
59151.1Skamil
59161.77Skamil/// ----------------------------------------------------------------------------
59171.77Skamil
59181.1Skamilstatic void
59191.79Skamilptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c), int *signal_caught)
59201.1Skamil{
59211.1Skamil	const int exitval = 5;
59221.1Skamil	const int sigval = SIGINT;
59231.1Skamil	const int sigfaked = SIGTRAP;
59241.1Skamil	const int sicodefaked = TRAP_BRKPT;
59251.1Skamil	pid_t child, wpid;
59261.1Skamil	struct sigaction sa;
59271.1Skamil#if defined(TWAIT_HAVE_STATUS)
59281.1Skamil	int status;
59291.1Skamil#endif
59301.1Skamil	struct ptrace_siginfo info;
59311.1Skamil	memset(&info, 0, sizeof(info));
59321.1Skamil
59331.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
59341.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
59351.1Skamil	if (child == 0) {
59361.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
59371.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
59381.1Skamil
59391.79Skamil		sa.sa_sigaction = sah;
59401.1Skamil		sa.sa_flags = SA_SIGINFO;
59411.1Skamil		sigemptyset(&sa.sa_mask);
59421.1Skamil
59431.79Skamil		FORKEE_ASSERT(sigaction(faked ? sigfaked : sigval, &sa, NULL)
59441.79Skamil		    != -1);
59451.1Skamil
59461.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
59471.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
59481.1Skamil
59491.79Skamil		FORKEE_ASSERT_EQ(*signal_caught, 1);
59501.1Skamil
59511.13Schristos		DPRINTF("Before exiting of the child process\n");
59521.1Skamil		_exit(exitval);
59531.1Skamil	}
59541.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
59551.1Skamil
59561.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
59571.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
59581.1Skamil
59591.1Skamil	validate_status_stopped(status, sigval);
59601.1Skamil
59611.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
59621.61Skre	SYSCALL_REQUIRE(
59631.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
59641.1Skamil
59651.13Schristos	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
59661.13Schristos	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
59671.1Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
59681.1Skamil	    info.psi_siginfo.si_errno);
59691.1Skamil
59701.79Skamil	if (faked) {
59711.79Skamil		DPRINTF("Before setting new faked signal to signo=%d "
59721.79Skamil		    "si_code=%d\n", sigfaked, sicodefaked);
59731.79Skamil		info.psi_siginfo.si_signo = sigfaked;
59741.79Skamil		info.psi_siginfo.si_code = sicodefaked;
59751.79Skamil	}
59761.1Skamil
59771.13Schristos	DPRINTF("Before calling ptrace(2) with PT_SET_SIGINFO for child\n");
59781.61Skre	SYSCALL_REQUIRE(
59791.61Skre	    ptrace(PT_SET_SIGINFO, child, &info, sizeof(info)) != -1);
59801.1Skamil
59811.79Skamil	if (faked) {
59821.79Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
59831.79Skamil		    "child\n");
59841.79Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
59851.79Skamil		    sizeof(info)) != -1);
59861.1Skamil
59871.79Skamil		DPRINTF("Before checking siginfo_t\n");
59881.79Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigfaked);
59891.79Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, sicodefaked);
59901.79Skamil	}
59911.1Skamil
59921.13Schristos	DPRINTF("Before resuming the child process where it left off and "
59931.1Skamil	    "without signal to be sent\n");
59941.79Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
59951.79Skamil	    faked ? sigfaked : sigval) != -1);
59961.1Skamil
59971.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
59981.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
59991.1Skamil
60001.1Skamil	validate_status_exited(status, exitval);
60011.1Skamil
60021.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
60031.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
60041.1Skamil}
60051.1Skamil
60061.79Skamil#define PTRACE_SIGINFO(test, faked)					\
60071.79SkamilATF_TC(test);								\
60081.79SkamilATF_TC_HEAD(test, tc)							\
60091.79Skamil{									\
60101.79Skamil	atf_tc_set_md_var(tc, "descr",					\
60111.79Skamil	    "Verify basic PT_GET_SIGINFO and PT_SET_SIGINFO calls"	\
60121.79Skamil	    "with%s setting signal to new value", faked ? "" : "out");	\
60131.79Skamil}									\
60141.79Skamil									\
60151.79Skamilstatic int test##_caught = 0;						\
60161.79Skamil									\
60171.79Skamilstatic void								\
60181.79Skamiltest##_sighandler(int sig, siginfo_t *info, void *ctx)			\
60191.79Skamil{									\
60201.79Skamil	if (faked) {							\
60211.79Skamil		FORKEE_ASSERT_EQ(sig, SIGTRAP);				\
60221.79Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGTRAP);		\
60231.79Skamil		FORKEE_ASSERT_EQ(info->si_code, TRAP_BRKPT);		\
60241.79Skamil	} else {							\
60251.79Skamil		FORKEE_ASSERT_EQ(sig, SIGINT);				\
60261.79Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGINT);		\
60271.79Skamil		FORKEE_ASSERT_EQ(info->si_code, SI_LWP);		\
60281.79Skamil	}								\
60291.79Skamil									\
60301.79Skamil	++ test##_caught;						\
60311.79Skamil}									\
60321.79Skamil									\
60331.79SkamilATF_TC_BODY(test, tc)							\
60341.79Skamil{									\
60351.79Skamil									\
60361.79Skamil	ptrace_siginfo(faked, test##_sighandler, & test##_caught); 	\
60371.79Skamil}
60381.79Skamil
60391.79SkamilPTRACE_SIGINFO(siginfo_set_unmodified, false)
60401.79SkamilPTRACE_SIGINFO(siginfo_set_faked, true)
60411.79Skamil
60421.79Skamil/// ----------------------------------------------------------------------------
60431.79Skamil
60441.97Skamilstatic void
60451.97Skamiltraceme_exec(bool masked, bool ignored)
60461.1Skamil{
60471.1Skamil	const int sigval = SIGTRAP;
60481.1Skamil	pid_t child, wpid;
60491.1Skamil#if defined(TWAIT_HAVE_STATUS)
60501.1Skamil	int status;
60511.1Skamil#endif
60521.97Skamil	struct sigaction sa;
60531.97Skamil	struct ptrace_siginfo info;
60541.97Skamil	sigset_t intmask;
60551.97Skamil	struct kinfo_proc2 kp;
60561.97Skamil	size_t len = sizeof(kp);
60571.97Skamil
60581.97Skamil	int name[6];
60591.97Skamil	const size_t namelen = __arraycount(name);
60601.97Skamil	ki_sigset_t kp_sigmask;
60611.97Skamil	ki_sigset_t kp_sigignore;
60621.1Skamil
60631.1Skamil	memset(&info, 0, sizeof(info));
60641.1Skamil
60651.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
60661.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
60671.1Skamil	if (child == 0) {
60681.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
60691.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
60701.1Skamil
60711.97Skamil		if (masked) {
60721.97Skamil			sigemptyset(&intmask);
60731.97Skamil			sigaddset(&intmask, sigval);
60741.97Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
60751.97Skamil		}
60761.97Skamil
60771.97Skamil		if (ignored) {
60781.97Skamil			memset(&sa, 0, sizeof(sa));
60791.97Skamil			sa.sa_handler = SIG_IGN;
60801.97Skamil			sigemptyset(&sa.sa_mask);
60811.97Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
60821.97Skamil		}
60831.97Skamil
60841.13Schristos		DPRINTF("Before calling execve(2) from child\n");
60851.1Skamil		execlp("/bin/echo", "/bin/echo", NULL);
60861.1Skamil
60871.1Skamil		FORKEE_ASSERT(0 && "Not reached");
60881.1Skamil	}
60891.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
60901.1Skamil
60911.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
60921.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
60931.1Skamil
60941.1Skamil	validate_status_stopped(status, sigval);
60951.1Skamil
60961.97Skamil	name[0] = CTL_KERN,
60971.97Skamil	name[1] = KERN_PROC2,
60981.97Skamil	name[2] = KERN_PROC_PID;
60991.97Skamil	name[3] = getpid();
61001.97Skamil	name[4] = sizeof(kp);
61011.97Skamil	name[5] = 1;
61021.97Skamil
61031.97Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
61041.97Skamil
61051.97Skamil	if (masked)
61061.97Skamil		kp_sigmask = kp.p_sigmask;
61071.97Skamil
61081.97Skamil	if (ignored)
61091.97Skamil		kp_sigignore = kp.p_sigignore;
61101.97Skamil
61111.97Skamil	name[3] = getpid();
61121.97Skamil
61131.97Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
61141.97Skamil
61151.97Skamil	if (masked) {
61161.97Skamil		DPRINTF("kp_sigmask="
61171.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
61181.97Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
61191.97Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
61201.97Skamil
61211.97Skamil		DPRINTF("kp.p_sigmask="
61221.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
61231.97Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
61241.97Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
61251.97Skamil
61261.97Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
61271.97Skamil		    sizeof(kp_sigmask)));
61281.97Skamil	}
61291.97Skamil
61301.97Skamil	if (ignored) {
61311.97Skamil		DPRINTF("kp_sigignore="
61321.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
61331.97Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
61341.97Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
61351.97Skamil
61361.97Skamil		DPRINTF("kp.p_sigignore="
61371.97Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
61381.97Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
61391.97Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
61401.97Skamil
61411.97Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
61421.97Skamil		    sizeof(kp_sigignore)));
61431.97Skamil	}
61441.97Skamil
61451.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
61461.61Skre	SYSCALL_REQUIRE(
61471.61Skre	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
61481.1Skamil
61491.13Schristos	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
61501.13Schristos	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
61511.1Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
61521.1Skamil	    info.psi_siginfo.si_errno);
61531.1Skamil
61541.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
61551.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
61561.1Skamil
61571.13Schristos	DPRINTF("Before resuming the child process where it left off and "
61581.1Skamil	    "without signal to be sent\n");
61591.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
61601.1Skamil
61611.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
61621.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
61631.1Skamil
61641.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
61651.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
61661.1Skamil}
61671.1Skamil
61681.97Skamil#define TRACEME_EXEC(test, masked, ignored)				\
61691.97SkamilATF_TC(test);								\
61701.97SkamilATF_TC_HEAD(test, tc)							\
61711.97Skamil{									\
61721.97Skamil       atf_tc_set_md_var(tc, "descr",					\
61731.97Skamil           "Detect SIGTRAP TRAP_EXEC from "				\
61741.97Skamil           "child%s%s", masked ? " with masked signal" : "",		\
61751.97Skamil           masked ? " with ignored signal" : "");			\
61761.97Skamil}									\
61771.97Skamil									\
61781.97SkamilATF_TC_BODY(test, tc)							\
61791.97Skamil{									\
61801.97Skamil									\
61811.97Skamil       traceme_exec(masked, ignored);					\
61821.97Skamil}
61831.97Skamil
61841.97SkamilTRACEME_EXEC(traceme_exec, false, false)
61851.97SkamilTRACEME_EXEC(traceme_signalmasked_exec, true, false)
61861.97SkamilTRACEME_EXEC(traceme_signalignored_exec, false, true)
61871.97Skamil
61881.82Skamil/// ----------------------------------------------------------------------------
61891.82Skamil
61901.135Skamil#define TRACE_THREADS_NUM 100
61911.135Skamil
61921.83Skamilstatic volatile int done;
61931.137Skamilpthread_mutex_t trace_threads_mtx = PTHREAD_MUTEX_INITIALIZER;
61941.1Skamil
61951.83Skamilstatic void *
61961.83Skamiltrace_threads_cb(void *arg __unused)
61971.1Skamil{
61981.1Skamil
61991.137Skamil	pthread_mutex_lock(&trace_threads_mtx);
62001.83Skamil	done++;
62011.137Skamil	pthread_mutex_unlock(&trace_threads_mtx);
62021.83Skamil
62031.135Skamil	while (done < TRACE_THREADS_NUM)
62041.135Skamil		sched_yield();
62051.83Skamil
62061.83Skamil	return NULL;
62071.1Skamil}
62081.1Skamil
62091.83Skamilstatic void
62101.153Skamiltrace_threads(bool trace_create, bool trace_exit, bool masked)
62111.1Skamil{
62121.1Skamil	const int sigval = SIGSTOP;
62131.1Skamil	pid_t child, wpid;
62141.1Skamil#if defined(TWAIT_HAVE_STATUS)
62151.1Skamil	int status;
62161.1Skamil#endif
62171.1Skamil	ptrace_state_t state;
62181.1Skamil	const int slen = sizeof(state);
62191.1Skamil	ptrace_event_t event;
62201.1Skamil	const int elen = sizeof(event);
62211.83Skamil	struct ptrace_siginfo info;
62221.83Skamil
62231.153Skamil	sigset_t intmask;
62241.153Skamil
62251.135Skamil	pthread_t t[TRACE_THREADS_NUM];
62261.83Skamil	int rv;
62271.83Skamil	size_t n;
62281.1Skamil	lwpid_t lid;
62291.83Skamil
62301.83Skamil	/* Track created and exited threads */
62311.141Skamil	struct lwp_event_count traced_lwps[__arraycount(t)] = {{0, 0}};
62321.83Skamil
62331.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
62341.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
62351.1Skamil	if (child == 0) {
62361.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
62371.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
62381.1Skamil
62391.153Skamil		if (masked) {
62401.153Skamil			sigemptyset(&intmask);
62411.153Skamil			sigaddset(&intmask, SIGTRAP);
62421.153Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
62431.153Skamil		}
62441.153Skamil
62451.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
62461.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
62471.1Skamil
62481.83Skamil		for (n = 0; n < __arraycount(t); n++) {
62491.83Skamil			rv = pthread_create(&t[n], NULL, trace_threads_cb,
62501.83Skamil			    NULL);
62511.83Skamil			FORKEE_ASSERT(rv == 0);
62521.83Skamil		}
62531.1Skamil
62541.83Skamil		for (n = 0; n < __arraycount(t); n++) {
62551.83Skamil			rv = pthread_join(t[n], NULL);
62561.83Skamil			FORKEE_ASSERT(rv == 0);
62571.83Skamil		}
62581.1Skamil
62591.83Skamil		/*
62601.83Skamil		 * There is race between _exit() and pthread_join() detaching
62611.83Skamil		 * a thread. For simplicity kill the process after detecting
62621.83Skamil		 * LWP events.
62631.83Skamil		 */
62641.83Skamil		while (true)
62651.83Skamil			continue;
62661.1Skamil
62671.83Skamil		FORKEE_ASSERT(0 && "Not reached");
62681.1Skamil	}
62691.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
62701.1Skamil
62711.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
62721.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
62731.1Skamil
62741.1Skamil	validate_status_stopped(status, sigval);
62751.1Skamil
62761.83Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
62771.83Skamil	SYSCALL_REQUIRE(
62781.83Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
62791.1Skamil
62801.83Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
62811.83Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
62821.83Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
62831.83Skamil	    info.psi_siginfo.si_errno);
62841.1Skamil
62851.83Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
62861.83Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
62871.1Skamil
62881.83Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
62891.83Skamil	memset(&event, 0, sizeof(event));
62901.83Skamil	if (trace_create)
62911.83Skamil		event.pe_set_event |= PTRACE_LWP_CREATE;
62921.83Skamil	if (trace_exit)
62931.83Skamil		event.pe_set_event |= PTRACE_LWP_EXIT;
62941.83Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
62951.1Skamil
62961.13Schristos	DPRINTF("Before resuming the child process where it left off and "
62971.1Skamil	    "without signal to be sent\n");
62981.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
62991.1Skamil
63001.83Skamil	for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
63011.83Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
63021.83Skamil		    "SIGTRAP\n", TWAIT_FNAME);
63031.83Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
63041.83Skamil		    child);
63051.1Skamil
63061.83Skamil		validate_status_stopped(status, SIGTRAP);
63071.1Skamil
63081.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
63091.83Skamil		    "child\n");
63101.83Skamil		SYSCALL_REQUIRE(
63111.83Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
63121.1Skamil
63131.83Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
63141.83Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
63151.83Skamil		    "si_errno=%#x\n",
63161.83Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
63171.83Skamil		    info.psi_siginfo.si_errno);
63181.1Skamil
63191.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
63201.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
63211.1Skamil
63221.83Skamil		SYSCALL_REQUIRE(
63231.83Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
63241.1Skamil
63251.83Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
63261.83Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
63271.1Skamil
63281.83Skamil		lid = state.pe_lwp;
63291.83Skamil		DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
63301.1Skamil
63311.141Skamil		*FIND_EVENT_COUNT(traced_lwps, lid) += 1;
63321.1Skamil
63331.83Skamil		DPRINTF("Before resuming the child process where it left off "
63341.83Skamil		    "and without signal to be sent\n");
63351.83Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
63361.83Skamil	}
63371.1Skamil
63381.83Skamil	for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
63391.83Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
63401.83Skamil		    "SIGTRAP\n", TWAIT_FNAME);
63411.83Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
63421.83Skamil		    child);
63431.1Skamil
63441.83Skamil		validate_status_stopped(status, SIGTRAP);
63451.1Skamil
63461.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
63471.83Skamil		    "child\n");
63481.83Skamil		SYSCALL_REQUIRE(
63491.83Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
63501.1Skamil
63511.83Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
63521.83Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
63531.83Skamil		    "si_errno=%#x\n",
63541.83Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
63551.83Skamil		    info.psi_siginfo.si_errno);
63561.1Skamil
63571.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
63581.83Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
63591.1Skamil
63601.83Skamil		SYSCALL_REQUIRE(
63611.83Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
63621.1Skamil
63631.83Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
63641.83Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
63651.1Skamil
63661.83Skamil		lid = state.pe_lwp;
63671.83Skamil		DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
63681.1Skamil
63691.83Skamil		if (trace_create) {
63701.141Skamil			int *count = FIND_EVENT_COUNT(traced_lwps, lid);
63711.141Skamil			ATF_REQUIRE_EQ(*count, 1);
63721.141Skamil			*count = 0;
63731.83Skamil		}
63741.1Skamil
63751.83Skamil		DPRINTF("Before resuming the child process where it left off "
63761.83Skamil		    "and without signal to be sent\n");
63771.83Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
63781.83Skamil	}
63791.1Skamil
63801.83Skamil	kill(child, SIGKILL);
63811.1Skamil
63821.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
63831.1Skamil	    TWAIT_FNAME);
63841.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
63851.1Skamil
63861.83Skamil	validate_status_signaled(status, SIGKILL, 0);
63871.1Skamil
63881.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
63891.1Skamil	    TWAIT_FNAME);
63901.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
63911.1Skamil}
63921.1Skamil
63931.153Skamil#define TRACE_THREADS(test, trace_create, trace_exit, mask)		\
63941.83SkamilATF_TC(test);								\
63951.83SkamilATF_TC_HEAD(test, tc)							\
63961.83Skamil{									\
63971.83Skamil        atf_tc_set_md_var(tc, "descr",					\
63981.83Skamil            "Verify spawning threads with%s tracing LWP create and"	\
63991.83Skamil	    "with%s tracing LWP exit", trace_create ? "" : "out",	\
64001.83Skamil	    trace_exit ? "" : "out");					\
64011.83Skamil}									\
64021.83Skamil									\
64031.83SkamilATF_TC_BODY(test, tc)							\
64041.83Skamil{									\
64051.83Skamil									\
64061.153Skamil        trace_threads(trace_create, trace_exit, mask);			\
64071.83Skamil}
64081.83Skamil
64091.153SkamilTRACE_THREADS(trace_thread_nolwpevents, false, false, false)
64101.153SkamilTRACE_THREADS(trace_thread_lwpexit, false, true, false)
64111.153SkamilTRACE_THREADS(trace_thread_lwpcreate, true, false, false)
64121.153SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true, false)
64131.153Skamil
64141.153SkamilTRACE_THREADS(trace_thread_lwpexit_masked_sigtrap, false, true, true)
64151.153SkamilTRACE_THREADS(trace_thread_lwpcreate_masked_sigtrap, true, false, true)
64161.153SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit_masked_sigtrap, true, true, true)
64171.83Skamil
64181.83Skamil/// ----------------------------------------------------------------------------
64191.83Skamil
64201.84SkamilATF_TC(signal_mask_unrelated);
64211.84SkamilATF_TC_HEAD(signal_mask_unrelated, tc)
64221.1Skamil{
64231.1Skamil	atf_tc_set_md_var(tc, "descr",
64241.1Skamil	    "Verify that masking single unrelated signal does not stop tracer "
64251.1Skamil	    "from catching other signals");
64261.1Skamil}
64271.1Skamil
64281.84SkamilATF_TC_BODY(signal_mask_unrelated, tc)
64291.1Skamil{
64301.1Skamil	const int exitval = 5;
64311.1Skamil	const int sigval = SIGSTOP;
64321.1Skamil	const int sigmasked = SIGTRAP;
64331.1Skamil	const int signotmasked = SIGINT;
64341.1Skamil	pid_t child, wpid;
64351.1Skamil#if defined(TWAIT_HAVE_STATUS)
64361.1Skamil	int status;
64371.1Skamil#endif
64381.1Skamil	sigset_t intmask;
64391.1Skamil
64401.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
64411.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
64421.1Skamil	if (child == 0) {
64431.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
64441.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
64451.1Skamil
64461.1Skamil		sigemptyset(&intmask);
64471.1Skamil		sigaddset(&intmask, sigmasked);
64481.1Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
64491.1Skamil
64501.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
64511.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
64521.1Skamil
64531.13Schristos		DPRINTF("Before raising %s from child\n",
64541.1Skamil		    strsignal(signotmasked));
64551.1Skamil		FORKEE_ASSERT(raise(signotmasked) == 0);
64561.1Skamil
64571.13Schristos		DPRINTF("Before exiting of the child process\n");
64581.1Skamil		_exit(exitval);
64591.1Skamil	}
64601.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
64611.1Skamil
64621.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
64631.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64641.1Skamil
64651.1Skamil	validate_status_stopped(status, sigval);
64661.1Skamil
64671.13Schristos	DPRINTF("Before resuming the child process where it left off and "
64681.1Skamil	    "without signal to be sent\n");
64691.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
64701.1Skamil
64711.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
64721.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64731.1Skamil
64741.1Skamil	validate_status_stopped(status, signotmasked);
64751.1Skamil
64761.13Schristos	DPRINTF("Before resuming the child process where it left off and "
64771.1Skamil	    "without signal to be sent\n");
64781.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
64791.1Skamil
64801.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
64811.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
64821.1Skamil
64831.1Skamil	validate_status_exited(status, exitval);
64841.1Skamil
64851.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
64861.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
64871.1Skamil}
64881.1Skamil
64891.84Skamil/// ----------------------------------------------------------------------------
64901.84Skamil
64911.1Skamil#if defined(TWAIT_HAVE_PID)
64921.99Skamilstatic void
64931.126Skamilfork2_body(const char *fn, bool masked, bool ignored)
64941.1Skamil{
64951.1Skamil	const int exitval = 5;
64961.126Skamil	const int exitval2 = 0; /* Match exit status from /bin/echo */
64971.1Skamil	const int sigval = SIGSTOP;
64981.99Skamil	pid_t child, child2 = 0, wpid;
64991.1Skamil#if defined(TWAIT_HAVE_STATUS)
65001.1Skamil	int status;
65011.1Skamil#endif
65021.1Skamil	ptrace_state_t state;
65031.1Skamil	const int slen = sizeof(state);
65041.1Skamil	ptrace_event_t event;
65051.1Skamil	const int elen = sizeof(event);
65061.99Skamil	struct sigaction sa;
65071.99Skamil	struct ptrace_siginfo info;
65081.99Skamil	sigset_t intmask;
65091.99Skamil	struct kinfo_proc2 kp;
65101.99Skamil	size_t len = sizeof(kp);
65111.99Skamil
65121.99Skamil	int name[6];
65131.99Skamil	const size_t namelen = __arraycount(name);
65141.99Skamil	ki_sigset_t kp_sigmask;
65151.99Skamil	ki_sigset_t kp_sigignore;
65161.1Skamil
65171.126Skamil	char * const arg[] = { __UNCONST("/bin/echo"), NULL };
65181.14Schristos
65191.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
65201.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
65211.1Skamil	if (child == 0) {
65221.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
65231.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
65241.1Skamil
65251.99Skamil		if (masked) {
65261.99Skamil			sigemptyset(&intmask);
65271.99Skamil			sigaddset(&intmask, SIGTRAP);
65281.99Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
65291.99Skamil		}
65301.99Skamil
65311.99Skamil		if (ignored) {
65321.99Skamil			memset(&sa, 0, sizeof(sa));
65331.99Skamil			sa.sa_handler = SIG_IGN;
65341.99Skamil			sigemptyset(&sa.sa_mask);
65351.99Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
65361.99Skamil		}
65371.1Skamil
65381.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
65391.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
65401.1Skamil
65411.126Skamil		if (strcmp(fn, "spawn") == 0) {
65421.126Skamil			FORKEE_ASSERT_EQ(posix_spawn(&child2,
65431.126Skamil			    arg[0], NULL, NULL, arg, NULL), 0);
65441.126Skamil		} else  {
65451.126Skamil			if (strcmp(fn, "fork") == 0) {
65461.126Skamil				FORKEE_ASSERT((child2 = fork()) != -1);
65471.126Skamil			} else {
65481.126Skamil				FORKEE_ASSERT((child2 = vfork()) != -1);
65491.126Skamil			}
65501.126Skamil			if (child2 == 0)
65511.126Skamil				_exit(exitval2);
65521.126Skamil		}
65531.1Skamil
65541.1Skamil		FORKEE_REQUIRE_SUCCESS
65551.99Skamil		    (wpid = TWAIT_GENERIC(child2, &status, 0), child2);
65561.1Skamil
65571.1Skamil		forkee_status_exited(status, exitval2);
65581.1Skamil
65591.13Schristos		DPRINTF("Before exiting of the child process\n");
65601.1Skamil		_exit(exitval);
65611.1Skamil	}
65621.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
65631.1Skamil
65641.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
65651.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
65661.1Skamil
65671.1Skamil	validate_status_stopped(status, sigval);
65681.1Skamil
65691.99Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
65701.99Skamil	SYSCALL_REQUIRE(
65711.99Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
65721.99Skamil
65731.99Skamil	DPRINTF("Before checking siginfo_t\n");
65741.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
65751.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
65761.1Skamil
65771.99Skamil	name[0] = CTL_KERN,
65781.99Skamil	name[1] = KERN_PROC2,
65791.99Skamil	name[2] = KERN_PROC_PID;
65801.99Skamil	name[3] = child;
65811.99Skamil	name[4] = sizeof(kp);
65821.99Skamil	name[5] = 1;
65831.1Skamil
65841.99Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
65851.1Skamil
65861.99Skamil	if (masked)
65871.99Skamil		kp_sigmask = kp.p_sigmask;
65881.1Skamil
65891.99Skamil	if (ignored)
65901.99Skamil		kp_sigignore = kp.p_sigignore;
65911.1Skamil
65921.126Skamil	DPRINTF("Set 0%s%s%s%s in EVENT_MASK for the child %d\n",
65931.126Skamil	    strcmp(fn, "spawn") == 0 ? "|PTRACE_POSIX_SPAWN" : "",
65941.126Skamil	    strcmp(fn, "fork") == 0 ? "|PTRACE_FORK" : "",
65951.126Skamil	    strcmp(fn, "vfork") == 0 ? "|PTRACE_VFORK" : "",
65961.126Skamil	    strcmp(fn, "vforkdone") == 0 ? "|PTRACE_VFORK_DONE" : "", child);
65971.99Skamil	event.pe_set_event = 0;
65981.126Skamil	if (strcmp(fn, "spawn") == 0)
65991.126Skamil		event.pe_set_event |= PTRACE_POSIX_SPAWN;
66001.126Skamil	if (strcmp(fn, "fork") == 0)
66011.99Skamil		event.pe_set_event |= PTRACE_FORK;
66021.126Skamil	if (strcmp(fn, "vfork") == 0)
66031.99Skamil		event.pe_set_event |= PTRACE_VFORK;
66041.126Skamil	if (strcmp(fn, "vforkdone") == 0)
66051.99Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
66061.99Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
66071.1Skamil
66081.99Skamil	DPRINTF("Before resuming the child process where it left off and "
66091.99Skamil	    "without signal to be sent\n");
66101.99Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
66111.1Skamil
66121.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
66131.126Skamil	    strcmp(fn, "vfork") == 0) {
66141.99Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
66151.99Skamil		    child);
66161.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
66171.99Skamil		    child);
66181.1Skamil
66191.99Skamil		validate_status_stopped(status, SIGTRAP);
66201.1Skamil
66211.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
66221.1Skamil
66231.99Skamil		if (masked) {
66241.99Skamil			DPRINTF("kp_sigmask="
66251.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
66261.99Skamil			    PRIx32 "\n",
66271.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
66281.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
66291.1Skamil
66301.99Skamil			DPRINTF("kp.p_sigmask="
66311.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
66321.99Skamil			    PRIx32 "\n",
66331.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
66341.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
66351.1Skamil
66361.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
66371.99Skamil			    sizeof(kp_sigmask)));
66381.99Skamil		}
66391.1Skamil
66401.99Skamil		if (ignored) {
66411.99Skamil			DPRINTF("kp_sigignore="
66421.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
66431.99Skamil			    PRIx32 "\n",
66441.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
66451.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
66461.1Skamil
66471.99Skamil			DPRINTF("kp.p_sigignore="
66481.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
66491.99Skamil			    PRIx32 "\n",
66501.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
66511.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
66521.1Skamil
66531.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
66541.99Skamil			    sizeof(kp_sigignore)));
66551.99Skamil		}
66561.1Skamil
66571.99Skamil		SYSCALL_REQUIRE(
66581.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
66591.126Skamil		if (strcmp(fn, "spawn") == 0) {
66601.126Skamil			ATF_REQUIRE_EQ(
66611.126Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
66621.126Skamil			       PTRACE_POSIX_SPAWN);
66631.126Skamil		}
66641.126Skamil		if (strcmp(fn, "fork") == 0) {
66651.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
66661.99Skamil			       PTRACE_FORK);
66671.99Skamil		}
66681.126Skamil		if (strcmp(fn, "vfork") == 0) {
66691.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
66701.99Skamil			       PTRACE_VFORK);
66711.99Skamil		}
66721.1Skamil
66731.99Skamil		child2 = state.pe_other_pid;
66741.99Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
66751.1Skamil
66761.99Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
66771.99Skamil		    "%d\n", TWAIT_FNAME, child2, child);
66781.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
66791.99Skamil		    child2);
66801.1Skamil
66811.99Skamil		validate_status_stopped(status, SIGTRAP);
66821.1Skamil
66831.99Skamil		name[3] = child2;
66841.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
66851.1Skamil
66861.99Skamil		if (masked) {
66871.99Skamil			DPRINTF("kp_sigmask="
66881.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
66891.99Skamil			    PRIx32 "\n",
66901.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
66911.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
66921.1Skamil
66931.99Skamil			DPRINTF("kp.p_sigmask="
66941.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
66951.99Skamil			    PRIx32 "\n",
66961.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
66971.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
66981.14Schristos
66991.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
67001.99Skamil			    sizeof(kp_sigmask)));
67011.99Skamil		}
67021.1Skamil
67031.99Skamil		if (ignored) {
67041.99Skamil			DPRINTF("kp_sigignore="
67051.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
67061.99Skamil			    PRIx32 "\n",
67071.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
67081.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
67091.1Skamil
67101.99Skamil			DPRINTF("kp.p_sigignore="
67111.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
67121.99Skamil			    PRIx32 "\n",
67131.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
67141.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
67151.1Skamil
67161.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
67171.99Skamil			    sizeof(kp_sigignore)));
67181.99Skamil		}
67191.1Skamil
67201.99Skamil		SYSCALL_REQUIRE(
67211.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
67221.126Skamil		if (strcmp(fn, "spawn") == 0) {
67231.126Skamil			ATF_REQUIRE_EQ(
67241.126Skamil			    state.pe_report_event & PTRACE_POSIX_SPAWN,
67251.126Skamil			       PTRACE_POSIX_SPAWN);
67261.126Skamil		}
67271.126Skamil		if (strcmp(fn, "fork") == 0) {
67281.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
67291.99Skamil			       PTRACE_FORK);
67301.99Skamil		}
67311.126Skamil		if (strcmp(fn, "vfork") == 0) {
67321.99Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
67331.99Skamil			       PTRACE_VFORK);
67341.99Skamil		}
67351.1Skamil
67361.99Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
67371.1Skamil
67381.99Skamil		DPRINTF("Before resuming the forkee process where it left off "
67391.99Skamil		    "and without signal to be sent\n");
67401.99Skamil		SYSCALL_REQUIRE(
67411.99Skamil		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
67421.1Skamil
67431.99Skamil		DPRINTF("Before resuming the child process where it left off "
67441.99Skamil		    "and without signal to be sent\n");
67451.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
67461.1Skamil	}
67471.1Skamil
67481.126Skamil	if (strcmp(fn, "vforkdone") == 0) {
67491.99Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
67501.99Skamil		    child);
67511.99Skamil		TWAIT_REQUIRE_SUCCESS(
67521.99Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
67531.1Skamil
67541.99Skamil		validate_status_stopped(status, SIGTRAP);
67551.1Skamil
67561.99Skamil		name[3] = child;
67571.99Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
67581.1Skamil
67591.102Skamil		/*
67601.102Skamil		 * SIGCHLD is now pending in the signal queue and
67611.102Skamil		 * the kernel presents it to userland as a masked signal.
67621.102Skamil		 */
67631.102Skamil		sigdelset((sigset_t *)&kp.p_sigmask, SIGCHLD);
67641.102Skamil
67651.99Skamil		if (masked) {
67661.99Skamil			DPRINTF("kp_sigmask="
67671.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
67681.99Skamil			    PRIx32 "\n",
67691.99Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
67701.99Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
67711.1Skamil
67721.99Skamil			DPRINTF("kp.p_sigmask="
67731.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
67741.99Skamil			    PRIx32 "\n",
67751.99Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
67761.99Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
67771.1Skamil
67781.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
67791.99Skamil			    sizeof(kp_sigmask)));
67801.99Skamil		}
67811.1Skamil
67821.99Skamil		if (ignored) {
67831.99Skamil			DPRINTF("kp_sigignore="
67841.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
67851.99Skamil			    PRIx32 "\n",
67861.99Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
67871.99Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
67881.1Skamil
67891.99Skamil			DPRINTF("kp.p_sigignore="
67901.99Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
67911.99Skamil			    PRIx32 "\n",
67921.99Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
67931.99Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
67941.1Skamil
67951.99Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
67961.99Skamil			    sizeof(kp_sigignore)));
67971.99Skamil		}
67981.1Skamil
67991.99Skamil		SYSCALL_REQUIRE(
68001.99Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
68011.99Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
68021.1Skamil
68031.99Skamil		child2 = state.pe_other_pid;
68041.99Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
68051.99Skamil		    child2);
68061.1Skamil
68071.99Skamil		DPRINTF("Before resuming the child process where it left off "
68081.99Skamil		    "and without signal to be sent\n");
68091.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
68101.99Skamil	}
68111.1Skamil
68121.126Skamil	if (strcmp(fn, "spawn") == 0 || strcmp(fn, "fork") == 0 ||
68131.126Skamil	    strcmp(fn, "vfork") == 0) {
68141.99Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
68151.99Skamil		    "\n", TWAIT_FNAME);
68161.99Skamil		TWAIT_REQUIRE_SUCCESS(
68171.99Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
68181.1Skamil
68191.99Skamil		validate_status_exited(status, exitval2);
68201.1Skamil
68211.99Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
68221.99Skamil		    "process\n", TWAIT_FNAME);
68231.99Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
68241.99Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
68251.99Skamil	}
68261.1Skamil
68271.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
68281.1Skamil	    "SIGCHLD\n", TWAIT_FNAME);
68291.57Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68301.1Skamil
68311.1Skamil	validate_status_stopped(status, SIGCHLD);
68321.1Skamil
68331.57Skamil	DPRINTF("Before resuming the child process where it left off and "
68341.1Skamil	    "without signal to be sent\n");
68351.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
68361.1Skamil
68371.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
68381.1Skamil	    TWAIT_FNAME);
68391.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
68401.1Skamil
68411.1Skamil	validate_status_exited(status, exitval);
68421.1Skamil
68431.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
68441.57Skamil	    TWAIT_FNAME);
68451.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
68461.1Skamil}
68471.1Skamil
68481.126Skamil#define FORK2_TEST(name,fn,masked,ignored)				\
68491.99SkamilATF_TC(name);								\
68501.99SkamilATF_TC_HEAD(name, tc)							\
68511.99Skamil{									\
68521.126Skamil	atf_tc_set_md_var(tc, "descr", "Verify that " fn " is caught "	\
68531.99Skamil	    "regardless of signal %s%s", 				\
68541.99Skamil	    masked ? "masked" : "", ignored ? "ignored" : "");		\
68551.99Skamil}									\
68561.99Skamil									\
68571.99SkamilATF_TC_BODY(name, tc)							\
68581.99Skamil{									\
68591.99Skamil									\
68601.126Skamil	fork2_body(fn, masked, ignored);				\
68611.1Skamil}
68621.1Skamil
68631.126SkamilFORK2_TEST(posix_spawn_singalmasked, "spawn", true, false)
68641.126SkamilFORK2_TEST(posix_spawn_singalignored, "spawn", false, true)
68651.126SkamilFORK2_TEST(fork_singalmasked, "fork", true, false)
68661.126SkamilFORK2_TEST(fork_singalignored, "fork", false, true)
68671.126SkamilFORK2_TEST(vfork_singalmasked, "vfork", true, false)
68681.126SkamilFORK2_TEST(vfork_singalignored, "vfork", false, true)
68691.126SkamilFORK2_TEST(vforkdone_singalmasked, "vforkdone", true, false)
68701.126SkamilFORK2_TEST(vforkdone_singalignored, "vforkdone", false, true)
68711.1Skamil#endif
68721.1Skamil
68731.99Skamil/// ----------------------------------------------------------------------------
68741.1Skamil
68751.151Skamilstatic void *
68761.151Skamilthread_and_exec_thread_cb(void *arg __unused)
68771.151Skamil{
68781.151Skamil
68791.151Skamil	execlp("/bin/echo", "/bin/echo", NULL);
68801.151Skamil
68811.151Skamil	abort();
68821.151Skamil}
68831.151Skamil
68841.151Skamilstatic void
68851.151Skamilthreads_and_exec(void)
68861.151Skamil{
68871.151Skamil	const int sigval = SIGSTOP;
68881.151Skamil	pid_t child, wpid;
68891.151Skamil#if defined(TWAIT_HAVE_STATUS)
68901.151Skamil	int status;
68911.151Skamil#endif
68921.151Skamil	ptrace_state_t state;
68931.151Skamil	const int slen = sizeof(state);
68941.151Skamil	ptrace_event_t event;
68951.151Skamil	const int elen = sizeof(event);
68961.151Skamil	struct ptrace_siginfo info;
68971.151Skamil
68981.151Skamil	pthread_t t;
68991.151Skamil	lwpid_t lid;
69001.151Skamil
69011.151Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
69021.151Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
69031.151Skamil	if (child == 0) {
69041.151Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
69051.151Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
69061.151Skamil
69071.151Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
69081.151Skamil		FORKEE_ASSERT(raise(sigval) == 0);
69091.151Skamil
69101.151Skamil		FORKEE_ASSERT(pthread_create(&t, NULL,
69111.151Skamil		    thread_and_exec_thread_cb, NULL) == 0);
69121.151Skamil
69131.151Skamil		for (;;)
69141.151Skamil			continue;
69151.151Skamil
69161.151Skamil		FORKEE_ASSERT(0 && "Not reached");
69171.151Skamil	}
69181.151Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
69191.151Skamil
69201.151Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
69211.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
69221.151Skamil
69231.151Skamil	validate_status_stopped(status, sigval);
69241.151Skamil
69251.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
69261.151Skamil	SYSCALL_REQUIRE(
69271.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
69281.151Skamil
69291.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
69301.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
69311.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
69321.151Skamil	    info.psi_siginfo.si_errno);
69331.151Skamil
69341.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
69351.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
69361.151Skamil
69371.151Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
69381.151Skamil	memset(&event, 0, sizeof(event));
69391.151Skamil	event.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
69401.151Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
69411.151Skamil
69421.151Skamil	DPRINTF("Before resuming the child process where it left off and "
69431.151Skamil	    "without signal to be sent\n");
69441.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
69451.151Skamil
69461.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
69471.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
69481.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
69491.151Skamil	    child);
69501.151Skamil
69511.151Skamil	validate_status_stopped(status, SIGTRAP);
69521.151Skamil
69531.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
69541.151Skamil	    "child\n");
69551.151Skamil	SYSCALL_REQUIRE(
69561.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
69571.151Skamil
69581.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
69591.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
69601.151Skamil	    "si_errno=%#x\n",
69611.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
69621.151Skamil	    info.psi_siginfo.si_errno);
69631.151Skamil
69641.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
69651.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
69661.151Skamil
69671.151Skamil	SYSCALL_REQUIRE(
69681.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
69691.151Skamil
69701.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
69711.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
69721.151Skamil
69731.151Skamil	lid = state.pe_lwp;
69741.151Skamil	DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
69751.151Skamil
69761.151Skamil	DPRINTF("Before resuming the child process where it left off "
69771.151Skamil	    "and without signal to be sent\n");
69781.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
69791.151Skamil
69801.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
69811.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
69821.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
69831.151Skamil	    child);
69841.151Skamil
69851.151Skamil	validate_status_stopped(status, SIGTRAP);
69861.151Skamil
69871.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
69881.151Skamil	    "child\n");
69891.151Skamil	SYSCALL_REQUIRE(
69901.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
69911.151Skamil
69921.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
69931.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
69941.151Skamil	    "si_errno=%#x\n",
69951.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
69961.151Skamil	    info.psi_siginfo.si_errno);
69971.151Skamil
69981.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
69991.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
70001.151Skamil
70011.151Skamil	SYSCALL_REQUIRE(
70021.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
70031.151Skamil
70041.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
70051.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
70061.151Skamil
70071.151Skamil	lid = state.pe_lwp;
70081.151Skamil	DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
70091.151Skamil
70101.151Skamil	DPRINTF("Before resuming the child process where it left off "
70111.151Skamil	    "and without signal to be sent\n");
70121.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
70131.151Skamil
70141.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
70151.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
70161.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
70171.151Skamil	    child);
70181.151Skamil
70191.151Skamil	validate_status_stopped(status, SIGTRAP);
70201.151Skamil
70211.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
70221.151Skamil	    "child\n");
70231.151Skamil	SYSCALL_REQUIRE(
70241.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
70251.151Skamil
70261.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
70271.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
70281.151Skamil	    "si_errno=%#x\n",
70291.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
70301.151Skamil	    info.psi_siginfo.si_errno);
70311.151Skamil
70321.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
70331.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
70341.151Skamil
70351.151Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
70361.151Skamil
70371.151Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
70381.151Skamil	    TWAIT_FNAME);
70391.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
70401.151Skamil
70411.151Skamil	validate_status_signaled(status, SIGKILL, 0);
70421.151Skamil
70431.151Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
70441.151Skamil	    TWAIT_FNAME);
70451.151Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
70461.151Skamil}
70471.151Skamil
70481.151SkamilATF_TC(threads_and_exec);
70491.151SkamilATF_TC_HEAD(threads_and_exec, tc)
70501.151Skamil{
70511.151Skamil        atf_tc_set_md_var(tc, "descr",
70521.151Skamil            "Verify that multithreaded application on exec() will report "
70531.151Skamil	    "LWP_EXIT events");
70541.151Skamil}
70551.151Skamil
70561.151SkamilATF_TC_BODY(threads_and_exec, tc)
70571.151Skamil{
70581.151Skamil
70591.151Skamil        threads_and_exec();
70601.151Skamil}
70611.151Skamil
70621.151Skamil/// ----------------------------------------------------------------------------
70631.151Skamil
70641.154SkamilATF_TC(suspend_no_deadlock);
70651.154SkamilATF_TC_HEAD(suspend_no_deadlock, tc)
70661.1Skamil{
70671.1Skamil	atf_tc_set_md_var(tc, "descr",
70681.1Skamil	    "Verify that the while the only thread within a process is "
70691.1Skamil	    "suspended, the whole process cannot be unstopped");
70701.1Skamil}
70711.1Skamil
70721.154SkamilATF_TC_BODY(suspend_no_deadlock, tc)
70731.1Skamil{
70741.1Skamil	const int exitval = 5;
70751.1Skamil	const int sigval = SIGSTOP;
70761.1Skamil	pid_t child, wpid;
70771.1Skamil#if defined(TWAIT_HAVE_STATUS)
70781.1Skamil	int status;
70791.1Skamil#endif
70801.1Skamil	struct ptrace_siginfo psi;
70811.1Skamil
70821.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
70831.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
70841.1Skamil	if (child == 0) {
70851.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
70861.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
70871.1Skamil
70881.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
70891.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
70901.1Skamil
70911.13Schristos		DPRINTF("Before exiting of the child process\n");
70921.1Skamil		_exit(exitval);
70931.1Skamil	}
70941.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
70951.1Skamil
70961.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
70971.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
70981.1Skamil
70991.1Skamil	validate_status_stopped(status, sigval);
71001.1Skamil
71011.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
71021.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
71031.1Skamil
71041.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
71051.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
71061.1Skamil
71071.13Schristos	DPRINTF("Before resuming the child process where it left off and "
71081.1Skamil	    "without signal to be sent\n");
71091.1Skamil	ATF_REQUIRE_ERRNO(EDEADLK,
71101.1Skamil	    ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
71111.1Skamil
71121.13Schristos	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
71131.13Schristos	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
71141.1Skamil
71151.13Schristos	DPRINTF("Before resuming the child process where it left off and "
71161.1Skamil	    "without signal to be sent\n");
71171.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
71181.1Skamil
71191.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
71201.1Skamil	    TWAIT_FNAME);
71211.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
71221.1Skamil
71231.1Skamil	validate_status_exited(status, exitval);
71241.1Skamil
71251.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
71261.1Skamil	    TWAIT_FNAME);
71271.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
71281.1Skamil}
71291.1Skamil
71301.154Skamil/// ----------------------------------------------------------------------------
71311.154Skamil
71321.155Skamilstatic pthread_barrier_t barrier1_resume;
71331.155Skamilstatic pthread_barrier_t barrier2_resume;
71341.154Skamil
71351.155Skamilstatic void *
71361.155Skamilresume_thread(void *arg)
71371.154Skamil{
71381.154Skamil
71391.155Skamil	raise(SIGUSR1);
71401.155Skamil
71411.155Skamil	pthread_barrier_wait(&barrier1_resume);
71421.155Skamil
71431.155Skamil	/* Debugger will suspend the process here */
71441.155Skamil
71451.155Skamil	pthread_barrier_wait(&barrier2_resume);
71461.154Skamil
71471.155Skamil	raise(SIGUSR2);
71481.155Skamil
71491.155Skamil	return infinite_thread(arg);
71501.154Skamil}
71511.154Skamil
71521.155SkamilATF_TC(resume);
71531.155SkamilATF_TC_HEAD(resume, tc)
71541.1Skamil{
71551.1Skamil	atf_tc_set_md_var(tc, "descr",
71561.1Skamil	    "Verify that a thread can be suspended by a debugger and later "
71571.1Skamil	    "resumed by the debugger");
71581.1Skamil}
71591.1Skamil
71601.155SkamilATF_TC_BODY(resume, tc)
71611.1Skamil{
71621.1Skamil	const int sigval = SIGSTOP;
71631.1Skamil	pid_t child, wpid;
71641.1Skamil#if defined(TWAIT_HAVE_STATUS)
71651.1Skamil	int status;
71661.1Skamil#endif
71671.1Skamil	lwpid_t lid;
71681.1Skamil	struct ptrace_siginfo psi;
71691.155Skamil	pthread_t t;
71701.1Skamil
71711.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
71721.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
71731.1Skamil	if (child == 0) {
71741.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
71751.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
71761.1Skamil
71771.155Skamil		pthread_barrier_init(&barrier1_resume, NULL, 2);
71781.155Skamil		pthread_barrier_init(&barrier2_resume, NULL, 2);
71791.155Skamil
71801.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
71811.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
71821.1Skamil
71831.155Skamil		DPRINTF("Before creating new thread in child\n");
71841.155Skamil		FORKEE_ASSERT(pthread_create(&t, NULL, resume_thread, NULL) == 0);
71851.1Skamil
71861.155Skamil		pthread_barrier_wait(&barrier1_resume);
71871.1Skamil
71881.155Skamil		pthread_barrier_wait(&barrier2_resume);
71891.1Skamil
71901.155Skamil		infinite_thread(NULL);
71911.1Skamil	}
71921.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
71931.1Skamil
71941.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
71951.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
71961.1Skamil
71971.1Skamil	validate_status_stopped(status, sigval);
71981.1Skamil
71991.13Schristos	DPRINTF("Before resuming the child process where it left off and "
72001.1Skamil	    "without signal to be sent\n");
72011.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
72021.1Skamil
72031.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
72041.155Skamil	    "SIGUSR1\n", TWAIT_FNAME);
72051.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
72061.1Skamil
72071.155Skamil	validate_status_stopped(status, SIGUSR1);
72081.1Skamil
72091.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
72101.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
72111.1Skamil
72121.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
72131.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
72141.1Skamil
72151.155Skamil	lid = psi.psi_lwpid;
72161.1Skamil
72171.13Schristos	DPRINTF("Before resuming the child process where it left off and "
72181.1Skamil	    "without signal to be sent\n");
72191.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
72201.1Skamil
72211.155Skamil	DPRINTF("Before suspending the parent for 1 second, we expect no signals\n");
72221.155Skamil	SYSCALL_REQUIRE(sleep(1) == 0);
72231.155Skamil
72241.155Skamil#if defined(TWAIT_HAVE_OPTIONS)
72251.155Skamil	DPRINTF("Before calling %s() for the child - expected no status\n",
72261.155Skamil	    TWAIT_FNAME);
72271.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, WNOHANG), 0);
72281.155Skamil#endif
72291.155Skamil
72301.155Skamil	DPRINTF("Before resuming the child process where it left off and "
72311.155Skamil	    "without signal to be sent\n");
72321.155Skamil	SYSCALL_REQUIRE(ptrace(PT_STOP, child, NULL, 0) != -1);
72331.155Skamil
72341.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
72351.155Skamil	    "SIGSTOP\n", TWAIT_FNAME);
72361.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
72371.1Skamil
72381.155Skamil	validate_status_stopped(status, SIGSTOP);
72391.1Skamil
72401.155Skamil	DPRINTF("Before resuming LWP %d\n", lid);
72411.155Skamil	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, lid) != -1);
72421.155Skamil
72431.155Skamil	DPRINTF("Before resuming the child process where it left off and "
72441.155Skamil	    "without signal to be sent\n");
72451.155Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
72461.1Skamil
72471.155Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
72481.155Skamil	    "SIGUSR2\n", TWAIT_FNAME);
72491.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
72501.1Skamil
72511.155Skamil	validate_status_stopped(status, SIGUSR2);
72521.1Skamil
72531.13Schristos	DPRINTF("Before resuming the child process where it left off and "
72541.1Skamil	    "without signal to be sent\n");
72551.155Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
72561.1Skamil
72571.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
72581.1Skamil	    TWAIT_FNAME);
72591.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
72601.1Skamil
72611.155Skamil	validate_status_signaled(status, SIGKILL, 0);
72621.1Skamil
72631.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
72641.1Skamil	    TWAIT_FNAME);
72651.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
72661.155Skamil}
72671.1Skamil
72681.155Skamil/// ----------------------------------------------------------------------------
72691.1Skamil
72701.167Skamilstatic int test_syscall_caught;
72711.167Skamil
72721.167Skamilstatic void
72731.167Skamilsyscall_sighand(int arg)
72741.167Skamil{
72751.167Skamil
72761.167Skamil	DPRINTF("Caught a signal %d in process %d\n", arg, getpid());
72771.167Skamil
72781.167Skamil	FORKEE_ASSERT_EQ(arg, SIGINFO);
72791.167Skamil
72801.167Skamil	++test_syscall_caught;
72811.167Skamil
72821.167Skamil	FORKEE_ASSERT_EQ(test_syscall_caught, 1);
72831.167Skamil}
72841.167Skamil
72851.166Skamilstatic void
72861.167Skamilsyscall_body(const char *op)
72871.1Skamil{
72881.1Skamil	const int exitval = 5;
72891.1Skamil	const int sigval = SIGSTOP;
72901.1Skamil	pid_t child, wpid;
72911.1Skamil#if defined(TWAIT_HAVE_STATUS)
72921.1Skamil	int status;
72931.1Skamil#endif
72941.1Skamil	struct ptrace_siginfo info;
72951.167Skamil
72961.1Skamil	memset(&info, 0, sizeof(info));
72971.1Skamil
72981.167Skamil#if defined(TWAIT_HAVE_STATUS)
72991.167Skamil	if (strstr(op, "signal") != NULL) {
73001.167Skamil		atf_tc_expect_fail("XXX: behavior under investigation");
73011.167Skamil	}
73021.167Skamil#endif
73031.167Skamil
73041.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
73051.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
73061.1Skamil	if (child == 0) {
73071.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
73081.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
73091.1Skamil
73101.167Skamil		signal(SIGINFO, syscall_sighand);
73111.167Skamil
73121.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
73131.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
73141.1Skamil
73151.1Skamil		syscall(SYS_getpid);
73161.1Skamil
73171.167Skamil		if (strstr(op, "signal") != NULL) {
73181.167Skamil			FORKEE_ASSERT_EQ(test_syscall_caught, 1);
73191.167Skamil		}
73201.167Skamil
73211.13Schristos		DPRINTF("Before exiting of the child process\n");
73221.1Skamil		_exit(exitval);
73231.1Skamil	}
73241.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
73251.1Skamil
73261.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
73271.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
73281.1Skamil
73291.1Skamil	validate_status_stopped(status, sigval);
73301.1Skamil
73311.13Schristos	DPRINTF("Before resuming the child process where it left off and "
73321.1Skamil	    "without signal to be sent\n");
73331.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
73341.1Skamil
73351.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
73361.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
73371.1Skamil
73381.1Skamil	validate_status_stopped(status, SIGTRAP);
73391.1Skamil
73401.13Schristos	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
73411.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
73421.1Skamil
73431.38Skamil	DPRINTF("Before checking siginfo_t and lwpid\n");
73441.173Skamil	ATF_REQUIRE(info.psi_lwpid > 0);
73451.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
73461.1Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_SCE);
73471.1Skamil
73481.167Skamil	if (strstr(op, "killed") != NULL) {
73491.166Skamil		SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
73501.166Skamil
73511.166Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
73521.166Skamil		TWAIT_REQUIRE_SUCCESS(
73531.166Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
73541.166Skamil
73551.166Skamil		validate_status_signaled(status, SIGKILL, 0);
73561.166Skamil	} else {
73571.167Skamil		if (strstr(op, "signal") != NULL) {
73581.167Skamil			DPRINTF("Before resuming the child %d and sending a "
73591.167Skamil			    "signal SIGINFO\n", child);
73601.167Skamil			SYSCALL_REQUIRE(
73611.167Skamil			    ptrace(PT_CONTINUE, child, (void *)1, SIGINFO)
73621.167Skamil			    != -1);
73631.167Skamil		} else if (strstr(op, "detach") != NULL) {
73641.167Skamil			DPRINTF("Before detaching the child %d\n", child);
73651.167Skamil			SYSCALL_REQUIRE(
73661.167Skamil			    ptrace(PT_DETACH, child, (void *)1, 0) != -1);
73671.167Skamil		} else {
73681.167Skamil			DPRINTF("Before resuming the child process where it "
73691.167Skamil			    "left off and without signal to be sent\n");
73701.167Skamil			SYSCALL_REQUIRE(
73711.167Skamil			    ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
73721.166Skamil
73731.167Skamil			DPRINTF("Before calling %s() for the child\n",
73741.167Skamil			    TWAIT_FNAME);
73751.167Skamil			TWAIT_REQUIRE_SUCCESS(
73761.167Skamil			    wpid = TWAIT_GENERIC(child, &status, 0), child);
73771.1Skamil
73781.167Skamil			validate_status_stopped(status, SIGTRAP);
73791.1Skamil
73801.167Skamil			DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO "
73811.167Skamil			    "for child\n");
73821.167Skamil			SYSCALL_REQUIRE(
73831.167Skamil			    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info))
73841.167Skamil			    != -1);
73851.1Skamil
73861.167Skamil			DPRINTF("Before checking siginfo_t and lwpid\n");
73871.173Skamil			ATF_REQUIRE(info.psi_lwpid > 0);
73881.167Skamil			ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
73891.167Skamil			ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_SCX);
73901.1Skamil
73911.167Skamil			DPRINTF("Before resuming the child process where it "
73921.167Skamil			    "left off and without signal to be sent\n");
73931.167Skamil			SYSCALL_REQUIRE(
73941.167Skamil			    ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
73951.167Skamil		}
73961.1Skamil
73971.166Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
73981.166Skamil		TWAIT_REQUIRE_SUCCESS(
73991.166Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
74001.1Skamil
74011.166Skamil		validate_status_exited(status, exitval);
74021.166Skamil	}
74031.1Skamil
74041.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
74051.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
74061.1Skamil}
74071.1Skamil
74081.167Skamil#define SYSCALL_TEST(name,op)						\
74091.166SkamilATF_TC(name);								\
74101.166SkamilATF_TC_HEAD(name, tc)							\
74111.166Skamil{									\
74121.170Skamil	atf_tc_set_md_var(tc, "timeout", "15");				\
74131.166Skamil	atf_tc_set_md_var(tc, "descr",					\
74141.166Skamil	    "Verify that getpid(2) can be traced with PT_SYSCALL %s",	\
74151.167Skamil	   #op );							\
74161.166Skamil}									\
74171.166Skamil									\
74181.166SkamilATF_TC_BODY(name, tc)							\
74191.166Skamil{									\
74201.166Skamil									\
74211.167Skamil	syscall_body(op);						\
74221.166Skamil}
74231.166Skamil
74241.167SkamilSYSCALL_TEST(syscall, "")
74251.167SkamilSYSCALL_TEST(syscall_killed_on_sce, "and killed")
74261.167SkamilSYSCALL_TEST(syscall_signal_on_sce, "and signaled")
74271.167SkamilSYSCALL_TEST(syscall_detach_on_sce, "and detached")
74281.166Skamil
74291.164Skamil/// ----------------------------------------------------------------------------
74301.164Skamil
74311.1SkamilATF_TC(syscallemu1);
74321.1SkamilATF_TC_HEAD(syscallemu1, tc)
74331.1Skamil{
74341.1Skamil	atf_tc_set_md_var(tc, "descr",
74351.1Skamil	    "Verify that exit(2) can be intercepted with PT_SYSCALLEMU");
74361.1Skamil}
74371.1Skamil
74381.1SkamilATF_TC_BODY(syscallemu1, tc)
74391.1Skamil{
74401.1Skamil	const int exitval = 5;
74411.1Skamil	const int sigval = SIGSTOP;
74421.1Skamil	pid_t child, wpid;
74431.1Skamil#if defined(TWAIT_HAVE_STATUS)
74441.1Skamil	int status;
74451.1Skamil#endif
74461.1Skamil
74471.6Skamil#if defined(__sparc__) && !defined(__sparc64__)
74481.6Skamil	/* syscallemu does not work on sparc (32-bit) */
74491.6Skamil	atf_tc_expect_fail("PR kern/52166");
74501.6Skamil#endif
74511.6Skamil
74521.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
74531.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
74541.1Skamil	if (child == 0) {
74551.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
74561.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
74571.1Skamil
74581.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
74591.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
74601.1Skamil
74611.1Skamil		syscall(SYS_exit, 100);
74621.1Skamil
74631.13Schristos		DPRINTF("Before exiting of the child process\n");
74641.1Skamil		_exit(exitval);
74651.1Skamil	}
74661.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
74671.1Skamil
74681.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
74691.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74701.1Skamil
74711.1Skamil	validate_status_stopped(status, sigval);
74721.1Skamil
74731.13Schristos	DPRINTF("Before resuming the child process where it left off and "
74741.1Skamil	    "without signal to be sent\n");
74751.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
74761.1Skamil
74771.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
74781.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74791.1Skamil
74801.1Skamil	validate_status_stopped(status, SIGTRAP);
74811.1Skamil
74821.13Schristos	DPRINTF("Set SYSCALLEMU for intercepted syscall\n");
74831.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALLEMU, child, (void *)1, 0) != -1);
74841.1Skamil
74851.13Schristos	DPRINTF("Before resuming the child process where it left off and "
74861.1Skamil	    "without signal to be sent\n");
74871.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1);
74881.1Skamil
74891.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
74901.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
74911.1Skamil
74921.1Skamil	validate_status_stopped(status, SIGTRAP);
74931.1Skamil
74941.13Schristos	DPRINTF("Before resuming the child process where it left off and "
74951.1Skamil	    "without signal to be sent\n");
74961.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
74971.1Skamil
74981.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
74991.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
75001.1Skamil
75011.1Skamil	validate_status_exited(status, exitval);
75021.1Skamil
75031.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
75041.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
75051.1Skamil}
75061.1Skamil
75071.103Skamil/// ----------------------------------------------------------------------------
75081.103Skamil
75091.106Skamilstatic void
75101.106Skamilclone_body(int flags, bool trackfork, bool trackvfork,
75111.106Skamil    bool trackvforkdone)
75121.106Skamil{
75131.106Skamil	const int exitval = 5;
75141.106Skamil	const int exitval2 = 15;
75151.106Skamil	const int sigval = SIGSTOP;
75161.106Skamil	pid_t child, child2 = 0, wpid;
75171.106Skamil#if defined(TWAIT_HAVE_STATUS)
75181.106Skamil	int status;
75191.106Skamil#endif
75201.106Skamil	ptrace_state_t state;
75211.106Skamil	const int slen = sizeof(state);
75221.106Skamil	ptrace_event_t event;
75231.106Skamil	const int elen = sizeof(event);
75241.106Skamil
75251.106Skamil	const size_t stack_size = 1024 * 1024;
75261.106Skamil	void *stack, *stack_base;
75271.106Skamil
75281.106Skamil	stack = malloc(stack_size);
75291.106Skamil	ATF_REQUIRE(stack != NULL);
75301.106Skamil
75311.106Skamil#ifdef __MACHINE_STACK_GROWS_UP
75321.106Skamil	stack_base = stack;
75331.106Skamil#else
75341.106Skamil	stack_base = (char *)stack + stack_size;
75351.106Skamil#endif
75361.106Skamil
75371.106Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
75381.106Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
75391.106Skamil	if (child == 0) {
75401.106Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
75411.106Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
75421.106Skamil
75431.106Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
75441.106Skamil		FORKEE_ASSERT(raise(sigval) == 0);
75451.106Skamil
75461.106Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
75471.106Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
75481.106Skamil
75491.106Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
75501.106Skamil		    child2);
75511.106Skamil
75521.106Skamil		// XXX WALLSIG?
75531.106Skamil		FORKEE_REQUIRE_SUCCESS
75541.106Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
75551.106Skamil
75561.106Skamil		forkee_status_exited(status, exitval2);
75571.106Skamil
75581.106Skamil		DPRINTF("Before exiting of the child process\n");
75591.106Skamil		_exit(exitval);
75601.106Skamil	}
75611.106Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
75621.106Skamil
75631.106Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
75641.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
75651.106Skamil
75661.106Skamil	validate_status_stopped(status, sigval);
75671.106Skamil
75681.106Skamil	DPRINTF("Set 0%s%s%s in EVENT_MASK for the child %d\n",
75691.106Skamil	    trackfork ? "|PTRACE_FORK" : "",
75701.106Skamil	    trackvfork ? "|PTRACE_VFORK" : "",
75711.106Skamil	    trackvforkdone ? "|PTRACE_VFORK_DONE" : "", child);
75721.106Skamil	event.pe_set_event = 0;
75731.106Skamil	if (trackfork)
75741.106Skamil		event.pe_set_event |= PTRACE_FORK;
75751.106Skamil	if (trackvfork)
75761.106Skamil		event.pe_set_event |= PTRACE_VFORK;
75771.106Skamil	if (trackvforkdone)
75781.106Skamil		event.pe_set_event |= PTRACE_VFORK_DONE;
75791.106Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
75801.106Skamil
75811.106Skamil	DPRINTF("Before resuming the child process where it left off and "
75821.106Skamil	    "without signal to be sent\n");
75831.106Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
75841.106Skamil
75851.106Skamil#if defined(TWAIT_HAVE_PID)
75861.106Skamil	if ((trackfork && !(flags & CLONE_VFORK)) ||
75871.106Skamil	    (trackvfork && (flags & CLONE_VFORK))) {
75881.106Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
75891.106Skamil		    child);
75901.106Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
75911.106Skamil		    child);
75921.106Skamil
75931.106Skamil		validate_status_stopped(status, SIGTRAP);
75941.106Skamil
75951.106Skamil		SYSCALL_REQUIRE(
75961.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
75971.106Skamil		if (trackfork && !(flags & CLONE_VFORK)) {
75981.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
75991.106Skamil			       PTRACE_FORK);
76001.106Skamil		}
76011.106Skamil		if (trackvfork && (flags & CLONE_VFORK)) {
76021.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
76031.106Skamil			       PTRACE_VFORK);
76041.106Skamil		}
76051.106Skamil
76061.106Skamil		child2 = state.pe_other_pid;
76071.106Skamil		DPRINTF("Reported ptrace event with forkee %d\n", child2);
76081.106Skamil
76091.106Skamil		DPRINTF("Before calling %s() for the forkee %d of the child "
76101.106Skamil		    "%d\n", TWAIT_FNAME, child2, child);
76111.106Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
76121.106Skamil		    child2);
76131.106Skamil
76141.106Skamil		validate_status_stopped(status, SIGTRAP);
76151.106Skamil
76161.106Skamil		SYSCALL_REQUIRE(
76171.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
76181.106Skamil		if (trackfork && !(flags & CLONE_VFORK)) {
76191.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
76201.106Skamil			       PTRACE_FORK);
76211.106Skamil		}
76221.106Skamil		if (trackvfork && (flags & CLONE_VFORK)) {
76231.106Skamil			ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
76241.106Skamil			       PTRACE_VFORK);
76251.106Skamil		}
76261.106Skamil
76271.106Skamil		ATF_REQUIRE_EQ(state.pe_other_pid, child);
76281.106Skamil
76291.106Skamil		DPRINTF("Before resuming the forkee process where it left off "
76301.106Skamil		    "and without signal to be sent\n");
76311.106Skamil		SYSCALL_REQUIRE(
76321.106Skamil		    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
76331.106Skamil
76341.106Skamil		DPRINTF("Before resuming the child process where it left off "
76351.106Skamil		    "and without signal to be sent\n");
76361.106Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
76371.106Skamil	}
76381.106Skamil#endif
76391.106Skamil
76401.106Skamil	if (trackvforkdone && (flags & CLONE_VFORK)) {
76411.106Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
76421.106Skamil		    child);
76431.106Skamil		TWAIT_REQUIRE_SUCCESS(
76441.106Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
76451.106Skamil
76461.106Skamil		validate_status_stopped(status, SIGTRAP);
76471.106Skamil
76481.106Skamil		SYSCALL_REQUIRE(
76491.106Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
76501.106Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
76511.106Skamil
76521.106Skamil		child2 = state.pe_other_pid;
76531.106Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
76541.106Skamil		    child2);
76551.106Skamil
76561.106Skamil		DPRINTF("Before resuming the child process where it left off "
76571.106Skamil		    "and without signal to be sent\n");
76581.106Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
76591.106Skamil	}
76601.106Skamil
76611.103Skamil#if defined(TWAIT_HAVE_PID)
76621.106Skamil	if ((trackfork && !(flags & CLONE_VFORK)) ||
76631.106Skamil	    (trackvfork && (flags & CLONE_VFORK))) {
76641.106Skamil		DPRINTF("Before calling %s() for the forkee - expected exited"
76651.106Skamil		    "\n", TWAIT_FNAME);
76661.106Skamil		TWAIT_REQUIRE_SUCCESS(
76671.106Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
76681.106Skamil
76691.106Skamil		validate_status_exited(status, exitval2);
76701.106Skamil
76711.106Skamil		DPRINTF("Before calling %s() for the forkee - expected no "
76721.106Skamil		    "process\n", TWAIT_FNAME);
76731.106Skamil		TWAIT_REQUIRE_FAILURE(ECHILD,
76741.106Skamil		    wpid = TWAIT_GENERIC(child2, &status, 0));
76751.106Skamil	}
76761.106Skamil#endif
76771.106Skamil
76781.106Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
76791.106Skamil	    "SIGCHLD\n", TWAIT_FNAME);
76801.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
76811.106Skamil
76821.106Skamil	validate_status_stopped(status, SIGCHLD);
76831.106Skamil
76841.106Skamil	DPRINTF("Before resuming the child process where it left off and "
76851.106Skamil	    "without signal to be sent\n");
76861.106Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
76871.106Skamil
76881.106Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
76891.106Skamil	    TWAIT_FNAME);
76901.106Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
76911.106Skamil
76921.106Skamil	validate_status_exited(status, exitval);
76931.103Skamil
76941.106Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
76951.106Skamil	    TWAIT_FNAME);
76961.106Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
76971.106Skamil}
76981.103Skamil
76991.106Skamil#define CLONE_TEST(name,flags,tfork,tvfork,tvforkdone)			\
77001.106SkamilATF_TC(name);								\
77011.106SkamilATF_TC_HEAD(name, tc)							\
77021.106Skamil{									\
77031.106Skamil	atf_tc_set_md_var(tc, "descr", "Verify clone(%s) "		\
77041.106Skamil	    "called with 0%s%s%s in EVENT_MASK",			\
77051.106Skamil	    #flags,							\
77061.106Skamil	    tfork ? "|PTRACE_FORK" : "",				\
77071.106Skamil	    tvfork ? "|PTRACE_VFORK" : "",				\
77081.106Skamil	    tvforkdone ? "|PTRACE_VFORK_DONE" : "");			\
77091.106Skamil}									\
77101.106Skamil									\
77111.106SkamilATF_TC_BODY(name, tc)							\
77121.106Skamil{									\
77131.106Skamil									\
77141.106Skamil	clone_body(flags, tfork, tvfork, tvforkdone);			\
77151.103Skamil}
77161.103Skamil
77171.106SkamilCLONE_TEST(clone1, 0, false, false, false)
77181.106Skamil#if defined(TWAIT_HAVE_PID)
77191.106SkamilCLONE_TEST(clone2, 0, true, false, false)
77201.106SkamilCLONE_TEST(clone3, 0, false, true, false)
77211.106SkamilCLONE_TEST(clone4, 0, true, true, false)
77221.106Skamil#endif
77231.106SkamilCLONE_TEST(clone5, 0, false, false, true)
77241.106Skamil#if defined(TWAIT_HAVE_PID)
77251.106SkamilCLONE_TEST(clone6, 0, true, false, true)
77261.106SkamilCLONE_TEST(clone7, 0, false, true, true)
77271.106SkamilCLONE_TEST(clone8, 0, true, true, true)
77281.106Skamil#endif
77291.106Skamil
77301.106SkamilCLONE_TEST(clone_vm1, CLONE_VM, false, false, false)
77311.106Skamil#if defined(TWAIT_HAVE_PID)
77321.106SkamilCLONE_TEST(clone_vm2, CLONE_VM, true, false, false)
77331.106SkamilCLONE_TEST(clone_vm3, CLONE_VM, false, true, false)
77341.106SkamilCLONE_TEST(clone_vm4, CLONE_VM, true, true, false)
77351.106Skamil#endif
77361.106SkamilCLONE_TEST(clone_vm5, CLONE_VM, false, false, true)
77371.106Skamil#if defined(TWAIT_HAVE_PID)
77381.106SkamilCLONE_TEST(clone_vm6, CLONE_VM, true, false, true)
77391.106SkamilCLONE_TEST(clone_vm7, CLONE_VM, false, true, true)
77401.106SkamilCLONE_TEST(clone_vm8, CLONE_VM, true, true, true)
77411.106Skamil#endif
77421.106Skamil
77431.106SkamilCLONE_TEST(clone_fs1, CLONE_FS, false, false, false)
77441.106Skamil#if defined(TWAIT_HAVE_PID)
77451.106SkamilCLONE_TEST(clone_fs2, CLONE_FS, true, false, false)
77461.106SkamilCLONE_TEST(clone_fs3, CLONE_FS, false, true, false)
77471.106SkamilCLONE_TEST(clone_fs4, CLONE_FS, true, true, false)
77481.106Skamil#endif
77491.106SkamilCLONE_TEST(clone_fs5, CLONE_FS, false, false, true)
77501.106Skamil#if defined(TWAIT_HAVE_PID)
77511.106SkamilCLONE_TEST(clone_fs6, CLONE_FS, true, false, true)
77521.106SkamilCLONE_TEST(clone_fs7, CLONE_FS, false, true, true)
77531.106SkamilCLONE_TEST(clone_fs8, CLONE_FS, true, true, true)
77541.106Skamil#endif
77551.106Skamil
77561.106SkamilCLONE_TEST(clone_files1, CLONE_FILES, false, false, false)
77571.106Skamil#if defined(TWAIT_HAVE_PID)
77581.106SkamilCLONE_TEST(clone_files2, CLONE_FILES, true, false, false)
77591.106SkamilCLONE_TEST(clone_files3, CLONE_FILES, false, true, false)
77601.106SkamilCLONE_TEST(clone_files4, CLONE_FILES, true, true, false)
77611.106Skamil#endif
77621.106SkamilCLONE_TEST(clone_files5, CLONE_FILES, false, false, true)
77631.106Skamil#if defined(TWAIT_HAVE_PID)
77641.106SkamilCLONE_TEST(clone_files6, CLONE_FILES, true, false, true)
77651.106SkamilCLONE_TEST(clone_files7, CLONE_FILES, false, true, true)
77661.106SkamilCLONE_TEST(clone_files8, CLONE_FILES, true, true, true)
77671.106Skamil#endif
77681.106Skamil
77691.106Skamil//CLONE_TEST(clone_sighand1, CLONE_SIGHAND, false, false, false)
77701.106Skamil#if defined(TWAIT_HAVE_PID)
77711.106Skamil//CLONE_TEST(clone_sighand2, CLONE_SIGHAND, true, false, false)
77721.106Skamil//CLONE_TEST(clone_sighand3, CLONE_SIGHAND, false, true, false)
77731.106Skamil//CLONE_TEST(clone_sighand4, CLONE_SIGHAND, true, true, false)
77741.106Skamil#endif
77751.106Skamil//CLONE_TEST(clone_sighand5, CLONE_SIGHAND, false, false, true)
77761.106Skamil#if defined(TWAIT_HAVE_PID)
77771.106Skamil//CLONE_TEST(clone_sighand6, CLONE_SIGHAND, true, false, true)
77781.106Skamil//CLONE_TEST(clone_sighand7, CLONE_SIGHAND, false, true, true)
77791.106Skamil//CLONE_TEST(clone_sighand8, CLONE_SIGHAND, true, true, true)
77801.106Skamil#endif
77811.106Skamil
77821.106SkamilCLONE_TEST(clone_vfork1, CLONE_VFORK, false, false, false)
77831.106Skamil#if defined(TWAIT_HAVE_PID)
77841.106SkamilCLONE_TEST(clone_vfork2, CLONE_VFORK, true, false, false)
77851.106SkamilCLONE_TEST(clone_vfork3, CLONE_VFORK, false, true, false)
77861.106SkamilCLONE_TEST(clone_vfork4, CLONE_VFORK, true, true, false)
77871.106Skamil#endif
77881.106SkamilCLONE_TEST(clone_vfork5, CLONE_VFORK, false, false, true)
77891.106Skamil#if defined(TWAIT_HAVE_PID)
77901.106SkamilCLONE_TEST(clone_vfork6, CLONE_VFORK, true, false, true)
77911.106SkamilCLONE_TEST(clone_vfork7, CLONE_VFORK, false, true, true)
77921.106SkamilCLONE_TEST(clone_vfork8, CLONE_VFORK, true, true, true)
77931.106Skamil#endif
77941.106Skamil
77951.106Skamil/// ----------------------------------------------------------------------------
77961.106Skamil
77971.106Skamil#if defined(TWAIT_HAVE_PID)
77981.103Skamilstatic void
77991.106Skamilclone_body2(int flags, bool masked, bool ignored)
78001.103Skamil{
78011.103Skamil	const int exitval = 5;
78021.103Skamil	const int exitval2 = 15;
78031.103Skamil	const int sigval = SIGSTOP;
78041.103Skamil	pid_t child, child2 = 0, wpid;
78051.103Skamil#if defined(TWAIT_HAVE_STATUS)
78061.103Skamil	int status;
78071.103Skamil#endif
78081.103Skamil	ptrace_state_t state;
78091.103Skamil	const int slen = sizeof(state);
78101.103Skamil	ptrace_event_t event;
78111.103Skamil	const int elen = sizeof(event);
78121.103Skamil	struct sigaction sa;
78131.103Skamil	struct ptrace_siginfo info;
78141.103Skamil	sigset_t intmask;
78151.103Skamil	struct kinfo_proc2 kp;
78161.103Skamil	size_t len = sizeof(kp);
78171.103Skamil
78181.103Skamil	int name[6];
78191.103Skamil	const size_t namelen = __arraycount(name);
78201.103Skamil	ki_sigset_t kp_sigmask;
78211.103Skamil	ki_sigset_t kp_sigignore;
78221.103Skamil
78231.103Skamil	const size_t stack_size = 1024 * 1024;
78241.103Skamil	void *stack, *stack_base;
78251.103Skamil
78261.103Skamil	stack = malloc(stack_size);
78271.103Skamil	ATF_REQUIRE(stack != NULL);
78281.103Skamil
78291.103Skamil#ifdef __MACHINE_STACK_GROWS_UP
78301.103Skamil	stack_base = stack;
78311.103Skamil#else
78321.103Skamil	stack_base = (char *)stack + stack_size;
78331.103Skamil#endif
78341.103Skamil
78351.103Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
78361.103Skamil	if (child == 0) {
78371.103Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
78381.103Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
78391.103Skamil
78401.103Skamil		if (masked) {
78411.103Skamil			sigemptyset(&intmask);
78421.103Skamil			sigaddset(&intmask, SIGTRAP);
78431.103Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
78441.103Skamil		}
78451.103Skamil
78461.103Skamil		if (ignored) {
78471.103Skamil			memset(&sa, 0, sizeof(sa));
78481.103Skamil			sa.sa_handler = SIG_IGN;
78491.103Skamil			sigemptyset(&sa.sa_mask);
78501.103Skamil			FORKEE_ASSERT(sigaction(SIGTRAP, &sa, NULL) != -1);
78511.103Skamil		}
78521.103Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
78531.103Skamil		FORKEE_ASSERT(raise(sigval) == 0);
78541.103Skamil
78551.103Skamil		DPRINTF("Before forking process PID=%d flags=%#x\n", getpid(),
78561.103Skamil		    flags);
78571.103Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
78581.103Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
78591.103Skamil
78601.103Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
78611.103Skamil		    child2);
78621.103Skamil
78631.103Skamil		// XXX WALLSIG?
78641.103Skamil		FORKEE_REQUIRE_SUCCESS
78651.103Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
78661.103Skamil
78671.103Skamil		forkee_status_exited(status, exitval2);
78681.103Skamil
78691.103Skamil		DPRINTF("Before exiting of the child process\n");
78701.103Skamil		_exit(exitval);
78711.103Skamil	}
78721.103Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
78731.103Skamil
78741.103Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
78751.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
78761.103Skamil
78771.103Skamil	validate_status_stopped(status, sigval);
78781.103Skamil
78791.103Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
78801.103Skamil	SYSCALL_REQUIRE(
78811.103Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
78821.103Skamil
78831.103Skamil	DPRINTF("Before checking siginfo_t\n");
78841.103Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
78851.103Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
78861.103Skamil
78871.103Skamil	name[0] = CTL_KERN,
78881.103Skamil	name[1] = KERN_PROC2,
78891.103Skamil	name[2] = KERN_PROC_PID;
78901.103Skamil	name[3] = child;
78911.103Skamil	name[4] = sizeof(kp);
78921.103Skamil	name[5] = 1;
78931.103Skamil
78941.103Skamil	FORKEE_ASSERT_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
78951.103Skamil
78961.103Skamil	if (masked)
78971.103Skamil		kp_sigmask = kp.p_sigmask;
78981.103Skamil
78991.103Skamil	if (ignored)
79001.103Skamil		kp_sigignore = kp.p_sigignore;
79011.103Skamil
79021.103Skamil	DPRINTF("Set PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE in "
79031.103Skamil	    "EVENT_MASK for the child %d\n", child);
79041.103Skamil	event.pe_set_event = PTRACE_FORK | PTRACE_VFORK | PTRACE_VFORK_DONE;
79051.103Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
79061.103Skamil
79071.103Skamil	DPRINTF("Before resuming the child process where it left off and "
79081.103Skamil	    "without signal to be sent\n");
79091.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
79101.103Skamil
79111.103Skamil	DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
79121.103Skamil	    child);
79131.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
79141.103Skamil	    child);
79151.103Skamil
79161.103Skamil	validate_status_stopped(status, SIGTRAP);
79171.103Skamil
79181.103Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
79191.103Skamil
79201.103Skamil	if (masked) {
79211.103Skamil		DPRINTF("kp_sigmask="
79221.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
79231.103Skamil		    PRIx32 "\n",
79241.103Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
79251.103Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
79261.103Skamil
79271.103Skamil		DPRINTF("kp.p_sigmask="
79281.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
79291.103Skamil		    PRIx32 "\n",
79301.103Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
79311.103Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
79321.103Skamil
79331.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
79341.103Skamil		    sizeof(kp_sigmask)));
79351.103Skamil	}
79361.103Skamil
79371.103Skamil	if (ignored) {
79381.103Skamil		DPRINTF("kp_sigignore="
79391.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
79401.103Skamil		    PRIx32 "\n",
79411.103Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
79421.103Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
79431.103Skamil
79441.103Skamil		DPRINTF("kp.p_sigignore="
79451.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
79461.103Skamil		    PRIx32 "\n",
79471.103Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
79481.103Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
79491.103Skamil
79501.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
79511.103Skamil		    sizeof(kp_sigignore)));
79521.103Skamil	}
79531.103Skamil
79541.103Skamil	SYSCALL_REQUIRE(
79551.103Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
79561.103Skamil	DPRINTF("state.pe_report_event=%#x pid=%d\n", state.pe_report_event,
79571.103Skamil	    child2);
79581.103Skamil	if (!(flags & CLONE_VFORK)) {
79591.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
79601.103Skamil		       PTRACE_FORK);
79611.103Skamil	} else {
79621.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
79631.103Skamil		       PTRACE_VFORK);
79641.103Skamil	}
79651.103Skamil
79661.103Skamil	child2 = state.pe_other_pid;
79671.103Skamil	DPRINTF("Reported ptrace event with forkee %d\n", child2);
79681.103Skamil
79691.103Skamil	DPRINTF("Before calling %s() for the forkee %d of the child "
79701.103Skamil	    "%d\n", TWAIT_FNAME, child2, child);
79711.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child2, &status, 0),
79721.103Skamil	    child2);
79731.103Skamil
79741.103Skamil	validate_status_stopped(status, SIGTRAP);
79751.103Skamil
79761.103Skamil	name[3] = child2;
79771.103Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
79781.103Skamil
79791.103Skamil	if (masked) {
79801.103Skamil		DPRINTF("kp_sigmask="
79811.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
79821.103Skamil		    PRIx32 "\n",
79831.103Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
79841.103Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
79851.103Skamil
79861.103Skamil		DPRINTF("kp.p_sigmask="
79871.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
79881.103Skamil		    PRIx32 "\n",
79891.103Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
79901.103Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
79911.103Skamil
79921.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
79931.103Skamil		    sizeof(kp_sigmask)));
79941.103Skamil	}
79951.103Skamil
79961.103Skamil	if (ignored) {
79971.103Skamil		DPRINTF("kp_sigignore="
79981.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
79991.103Skamil		    PRIx32 "\n",
80001.103Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
80011.103Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
80021.103Skamil
80031.103Skamil		DPRINTF("kp.p_sigignore="
80041.103Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
80051.103Skamil		    PRIx32 "\n",
80061.103Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
80071.103Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
80081.103Skamil
80091.103Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
80101.103Skamil		    sizeof(kp_sigignore)));
80111.103Skamil	}
80121.103Skamil
80131.103Skamil	SYSCALL_REQUIRE(
80141.103Skamil	    ptrace(PT_GET_PROCESS_STATE, child2, &state, slen) != -1);
80151.103Skamil	if (!(flags & CLONE_VFORK)) {
80161.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_FORK,
80171.103Skamil		       PTRACE_FORK);
80181.103Skamil	} else {
80191.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event & PTRACE_VFORK,
80201.103Skamil		       PTRACE_VFORK);
80211.103Skamil	}
80221.103Skamil
80231.103Skamil	ATF_REQUIRE_EQ(state.pe_other_pid, child);
80241.103Skamil
80251.103Skamil	DPRINTF("Before resuming the forkee process where it left off "
80261.103Skamil	    "and without signal to be sent\n");
80271.103Skamil	SYSCALL_REQUIRE(
80281.103Skamil	    ptrace(PT_CONTINUE, child2, (void *)1, 0) != -1);
80291.103Skamil
80301.103Skamil	DPRINTF("Before resuming the child process where it left off "
80311.103Skamil	    "and without signal to be sent\n");
80321.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
80331.103Skamil
80341.103Skamil	if (flags & CLONE_VFORK) {
80351.103Skamil		DPRINTF("Before calling %s() for the child %d\n", TWAIT_FNAME,
80361.103Skamil		    child);
80371.103Skamil		TWAIT_REQUIRE_SUCCESS(
80381.103Skamil		    wpid = TWAIT_GENERIC(child, &status, 0), child);
80391.103Skamil
80401.103Skamil		validate_status_stopped(status, SIGTRAP);
80411.103Skamil
80421.103Skamil		name[3] = child;
80431.103Skamil		ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
80441.103Skamil
80451.103Skamil		/*
80461.103Skamil		 * SIGCHLD is now pending in the signal queue and
80471.103Skamil		 * the kernel presents it to userland as a masked signal.
80481.103Skamil		 */
80491.103Skamil		sigdelset((sigset_t *)&kp.p_sigmask, SIGCHLD);
80501.103Skamil
80511.103Skamil		if (masked) {
80521.103Skamil			DPRINTF("kp_sigmask="
80531.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
80541.103Skamil			    PRIx32 "\n",
80551.103Skamil			    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
80561.103Skamil			    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
80571.103Skamil
80581.103Skamil			DPRINTF("kp.p_sigmask="
80591.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
80601.103Skamil			    PRIx32 "\n",
80611.103Skamil			    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
80621.103Skamil			    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
80631.103Skamil
80641.103Skamil			ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
80651.103Skamil			    sizeof(kp_sigmask)));
80661.103Skamil		}
80671.103Skamil
80681.103Skamil		if (ignored) {
80691.103Skamil			DPRINTF("kp_sigignore="
80701.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
80711.103Skamil			    PRIx32 "\n",
80721.103Skamil			    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
80731.103Skamil			    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
80741.103Skamil
80751.103Skamil			DPRINTF("kp.p_sigignore="
80761.103Skamil			    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02"
80771.103Skamil			    PRIx32 "\n",
80781.103Skamil			    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
80791.103Skamil			    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
80801.103Skamil
80811.103Skamil			ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
80821.103Skamil			    sizeof(kp_sigignore)));
80831.103Skamil		}
80841.103Skamil
80851.103Skamil		SYSCALL_REQUIRE(
80861.103Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
80871.103Skamil		ATF_REQUIRE_EQ(state.pe_report_event, PTRACE_VFORK_DONE);
80881.103Skamil
80891.103Skamil		child2 = state.pe_other_pid;
80901.103Skamil		DPRINTF("Reported PTRACE_VFORK_DONE event with forkee %d\n",
80911.103Skamil		    child2);
80921.103Skamil
80931.103Skamil		DPRINTF("Before resuming the child process where it left off "
80941.103Skamil		    "and without signal to be sent\n");
80951.103Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
80961.103Skamil	}
80971.103Skamil
80981.103Skamil	DPRINTF("Before calling %s() for the forkee - expected exited"
80991.103Skamil	    "\n", TWAIT_FNAME);
81001.103Skamil	TWAIT_REQUIRE_SUCCESS(
81011.103Skamil	    wpid = TWAIT_GENERIC(child2, &status, 0), child2);
81021.103Skamil
81031.103Skamil	validate_status_exited(status, exitval2);
81041.103Skamil
81051.103Skamil	DPRINTF("Before calling %s() for the forkee - expected no "
81061.103Skamil	    "process\n", TWAIT_FNAME);
81071.103Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
81081.103Skamil	    wpid = TWAIT_GENERIC(child2, &status, 0));
81091.103Skamil
81101.103Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
81111.103Skamil	    "SIGCHLD\n", TWAIT_FNAME);
81121.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
81131.103Skamil
81141.103Skamil	validate_status_stopped(status, SIGCHLD);
81151.103Skamil
81161.103Skamil	DPRINTF("Before resuming the child process where it left off and "
81171.103Skamil	    "without signal to be sent\n");
81181.103Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
81191.103Skamil
81201.103Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
81211.103Skamil	    TWAIT_FNAME);
81221.103Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
81231.103Skamil
81241.103Skamil	validate_status_exited(status, exitval);
81251.103Skamil
81261.103Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
81271.103Skamil	    TWAIT_FNAME);
81281.103Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
81291.103Skamil}
81301.103Skamil
81311.106Skamil#define CLONE_TEST2(name,flags,masked,ignored)				\
81321.103SkamilATF_TC(name);								\
81331.103SkamilATF_TC_HEAD(name, tc)							\
81341.103Skamil{									\
81351.103Skamil	atf_tc_set_md_var(tc, "descr", "Verify that clone(%s) is caught"\
81361.103Skamil	    " regardless of signal %s%s", 				\
81371.103Skamil	    #flags, masked ? "masked" : "", ignored ? "ignored" : "");	\
81381.103Skamil}									\
81391.103Skamil									\
81401.103SkamilATF_TC_BODY(name, tc)							\
81411.103Skamil{									\
81421.103Skamil									\
81431.106Skamil	clone_body2(flags, masked, ignored);				\
81441.103Skamil}
81451.103Skamil
81461.106SkamilCLONE_TEST2(clone_signalignored, 0, true, false)
81471.106SkamilCLONE_TEST2(clone_signalmasked, 0, false, true)
81481.106SkamilCLONE_TEST2(clone_vm_signalignored, CLONE_VM, true, false)
81491.106SkamilCLONE_TEST2(clone_vm_signalmasked, CLONE_VM, false, true)
81501.106SkamilCLONE_TEST2(clone_fs_signalignored, CLONE_FS, true, false)
81511.106SkamilCLONE_TEST2(clone_fs_signalmasked, CLONE_FS, false, true)
81521.106SkamilCLONE_TEST2(clone_files_signalignored, CLONE_FILES, true, false)
81531.106SkamilCLONE_TEST2(clone_files_signalmasked, CLONE_FILES, false, true)
81541.106Skamil//CLONE_TEST2(clone_sighand_signalignored, CLONE_SIGHAND, true, false) // XXX
81551.106Skamil//CLONE_TEST2(clone_sighand_signalmasked, CLONE_SIGHAND, false, true)  // XXX
81561.106SkamilCLONE_TEST2(clone_vfork_signalignored, CLONE_VFORK, true, false)
81571.106SkamilCLONE_TEST2(clone_vfork_signalmasked, CLONE_VFORK, false, true)
81581.103Skamil#endif
81591.103Skamil
81601.103Skamil/// ----------------------------------------------------------------------------
81611.103Skamil
81621.107Skamil#if defined(TWAIT_HAVE_PID)
81631.107Skamilstatic void
81641.107Skamiltraceme_vfork_clone_body(int flags)
81651.107Skamil{
81661.107Skamil	const int exitval = 5;
81671.107Skamil	const int exitval2 = 15;
81681.107Skamil	pid_t child, child2 = 0, wpid;
81691.107Skamil#if defined(TWAIT_HAVE_STATUS)
81701.107Skamil	int status;
81711.107Skamil#endif
81721.107Skamil
81731.107Skamil	const size_t stack_size = 1024 * 1024;
81741.107Skamil	void *stack, *stack_base;
81751.107Skamil
81761.107Skamil	stack = malloc(stack_size);
81771.107Skamil	ATF_REQUIRE(stack != NULL);
81781.107Skamil
81791.107Skamil#ifdef __MACHINE_STACK_GROWS_UP
81801.107Skamil	stack_base = stack;
81811.107Skamil#else
81821.107Skamil	stack_base = (char *)stack + stack_size;
81831.107Skamil#endif
81841.107Skamil
81851.107Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
81861.107Skamil	if (child == 0) {
81871.107Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
81881.107Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
81891.107Skamil
81901.107Skamil		DPRINTF("Before forking process PID=%d flags=%#x\n", getpid(),
81911.107Skamil		    flags);
81921.107Skamil		SYSCALL_REQUIRE((child2 = __clone(clone_func, stack_base,
81931.107Skamil		    flags|SIGCHLD, (void *)(intptr_t)exitval2)) != -1);
81941.107Skamil
81951.107Skamil		DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(),
81961.107Skamil		    child2);
81971.107Skamil
81981.107Skamil		// XXX WALLSIG?
81991.107Skamil		FORKEE_REQUIRE_SUCCESS
82001.107Skamil		    (wpid = TWAIT_GENERIC(child2, &status, WALLSIG), child2);
82011.107Skamil
82021.107Skamil		forkee_status_exited(status, exitval2);
82031.107Skamil
82041.107Skamil		DPRINTF("Before exiting of the child process\n");
82051.107Skamil		_exit(exitval);
82061.107Skamil	}
82071.107Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
82081.107Skamil
82091.107Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
82101.107Skamil	    TWAIT_FNAME);
82111.107Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
82121.107Skamil
82131.107Skamil	validate_status_exited(status, exitval);
82141.107Skamil
82151.107Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
82161.107Skamil	    TWAIT_FNAME);
82171.107Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
82181.107Skamil}
82191.107Skamil
82201.107Skamil#define TRACEME_VFORK_CLONE_TEST(name,flags)				\
82211.107SkamilATF_TC(name);								\
82221.107SkamilATF_TC_HEAD(name, tc)							\
82231.107Skamil{									\
82241.107Skamil	atf_tc_set_md_var(tc, "descr", "Verify that clone(%s) is "	\
82251.107Skamil	    "handled correctly with vfork(2)ed tracer", 		\
82261.107Skamil	    #flags);							\
82271.107Skamil}									\
82281.107Skamil									\
82291.107SkamilATF_TC_BODY(name, tc)							\
82301.107Skamil{									\
82311.107Skamil									\
82321.107Skamil	traceme_vfork_clone_body(flags);				\
82331.107Skamil}
82341.107Skamil
82351.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone, 0)
82361.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_vm, CLONE_VM)
82371.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_fs, CLONE_FS)
82381.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_files, CLONE_FILES)
82391.107Skamil//TRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_sighand, CLONE_SIGHAND)  // XXX
82401.107SkamilTRACEME_VFORK_CLONE_TEST(traceme_vfork_clone_vfork, CLONE_VFORK)
82411.107Skamil#endif
82421.107Skamil
82431.107Skamil/// ----------------------------------------------------------------------------
82441.107Skamil
82451.122Skamilstatic void
82461.122Skamiluser_va0_disable(int operation)
82471.122Skamil{
82481.122Skamil	pid_t child, wpid;
82491.122Skamil#if defined(TWAIT_HAVE_STATUS)
82501.122Skamil	int status;
82511.122Skamil#endif
82521.122Skamil	const int sigval = SIGSTOP;
82531.122Skamil	int rv;
82541.122Skamil
82551.122Skamil	struct ptrace_siginfo info;
82561.122Skamil
82571.122Skamil	if (get_user_va0_disable() == 0)
82581.122Skamil		atf_tc_skip("vm.user_va0_disable is set to 0");
82591.122Skamil
82601.122Skamil	memset(&info, 0, sizeof(info));
82611.122Skamil
82621.122Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
82631.122Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
82641.122Skamil	if (child == 0) {
82651.122Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
82661.122Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
82671.122Skamil
82681.122Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
82691.122Skamil		FORKEE_ASSERT(raise(sigval) == 0);
82701.122Skamil
82711.122Skamil		/* NOTREACHED */
82721.122Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
82731.122Skamil		__unreachable();
82741.122Skamil	}
82751.122Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
82761.122Skamil
82771.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
82781.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
82791.122Skamil
82801.122Skamil	validate_status_stopped(status, sigval);
82811.122Skamil
82821.122Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
82831.122Skamil		"child\n");
82841.122Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
82851.122Skamil		sizeof(info)) != -1);
82861.122Skamil
82871.122Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
82881.122Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
82891.122Skamil		"si_errno=%#x\n",
82901.122Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
82911.122Skamil		info.psi_siginfo.si_errno);
82921.122Skamil
82931.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
82941.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
82951.122Skamil
82961.122Skamil	DPRINTF("Before resuming the child process in PC=0x0 "
82971.122Skamil	    "and without signal to be sent\n");
82981.122Skamil	errno = 0;
82991.122Skamil	rv = ptrace(operation, child, (void *)0, 0);
83001.122Skamil	ATF_REQUIRE_EQ(errno, EINVAL);
83011.122Skamil	ATF_REQUIRE_EQ(rv, -1);
83021.122Skamil
83031.122Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
83041.122Skamil
83051.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
83061.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
83071.122Skamil	validate_status_signaled(status, SIGKILL, 0);
83081.122Skamil
83091.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
83101.122Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
83111.122Skamil}
83121.122Skamil
83131.122Skamil#define USER_VA0_DISABLE(test, operation)				\
83141.122SkamilATF_TC(test);								\
83151.122SkamilATF_TC_HEAD(test, tc)							\
83161.122Skamil{									\
83171.122Skamil	atf_tc_set_md_var(tc, "descr",					\
83181.122Skamil	    "Verify behavior of " #operation " with PC set to 0x0");	\
83191.122Skamil}									\
83201.122Skamil									\
83211.122SkamilATF_TC_BODY(test, tc)							\
83221.122Skamil{									\
83231.122Skamil									\
83241.122Skamil	user_va0_disable(operation);					\
83251.122Skamil}
83261.122Skamil
83271.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_continue, PT_CONTINUE)
83281.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_syscall, PT_SYSCALL)
83291.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_detach, PT_DETACH)
83301.122Skamil
83311.122Skamil/// ----------------------------------------------------------------------------
83321.122Skamil
83331.130Smgorny/*
83341.130Smgorny * Parse the core file and find the requested note.  If the reading or parsing
83351.130Smgorny * fails, the test is failed.  If the note is found, it is read onto buf, up to
83361.130Smgorny * buf_len.  The actual length of the note is returned (which can be greater
83371.130Smgorny * than buf_len, indicating that it has been truncated).  If the note is not
83381.130Smgorny * found, -1 is returned.
83391.172Sthorpej *
83401.172Sthorpej * If the note_name ends in '*', then we find the first note that matches
83411.172Sthorpej * the note_name prefix up to the '*' character, e.g.:
83421.172Sthorpej *
83431.172Sthorpej *	NetBSD-CORE@*
83441.172Sthorpej *
83451.172Sthorpej * finds the first note whose name prefix matches "NetBSD-CORE@".
83461.130Smgorny */
83471.130Smgornystatic ssize_t core_find_note(const char *core_path,
83481.130Smgorny    const char *note_name, uint64_t note_type, void *buf, size_t buf_len)
83491.130Smgorny{
83501.130Smgorny	int core_fd;
83511.130Smgorny	Elf *core_elf;
83521.130Smgorny	size_t core_numhdr, i;
83531.130Smgorny	ssize_t ret = -1;
83541.172Sthorpej	size_t name_len = strlen(note_name);
83551.172Sthorpej	bool prefix_match = false;
83561.172Sthorpej
83571.172Sthorpej	if (note_name[name_len - 1] == '*') {
83581.172Sthorpej		prefix_match = true;
83591.172Sthorpej		name_len--;
83601.172Sthorpej	} else {
83611.172Sthorpej		/* note: we assume note name will be null-terminated */
83621.172Sthorpej		name_len++;
83631.172Sthorpej	}
83641.130Smgorny
83651.130Smgorny	SYSCALL_REQUIRE((core_fd = open(core_path, O_RDONLY)) != -1);
83661.130Smgorny	SYSCALL_REQUIRE(elf_version(EV_CURRENT) != EV_NONE);
83671.130Smgorny	SYSCALL_REQUIRE((core_elf = elf_begin(core_fd, ELF_C_READ, NULL)));
83681.130Smgorny
83691.130Smgorny	SYSCALL_REQUIRE(elf_getphnum(core_elf, &core_numhdr) != 0);
83701.130Smgorny	for (i = 0; i < core_numhdr && ret == -1; i++) {
83711.130Smgorny		GElf_Phdr core_hdr;
83721.130Smgorny		size_t offset;
83731.130Smgorny		SYSCALL_REQUIRE(gelf_getphdr(core_elf, i, &core_hdr));
83741.130Smgorny		if (core_hdr.p_type != PT_NOTE)
83751.130Smgorny		    continue;
83761.130Smgorny
83771.130Smgorny		for (offset = core_hdr.p_offset;
83781.130Smgorny		    offset < core_hdr.p_offset + core_hdr.p_filesz;) {
83791.130Smgorny			Elf64_Nhdr note_hdr;
83801.130Smgorny			char name_buf[64];
83811.130Smgorny
83821.130Smgorny			switch (gelf_getclass(core_elf)) {
83831.130Smgorny			case ELFCLASS64:
83841.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &note_hdr,
83851.130Smgorny				    sizeof(note_hdr), offset)
83861.130Smgorny				    == sizeof(note_hdr));
83871.130Smgorny				offset += sizeof(note_hdr);
83881.130Smgorny				break;
83891.130Smgorny			case ELFCLASS32:
83901.130Smgorny				{
83911.130Smgorny				Elf32_Nhdr tmp_hdr;
83921.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &tmp_hdr,
83931.130Smgorny				    sizeof(tmp_hdr), offset)
83941.130Smgorny				    == sizeof(tmp_hdr));
83951.130Smgorny				offset += sizeof(tmp_hdr);
83961.130Smgorny				note_hdr.n_namesz = tmp_hdr.n_namesz;
83971.130Smgorny				note_hdr.n_descsz = tmp_hdr.n_descsz;
83981.130Smgorny				note_hdr.n_type = tmp_hdr.n_type;
83991.130Smgorny				}
84001.130Smgorny				break;
84011.130Smgorny			}
84021.130Smgorny
84031.130Smgorny			/* indicates end of notes */
84041.130Smgorny			if (note_hdr.n_namesz == 0 || note_hdr.n_descsz == 0)
84051.130Smgorny				break;
84061.172Sthorpej			if (((prefix_match &&
84071.172Sthorpej			      note_hdr.n_namesz > name_len) ||
84081.172Sthorpej			     (!prefix_match &&
84091.172Sthorpej			      note_hdr.n_namesz == name_len)) &&
84101.130Smgorny			    note_hdr.n_namesz <= sizeof(name_buf)) {
84111.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, name_buf,
84121.130Smgorny				    note_hdr.n_namesz, offset)
84131.131Skamil				    == (ssize_t)(size_t)note_hdr.n_namesz);
84141.130Smgorny
84151.130Smgorny				if (!strncmp(note_name, name_buf, name_len) &&
84161.130Smgorny				    note_hdr.n_type == note_type)
84171.130Smgorny					ret = note_hdr.n_descsz;
84181.130Smgorny			}
84191.130Smgorny
84201.130Smgorny			offset += note_hdr.n_namesz;
84211.130Smgorny			/* fix to alignment */
84221.146Smgorny			offset = roundup(offset, core_hdr.p_align);
84231.130Smgorny
84241.130Smgorny			/* if name & type matched above */
84251.130Smgorny			if (ret != -1) {
84261.130Smgorny				ssize_t read_len = MIN(buf_len,
84271.130Smgorny				    note_hdr.n_descsz);
84281.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, buf,
84291.130Smgorny				    read_len, offset) == read_len);
84301.130Smgorny				break;
84311.130Smgorny			}
84321.130Smgorny
84331.130Smgorny			offset += note_hdr.n_descsz;
84341.146Smgorny			/* fix to alignment */
84351.146Smgorny			offset = roundup(offset, core_hdr.p_align);
84361.130Smgorny		}
84371.130Smgorny	}
84381.130Smgorny
84391.130Smgorny	elf_end(core_elf);
84401.130Smgorny	close(core_fd);
84411.130Smgorny
84421.130Smgorny	return ret;
84431.130Smgorny}
84441.130Smgorny
84451.130SmgornyATF_TC(core_dump_procinfo);
84461.130SmgornyATF_TC_HEAD(core_dump_procinfo, tc)
84471.130Smgorny{
84481.130Smgorny	atf_tc_set_md_var(tc, "descr",
84491.130Smgorny		"Trigger a core dump and verify its contents.");
84501.130Smgorny}
84511.130Smgorny
84521.130SmgornyATF_TC_BODY(core_dump_procinfo, tc)
84531.130Smgorny{
84541.130Smgorny	const int exitval = 5;
84551.130Smgorny	pid_t child, wpid;
84561.130Smgorny#if defined(TWAIT_HAVE_STATUS)
84571.130Smgorny	const int sigval = SIGTRAP;
84581.130Smgorny	int status;
84591.130Smgorny#endif
84601.130Smgorny	char core_path[] = "/tmp/core.XXXXXX";
84611.130Smgorny	int core_fd;
84621.130Smgorny	struct netbsd_elfcore_procinfo procinfo;
84631.130Smgorny
84641.130Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
84651.130Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
84661.130Smgorny	if (child == 0) {
84671.130Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
84681.130Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
84691.130Smgorny
84701.130Smgorny		DPRINTF("Before triggering SIGTRAP\n");
84711.130Smgorny		trigger_trap();
84721.130Smgorny
84731.130Smgorny		DPRINTF("Before exiting of the child process\n");
84741.130Smgorny		_exit(exitval);
84751.130Smgorny	}
84761.130Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
84771.130Smgorny
84781.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
84791.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
84801.130Smgorny
84811.130Smgorny	validate_status_stopped(status, sigval);
84821.130Smgorny
84831.130Smgorny	SYSCALL_REQUIRE((core_fd = mkstemp(core_path)) != -1);
84841.130Smgorny	close(core_fd);
84851.130Smgorny
84861.130Smgorny	DPRINTF("Call DUMPCORE for the child process\n");
84871.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_DUMPCORE, child, core_path, strlen(core_path))
84881.130Smgorny	    != -1);
84891.130Smgorny
84901.130Smgorny	DPRINTF("Read core file\n");
84911.130Smgorny	ATF_REQUIRE_EQ(core_find_note(core_path, "NetBSD-CORE",
84921.130Smgorny	    ELF_NOTE_NETBSD_CORE_PROCINFO, &procinfo, sizeof(procinfo)),
84931.130Smgorny	    sizeof(procinfo));
84941.130Smgorny
84951.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_version, 1);
84961.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_cpisize, sizeof(procinfo));
84971.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_signo, SIGTRAP);
84981.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pid, child);
84991.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ppid, getpid());
85001.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pgrp, getpgid(child));
85011.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_sid, getsid(child));
85021.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ruid, getuid());
85031.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_euid, geteuid());
85041.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_rgid, getgid());
85051.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_egid, getegid());
85061.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_nlwps, 1);
85071.173Skamil	ATF_CHECK(procinfo.cpi_siglwp > 0);
85081.130Smgorny
85091.130Smgorny	unlink(core_path);
85101.130Smgorny
85111.130Smgorny	DPRINTF("Before resuming the child process where it left off and "
85121.130Smgorny	    "without signal to be sent\n");
85131.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
85141.130Smgorny
85151.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
85161.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
85171.130Smgorny
85181.130Smgorny	validate_status_exited(status, exitval);
85191.130Smgorny
85201.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
85211.130Smgorny	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
85221.130Smgorny}
85231.130Smgorny
85241.130Smgorny/// ----------------------------------------------------------------------------
85251.130Smgorny
85261.138Smgorny#if defined(TWAIT_HAVE_STATUS)
85271.138Smgorny
85281.160Smgorny#define THREAD_CONCURRENT_BREAKPOINT_NUM 50
85291.156Smgorny#define THREAD_CONCURRENT_SIGNALS_NUM 50
85301.161Smgorny#define THREAD_CONCURRENT_WATCHPOINT_NUM 50
85311.138Smgorny
85321.138Smgorny/* List of signals to use for the test */
85331.138Smgornyconst int thread_concurrent_signals_list[] = {
85341.138Smgorny	SIGIO,
85351.138Smgorny	SIGXCPU,
85361.138Smgorny	SIGXFSZ,
85371.138Smgorny	SIGVTALRM,
85381.138Smgorny	SIGPROF,
85391.138Smgorny	SIGWINCH,
85401.138Smgorny	SIGINFO,
85411.138Smgorny	SIGUSR1,
85421.138Smgorny	SIGUSR2
85431.138Smgorny};
85441.138Smgorny
85451.157Smgornyenum thread_concurrent_signal_handling {
85461.157Smgorny	/* the signal is discarded by debugger */
85471.157Smgorny	TCSH_DISCARD,
85481.157Smgorny	/* the handler is set to SIG_IGN */
85491.157Smgorny	TCSH_SIG_IGN,
85501.157Smgorny	/* an actual handler is used */
85511.157Smgorny	TCSH_HANDLER
85521.157Smgorny};
85531.157Smgorny
85541.156Smgornystatic pthread_barrier_t thread_concurrent_barrier;
85551.158Smgornystatic pthread_key_t thread_concurrent_key;
85561.161Smgornystatic uint32_t thread_concurrent_watchpoint_var = 0;
85571.138Smgorny
85581.160Smgornystatic void *
85591.160Smgornythread_concurrent_breakpoint_thread(void *arg)
85601.160Smgorny{
85611.160Smgorny	static volatile int watchme = 1;
85621.160Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
85631.160Smgorny	DPRINTF("Before entering breakpoint func from LWP %d\n", _lwp_self());
85641.160Smgorny	check_happy(watchme);
85651.160Smgorny	return NULL;
85661.160Smgorny}
85671.160Smgorny
85681.157Smgornystatic void
85691.157Smgornythread_concurrent_sig_handler(int sig)
85701.157Smgorny{
85711.158Smgorny	void *tls_val = pthread_getspecific(thread_concurrent_key);
85721.158Smgorny	DPRINTF("Before increment, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
85731.158Smgorny	FORKEE_ASSERT(pthread_setspecific(thread_concurrent_key,
85741.158Smgorny	    (void*)((uintptr_t)tls_val + 1)) == 0);
85751.157Smgorny}
85761.157Smgorny
85771.138Smgornystatic void *
85781.138Smgornythread_concurrent_signals_thread(void *arg)
85791.138Smgorny{
85801.138Smgorny	int sigval = thread_concurrent_signals_list[
85811.138Smgorny	    _lwp_self() % __arraycount(thread_concurrent_signals_list)];
85821.158Smgorny	enum thread_concurrent_signal_handling *signal_handle = arg;
85831.158Smgorny	void *tls_val;
85841.158Smgorny
85851.156Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
85861.138Smgorny	DPRINTF("Before raising %s from LWP %d\n", strsignal(sigval),
85871.138Smgorny		_lwp_self());
85881.138Smgorny	pthread_kill(pthread_self(), sigval);
85891.158Smgorny	if (*signal_handle == TCSH_HANDLER) {
85901.158Smgorny	    tls_val = pthread_getspecific(thread_concurrent_key);
85911.158Smgorny	    DPRINTF("After raising, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
85921.158Smgorny	    FORKEE_ASSERT(tls_val == (void*)1);
85931.158Smgorny	}
85941.138Smgorny	return NULL;
85951.138Smgorny}
85961.138Smgorny
85971.161Smgornystatic void *
85981.161Smgornythread_concurrent_watchpoint_thread(void *arg)
85991.161Smgorny{
86001.161Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
86011.161Smgorny	DPRINTF("Before modifying var from LWP %d\n", _lwp_self());
86021.161Smgorny	thread_concurrent_watchpoint_var = 1;
86031.161Smgorny	return NULL;
86041.161Smgorny}
86051.161Smgorny
86061.160Smgorny#if defined(__i386__) || defined(__x86_64__)
86071.160Smgornyenum thread_concurrent_sigtrap_event {
86081.160Smgorny	TCSE_UNKNOWN,
86091.161Smgorny	TCSE_BREAKPOINT,
86101.161Smgorny	TCSE_WATCHPOINT
86111.160Smgorny};
86121.160Smgorny
86131.160Smgornystatic void
86141.160Smgornythread_concurrent_lwp_setup(pid_t child, lwpid_t lwpid);
86151.160Smgornystatic enum thread_concurrent_sigtrap_event
86161.160Smgornythread_concurrent_handle_sigtrap(pid_t child, ptrace_siginfo_t *info);
86171.160Smgorny#endif
86181.160Smgorny
86191.156Smgornystatic void
86201.157Smgornythread_concurrent_test(enum thread_concurrent_signal_handling signal_handle,
86211.161Smgorny    int breakpoint_threads, int signal_threads, int watchpoint_threads)
86221.138Smgorny{
86231.138Smgorny	const int exitval = 5;
86241.138Smgorny	const int sigval = SIGSTOP;
86251.138Smgorny	pid_t child, wpid;
86261.138Smgorny	int status;
86271.141Skamil	struct lwp_event_count signal_counts[THREAD_CONCURRENT_SIGNALS_NUM]
86281.141Skamil	    = {{0, 0}};
86291.160Smgorny	struct lwp_event_count bp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
86301.160Smgorny	    = {{0, 0}};
86311.161Smgorny	struct lwp_event_count wp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
86321.161Smgorny	    = {{0, 0}};
86331.159Smgorny	ptrace_event_t event;
86341.156Smgorny	int i;
86351.156Smgorny
86361.164Skamil#if defined(HAVE_DBREGS)
86371.164Skamil	if (!can_we_set_dbregs()) {
86381.164Skamil		atf_tc_skip("Either run this test as root or set sysctl(3) "
86391.164Skamil		            "security.models.extensions.user_set_dbregs to 1");
86401.164Skamil        }
86411.164Skamil#endif
86421.164Skamil
86431.164Skamil	atf_tc_skip("PR kern/54960");
86441.157Smgorny
86451.156Smgorny	/* Protect against out-of-bounds array access. */
86461.160Smgorny	ATF_REQUIRE(breakpoint_threads <= THREAD_CONCURRENT_BREAKPOINT_NUM);
86471.156Smgorny	ATF_REQUIRE(signal_threads <= THREAD_CONCURRENT_SIGNALS_NUM);
86481.161Smgorny	ATF_REQUIRE(watchpoint_threads <= THREAD_CONCURRENT_WATCHPOINT_NUM);
86491.138Smgorny
86501.138Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
86511.138Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
86521.138Smgorny	if (child == 0) {
86531.160Smgorny		pthread_t bp_threads[THREAD_CONCURRENT_BREAKPOINT_NUM];
86541.156Smgorny		pthread_t sig_threads[THREAD_CONCURRENT_SIGNALS_NUM];
86551.161Smgorny		pthread_t wp_threads[THREAD_CONCURRENT_WATCHPOINT_NUM];
86561.138Smgorny
86571.138Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
86581.138Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
86591.138Smgorny
86601.138Smgorny		DPRINTF("Before raising %s from child\n", strsignal(sigval));
86611.138Smgorny		FORKEE_ASSERT(raise(sigval) == 0);
86621.138Smgorny
86631.157Smgorny		if (signal_handle != TCSH_DISCARD) {
86641.157Smgorny			struct sigaction sa;
86651.157Smgorny			unsigned int j;
86661.157Smgorny
86671.157Smgorny			memset(&sa, 0, sizeof(sa));
86681.157Smgorny			if (signal_handle == TCSH_SIG_IGN)
86691.157Smgorny				sa.sa_handler = SIG_IGN;
86701.157Smgorny			else
86711.157Smgorny				sa.sa_handler = thread_concurrent_sig_handler;
86721.157Smgorny			sigemptyset(&sa.sa_mask);
86731.157Smgorny
86741.157Smgorny			for (j = 0;
86751.157Smgorny			    j < __arraycount(thread_concurrent_signals_list);
86761.157Smgorny			    j++)
86771.157Smgorny				FORKEE_ASSERT(sigaction(
86781.157Smgorny				    thread_concurrent_signals_list[j], &sa, NULL)
86791.157Smgorny				    != -1);
86801.157Smgorny		}
86811.157Smgorny
86821.138Smgorny		DPRINTF("Before starting threads from the child\n");
86831.138Smgorny		FORKEE_ASSERT(pthread_barrier_init(
86841.156Smgorny		    &thread_concurrent_barrier, NULL,
86851.161Smgorny		    breakpoint_threads + signal_threads + watchpoint_threads)
86861.161Smgorny		    == 0);
86871.158Smgorny		FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL)
86881.158Smgorny		    == 0);
86891.138Smgorny
86901.156Smgorny		for (i = 0; i < signal_threads; i++) {
86911.156Smgorny			FORKEE_ASSERT(pthread_create(&sig_threads[i], NULL,
86921.158Smgorny			    thread_concurrent_signals_thread,
86931.158Smgorny			    &signal_handle) == 0);
86941.138Smgorny		}
86951.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
86961.160Smgorny			FORKEE_ASSERT(pthread_create(&bp_threads[i], NULL,
86971.160Smgorny			    thread_concurrent_breakpoint_thread, NULL) == 0);
86981.160Smgorny		}
86991.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
87001.161Smgorny			FORKEE_ASSERT(pthread_create(&wp_threads[i], NULL,
87011.161Smgorny			    thread_concurrent_watchpoint_thread, NULL) == 0);
87021.161Smgorny		}
87031.138Smgorny
87041.138Smgorny		DPRINTF("Before joining threads from the child\n");
87051.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
87061.161Smgorny			FORKEE_ASSERT(pthread_join(wp_threads[i], NULL) == 0);
87071.161Smgorny		}
87081.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
87091.160Smgorny			FORKEE_ASSERT(pthread_join(bp_threads[i], NULL) == 0);
87101.160Smgorny		}
87111.156Smgorny		for (i = 0; i < signal_threads; i++) {
87121.156Smgorny			FORKEE_ASSERT(pthread_join(sig_threads[i], NULL) == 0);
87131.138Smgorny		}
87141.138Smgorny
87151.158Smgorny		FORKEE_ASSERT(pthread_key_delete(thread_concurrent_key) == 0);
87161.138Smgorny		FORKEE_ASSERT(pthread_barrier_destroy(
87171.156Smgorny		    &thread_concurrent_barrier) == 0);
87181.138Smgorny
87191.138Smgorny		DPRINTF("Before exiting of the child process\n");
87201.138Smgorny		_exit(exitval);
87211.138Smgorny	}
87221.138Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
87231.138Smgorny
87241.138Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
87251.138Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
87261.138Smgorny
87271.138Smgorny	validate_status_stopped(status, sigval);
87281.138Smgorny
87291.159Smgorny	DPRINTF("Set LWP event mask for the child process\n");
87301.159Smgorny	memset(&event, 0, sizeof(event));
87311.159Smgorny	event.pe_set_event |= PTRACE_LWP_CREATE;
87321.159Smgorny	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, sizeof(event))
87331.159Smgorny	    != -1);
87341.159Smgorny
87351.138Smgorny	DPRINTF("Before resuming the child process where it left off\n");
87361.138Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
87371.138Smgorny
87381.138Smgorny	DPRINTF("Before entering signal collection loop\n");
87391.138Smgorny	while (1) {
87401.138Smgorny		ptrace_siginfo_t info;
87411.138Smgorny
87421.138Smgorny		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
87431.138Smgorny		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
87441.138Smgorny		    child);
87451.138Smgorny		if (WIFEXITED(status))
87461.138Smgorny			break;
87471.138Smgorny		/* Note: we use validate_status_stopped() to get nice error
87481.138Smgorny		 * message.  Signal is irrelevant since it won't be reached.
87491.138Smgorny		 */
87501.138Smgorny		else if (!WIFSTOPPED(status))
87511.138Smgorny			validate_status_stopped(status, 0);
87521.138Smgorny
87531.138Smgorny		DPRINTF("Before calling PT_GET_SIGINFO\n");
87541.138Smgorny		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
87551.138Smgorny		    sizeof(info)) != -1);
87561.138Smgorny
87571.138Smgorny		DPRINTF("Received signal %d from LWP %d (wait: %d)\n",
87581.138Smgorny		    info.psi_siginfo.si_signo, info.psi_lwpid,
87591.138Smgorny		    WSTOPSIG(status));
87601.138Smgorny
87611.159Smgorny		ATF_CHECK_EQ_MSG(info.psi_siginfo.si_signo, WSTOPSIG(status),
87621.159Smgorny		    "lwp=%d, WSTOPSIG=%d, psi_siginfo=%d", info.psi_lwpid,
87631.159Smgorny		    WSTOPSIG(status), info.psi_siginfo.si_signo);
87641.159Smgorny
87651.159Smgorny		if (WSTOPSIG(status) != SIGTRAP) {
87661.159Smgorny			int expected_sig =
87671.159Smgorny			    thread_concurrent_signals_list[info.psi_lwpid %
87681.159Smgorny			    __arraycount(thread_concurrent_signals_list)];
87691.159Smgorny			ATF_CHECK_EQ_MSG(WSTOPSIG(status), expected_sig,
87701.159Smgorny				"lwp=%d, expected %d, got %d", info.psi_lwpid,
87711.159Smgorny				expected_sig, WSTOPSIG(status));
87721.138Smgorny
87731.159Smgorny			*FIND_EVENT_COUNT(signal_counts, info.psi_lwpid) += 1;
87741.160Smgorny		} else if (info.psi_siginfo.si_code == TRAP_LWP) {
87751.160Smgorny#if defined(__i386__) || defined(__x86_64__)
87761.160Smgorny			thread_concurrent_lwp_setup(child, info.psi_lwpid);
87771.160Smgorny#endif
87781.159Smgorny		} else {
87791.160Smgorny#if defined(__i386__) || defined(__x86_64__)
87801.160Smgorny			switch (thread_concurrent_handle_sigtrap(child, &info)) {
87811.160Smgorny				case TCSE_UNKNOWN:
87821.160Smgorny					/* already reported inside the function */
87831.160Smgorny					break;
87841.160Smgorny				case TCSE_BREAKPOINT:
87851.160Smgorny					*FIND_EVENT_COUNT(bp_counts,
87861.160Smgorny					    info.psi_lwpid) += 1;
87871.160Smgorny					break;
87881.161Smgorny				case TCSE_WATCHPOINT:
87891.161Smgorny					*FIND_EVENT_COUNT(wp_counts,
87901.161Smgorny					    info.psi_lwpid) += 1;
87911.161Smgorny					break;
87921.160Smgorny			}
87931.160Smgorny#else
87941.160Smgorny			ATF_CHECK_MSG(0, "Unexpected SIGTRAP, si_code=%d\n",
87951.160Smgorny			    info.psi_siginfo.si_code);
87961.160Smgorny#endif
87971.159Smgorny		}
87981.138Smgorny
87991.138Smgorny		DPRINTF("Before resuming the child process\n");
88001.157Smgorny		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
88011.159Smgorny		     signal_handle != TCSH_DISCARD && WSTOPSIG(status) != SIGTRAP
88021.159Smgorny		     ? WSTOPSIG(status) : 0) != -1);
88031.138Smgorny	}
88041.138Smgorny
88051.156Smgorny	for (i = 0; i < signal_threads; i++)
88061.141Skamil		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 1,
88071.141Skamil		    "signal_counts[%d].lec_count=%d; lec_lwp=%d",
88081.141Skamil		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
88091.156Smgorny	for (i = signal_threads; i < THREAD_CONCURRENT_SIGNALS_NUM; i++)
88101.156Smgorny		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 0,
88111.156Smgorny		    "extraneous signal_counts[%d].lec_count=%d; lec_lwp=%d",
88121.156Smgorny		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
88131.138Smgorny
88141.160Smgorny	for (i = 0; i < breakpoint_threads; i++)
88151.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 1,
88161.160Smgorny		    "bp_counts[%d].lec_count=%d; lec_lwp=%d",
88171.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
88181.160Smgorny	for (i = breakpoint_threads; i < THREAD_CONCURRENT_BREAKPOINT_NUM; i++)
88191.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 0,
88201.160Smgorny		    "extraneous bp_counts[%d].lec_count=%d; lec_lwp=%d",
88211.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
88221.160Smgorny
88231.161Smgorny	for (i = 0; i < watchpoint_threads; i++)
88241.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 1,
88251.161Smgorny		    "wp_counts[%d].lec_count=%d; lec_lwp=%d",
88261.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
88271.161Smgorny	for (i = watchpoint_threads; i < THREAD_CONCURRENT_WATCHPOINT_NUM; i++)
88281.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 0,
88291.161Smgorny		    "extraneous wp_counts[%d].lec_count=%d; lec_lwp=%d",
88301.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
88311.161Smgorny
88321.138Smgorny	validate_status_exited(status, exitval);
88331.138Smgorny}
88341.138Smgorny
88351.161Smgorny#define THREAD_CONCURRENT_TEST(test, sig_hdl, bps, sigs, wps, descr)	\
88361.156SmgornyATF_TC(test);								\
88371.156SmgornyATF_TC_HEAD(test, tc)							\
88381.156Smgorny{									\
88391.156Smgorny	atf_tc_set_md_var(tc, "descr", descr);				\
88401.156Smgorny}									\
88411.156Smgorny									\
88421.156SmgornyATF_TC_BODY(test, tc)							\
88431.156Smgorny{									\
88441.161Smgorny	thread_concurrent_test(sig_hdl, bps, sigs, wps);		\
88451.156Smgorny}
88461.156Smgorny
88471.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals, TCSH_DISCARD,
88481.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
88491.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
88501.157Smgorny    "correctly");
88511.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_sig_ign, TCSH_SIG_IGN,
88521.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
88531.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
88541.157Smgorny    "correctly and passed back to SIG_IGN handler");
88551.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_handler, TCSH_HANDLER,
88561.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
88571.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
88581.157Smgorny    "correctly and passed back to a handler function");
88591.156Smgorny
88601.163Skamil#if defined(__i386__) || defined(__x86_64__)
88611.160SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_breakpoints, TCSH_DISCARD,
88621.161Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, 0,
88631.161Smgorny    "Verify that concurrent breakpoints are reported correctly");
88641.161SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_watchpoints, TCSH_DISCARD,
88651.161Smgorny    0, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
88661.160Smgorny    "Verify that concurrent breakpoints are reported correctly");
88671.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp, TCSH_DISCARD,
88681.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
88691.162Smgorny    "Verify that concurrent breakpoints and watchpoints are reported "
88701.162Smgorny    "correctly");
88711.162Smgorny
88721.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig, TCSH_DISCARD,
88731.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
88741.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly");
88751.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_sig_ign, TCSH_SIG_IGN,
88761.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
88771.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
88781.162Smgorny    "and passed back to SIG_IGN handler");
88791.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_handler, TCSH_HANDLER,
88801.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
88811.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
88821.162Smgorny    "and passed back to a handler function");
88831.162Smgorny
88841.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig, TCSH_DISCARD,
88851.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
88861.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly");
88871.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_sig_ign, TCSH_SIG_IGN,
88881.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
88891.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
88901.162Smgorny    "and passed back to SIG_IGN handler");
88911.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_handler, TCSH_HANDLER,
88921.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
88931.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
88941.162Smgorny    "and passed back to a handler function");
88951.162Smgorny
88961.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig, TCSH_DISCARD,
88971.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
88981.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
88991.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
89001.162Smgorny    "correctly");
89011.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_sig_ign, TCSH_SIG_IGN,
89021.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
89031.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
89041.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
89051.162Smgorny    "correctly and passed back to SIG_IGN handler");
89061.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_handler, TCSH_HANDLER,
89071.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
89081.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
89091.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
89101.162Smgorny    "correctly and passed back to a handler function");
89111.163Skamil#endif
89121.160Smgorny
89131.138Smgorny#endif /*defined(TWAIT_HAVE_STATUS)*/
89141.138Smgorny
89151.138Smgorny/// ----------------------------------------------------------------------------
89161.138Smgorny
89171.174Skamil#include "t_ptrace_register_wait.h"
89181.174Skamil
89191.174Skamil/// ----------------------------------------------------------------------------
89201.174Skamil
89211.1Skamil#include "t_ptrace_amd64_wait.h"
89221.1Skamil#include "t_ptrace_i386_wait.h"
89231.1Skamil#include "t_ptrace_x86_wait.h"
89241.1Skamil
89251.165Skamil/// ----------------------------------------------------------------------------
89261.165Skamil
89271.165Skamil#else
89281.165SkamilATF_TC(dummy);
89291.165SkamilATF_TC_HEAD(dummy, tc)
89301.165Skamil{
89311.165Skamil	atf_tc_set_md_var(tc, "descr", "A dummy test");
89321.165Skamil}
89331.165Skamil
89341.165SkamilATF_TC_BODY(dummy, tc)
89351.165Skamil{
89361.165Skamil
89371.165Skamil	// Dummy, skipped
89381.165Skamil	// The ATF framework requires at least a single defined test.
89391.165Skamil}
89401.165Skamil#endif
89411.165Skamil
89421.1SkamilATF_TP_ADD_TCS(tp)
89431.1Skamil{
89441.1Skamil	setvbuf(stdout, NULL, _IONBF, 0);
89451.1Skamil	setvbuf(stderr, NULL, _IONBF, 0);
89461.33Skamil
89471.165Skamil#ifdef ENABLE_TESTS
89481.36Skamil	ATF_TP_ADD_TC(tp, traceme_raise1);
89491.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise2);
89501.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise3);
89511.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise4);
89521.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise5);
89531.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise6);
89541.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise7);
89551.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise8);
89561.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise9);
89571.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise10);
89581.33Skamil
89591.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored1);
89601.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored2);
89611.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored3);
89621.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored4);
89631.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored5);
89641.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored6);
89651.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored7);
89661.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored8);
89671.87Skamil
89681.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked1);
89691.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked2);
89701.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked3);
89711.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked4);
89721.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked5);
89731.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked6);
89741.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked7);
89751.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked8);
89761.86Skamil
89771.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_trap);
89781.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_segv);
89791.71Skamil	ATF_TP_ADD_TC(tp, traceme_crash_ill);
89801.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_fpe);
89811.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_bus);
89821.59Skamil
89831.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_trap);
89841.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_segv);
89851.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_ill);
89861.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_fpe);
89871.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_bus);
89881.88Skamil
89891.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_trap);
89901.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_segv);
89911.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_ill);
89921.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_fpe);
89931.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_bus);
89941.88Skamil
89951.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle1);
89961.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle2);
89971.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle3);
89981.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle4);
89991.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle5);
90001.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle6);
90011.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle7);
90021.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle8);
90031.50Skamil
90041.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked1);
90051.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked2);
90061.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked3);
90071.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked4);
90081.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked5);
90091.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked6);
90101.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked7);
90111.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked8);
90121.50Skamil
90131.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored1);
90141.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored2);
90151.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored3);
90161.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored4);
90171.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored5);
90181.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored6);
90191.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored7);
90201.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored8);
90211.50Skamil
90221.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple1);
90231.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple2);
90241.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple3);
90251.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple4);
90261.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple5);
90271.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple6);
90281.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple7);
90291.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple8);
90301.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple9);
90311.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple10);
90321.1Skamil
90331.37Skamil	ATF_TP_ADD_TC(tp, traceme_pid1_parent);
90341.37Skamil
90351.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise1);
90361.46Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise2);
90371.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise3);
90381.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise4);
90391.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise5);
90401.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise6);
90411.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise7);
90421.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise8);
90431.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise9);
90441.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise10);
90451.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise11);
90461.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise12);
90471.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise13);
90481.40Skamil
90491.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_trap);
90501.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_segv);
90511.71Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_ill);
90521.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_fpe);
90531.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_bus);
90541.41Skamil
90551.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_trap);
90561.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_segv);
90571.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_ill);
90581.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_fpe);
90591.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_bus);
90601.92Skamil
90611.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_trap);
90621.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_segv);
90631.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_ill);
90641.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_fpe);
90651.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_bus);
90661.92Skamil
90671.43Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_exec);
90681.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_exec);
90691.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_exec);
90701.43Skamil
90711.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_trap);
90721.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_segv);
90731.71Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_ill);
90741.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_fpe);
90751.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_bus);
90761.59Skamil
90771.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
90781.94Skamil	    unrelated_tracer_sees_signalmasked_crash_trap);
90791.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
90801.94Skamil	    unrelated_tracer_sees_signalmasked_crash_segv);
90811.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
90821.94Skamil	    unrelated_tracer_sees_signalmasked_crash_ill);
90831.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
90841.94Skamil	    unrelated_tracer_sees_signalmasked_crash_fpe);
90851.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
90861.94Skamil	    unrelated_tracer_sees_signalmasked_crash_bus);
90871.94Skamil
90881.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
90891.94Skamil	    unrelated_tracer_sees_signalignored_crash_trap);
90901.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
90911.94Skamil	    unrelated_tracer_sees_signalignored_crash_segv);
90921.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
90931.94Skamil	    unrelated_tracer_sees_signalignored_crash_ill);
90941.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
90951.94Skamil	    unrelated_tracer_sees_signalignored_crash_fpe);
90961.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
90971.94Skamil	    unrelated_tracer_sees_signalignored_crash_bus);
90981.94Skamil
90991.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sees_terminaton_before_the_parent);
91001.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sysctl_lookup_without_duplicates);
91011.61Skre	ATF_TP_ADD_TC_HAVE_PID(tp,
91021.61Skre		unrelated_tracer_sees_terminaton_before_the_parent);
91031.67Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_attach_to_unrelated_stopped_process);
91041.51Skamil
91051.51Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_child);
91061.66Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_stopped_child);
91071.51Skamil
91081.51Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_parent);
91091.65Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_stopped_parent);
91101.51Skamil
91111.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
91121.51Skamil		tracee_sees_its_original_parent_getppid);
91131.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
91141.51Skamil		tracee_sees_its_original_parent_sysctl_kinfo_proc2);
91151.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
91161.51Skamil		tracee_sees_its_original_parent_procfs_status);
91171.1Skamil
91181.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_empty);
91191.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_fork);
91201.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork);
91211.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork_done);
91221.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_create);
91231.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_exit);
91241.125Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_posix_spawn);
91251.1Skamil
91261.31Skamil	ATF_TP_ADD_TC(tp, fork1);
91271.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork2);
91281.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork3);
91291.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork4);
91301.31Skamil	ATF_TP_ADD_TC(tp, fork5);
91311.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork6);
91321.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork7);
91331.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork8);
91341.125Skamil	ATF_TP_ADD_TC(tp, fork9);
91351.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork10);
91361.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork11);
91371.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork12);
91381.125Skamil	ATF_TP_ADD_TC(tp, fork13);
91391.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork14);
91401.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork15);
91411.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork16);
91421.31Skamil
91431.31Skamil	ATF_TP_ADD_TC(tp, vfork1);
91441.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork2);
91451.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork3);
91461.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork4);
91471.31Skamil	ATF_TP_ADD_TC(tp, vfork5);
91481.31Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork6);
91491.104Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork7);
91501.104Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork8);
91511.125Skamil	ATF_TP_ADD_TC(tp, vfork9);
91521.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork10);
91531.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork11);
91541.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork12);
91551.125Skamil	ATF_TP_ADD_TC(tp, vfork13);
91561.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork14);
91571.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork15);
91581.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork16);
91591.1Skamil
91601.124Skamil	ATF_TP_ADD_TC(tp, posix_spawn1);
91611.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn2);
91621.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn3);
91631.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn4);
91641.124Skamil	ATF_TP_ADD_TC(tp, posix_spawn5);
91651.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn6);
91661.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn7);
91671.125Skamil	ATF_TP_ADD_TC(tp, posix_spawn8);
91681.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn9);
91691.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn10);
91701.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn11);
91711.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn12);
91721.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn13);
91731.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn14);
91741.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn15);
91751.125Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn16);
91761.124Skamil
91771.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork1);
91781.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork2);
91791.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork3);
91801.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork4);
91811.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork5);
91821.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork6);
91831.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork7);
91841.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork8);
91851.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork9);
91861.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork10);
91871.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork11);
91881.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork12);
91891.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork13);
91901.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork14);
91911.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork15);
91921.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork16);
91931.149Skamil
91941.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork1);
91951.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork2);
91961.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork3);
91971.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork4);
91981.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork5);
91991.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork6);
92001.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork7);
92011.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork8);
92021.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork9);
92031.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork10);
92041.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork11);
92051.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork12);
92061.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork13);
92071.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork14);
92081.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork15);
92091.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork16);
92101.149Skamil
92111.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn1);
92121.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn2);
92131.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn3);
92141.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn4);
92151.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn5);
92161.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn6);
92171.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn7);
92181.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn8);
92191.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn9);
92201.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn10);
92211.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn11);
92221.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn12);
92231.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn13);
92241.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn14);
92251.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn15);
92261.149Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn16);
92271.149Skamil
92281.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_detach_spawner);
92291.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_detach_forker);
92301.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_detach_vforker);
92311.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_detach_vforkerdone);
92321.126Skamil
92331.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_kill_spawner);
92341.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_kill_forker);
92351.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_kill_vforker);
92361.116Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_kill_vforkerdone);
92371.116Skamil
92381.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn_detach_spawner);
92391.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork_detach_forker);
92401.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork_detach_vforker);
92411.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork_detach_vforkerdone);
92421.150Skamil
92431.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_posix_spawn_kill_spawner);
92441.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_fork_kill_forker);
92451.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork_kill_vforker);
92461.150Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_vfork_kill_vforkerdone);
92471.150Skamil
92481.108Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_fork);
92491.108Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_vfork);
92501.108Skamil
92511.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8);
92521.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16);
92531.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32);
92541.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64);
92551.54Skamil
92561.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8);
92571.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16);
92581.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32);
92591.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64);
92601.54Skamil
92611.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8);
92621.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16);
92631.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32);
92641.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64);
92651.54Skamil
92661.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8);
92671.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16);
92681.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32);
92691.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64);
92701.54Skamil
92711.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d);
92721.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i);
92731.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d);
92741.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i);
92751.54Skamil
92761.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8_text);
92771.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16_text);
92781.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32_text);
92791.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64_text);
92801.54Skamil
92811.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8_text);
92821.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16_text);
92831.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32_text);
92841.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64_text);
92851.54Skamil
92861.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8_text);
92871.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16_text);
92881.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32_text);
92891.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64_text);
92901.54Skamil
92911.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8_text);
92921.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16_text);
92931.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32_text);
92941.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64_text);
92951.54Skamil
92961.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d_text);
92971.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i_text);
92981.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d_text);
92991.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i_text);
93001.1Skamil
93011.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_auxv);
93021.1Skamil
93031.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_i);
93041.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_d);
93051.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_i);
93061.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_d);
93071.101Skamil
93081.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_i);
93091.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_d);
93101.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_i);
93111.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_d);
93121.101Skamil
93131.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_auxv);
93141.101Skamil
93151.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_i);
93161.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_d);
93171.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_i);
93181.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_d);
93191.115Skamil
93201.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_i);
93211.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_d);
93221.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_i);
93231.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_d);
93241.115Skamil
93251.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step1);
93261.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step2);
93271.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step3);
93281.1Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step4);
93291.1Skamil
93301.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep1);
93311.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep2);
93321.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep3);
93331.2Skamil	ATF_TP_ADD_TC_PT_STEP(tp, setstep4);
93341.2Skamil
93351.95Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step_signalmasked);
93361.95Skamil	ATF_TP_ADD_TC_PT_STEP(tp, step_signalignored);
93371.95Skamil
93381.1Skamil	ATF_TP_ADD_TC(tp, kill1);
93391.1Skamil	ATF_TP_ADD_TC(tp, kill2);
93401.75Skamil	ATF_TP_ADD_TC(tp, kill3);
93411.1Skamil
93421.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0);
93431.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1);
93441.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2);
93451.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3);
93461.77Skamil
93471.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus);
93481.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus);
93491.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus);
93501.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus);
93511.143Skamil
93521.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_sigmask);
93531.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_sigmask);
93541.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_sigmask);
93551.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_sigmask);
93561.143Skamil
93571.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_name);
93581.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_name);
93591.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_name);
93601.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_name);
93611.143Skamil
93621.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_private);
93631.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_private);
93641.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_private);
93651.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_private);
93661.143Skamil
93671.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0);
93681.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1);
93691.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2);
93701.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3);
93711.143Skamil
93721.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_sigmask);
93731.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_sigmask);
93741.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_sigmask);
93751.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_sigmask);
93761.143Skamil
93771.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_name);
93781.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_name);
93791.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_name);
93801.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_name);
93811.143Skamil
93821.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_private);
93831.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_private);
93841.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_private);
93851.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_private);
93861.143Skamil
93871.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo0);
93881.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo1);
93891.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo2);
93901.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo3);
93911.1Skamil
93921.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_unmodified);
93931.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_faked);
93941.79Skamil
93951.82Skamil	ATF_TP_ADD_TC(tp, traceme_exec);
93961.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_exec);
93971.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_exec);
93981.1Skamil
93991.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_nolwpevents);
94001.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit);
94011.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate);
94021.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit);
94031.1Skamil
94041.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit_masked_sigtrap);
94051.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_masked_sigtrap);
94061.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit_masked_sigtrap);
94071.153Skamil
94081.84Skamil	ATF_TP_ADD_TC(tp, signal_mask_unrelated);
94091.84Skamil
94101.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_singalmasked);
94111.126Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, posix_spawn_singalignored);
94121.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_singalmasked);
94131.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, fork_singalignored);
94141.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_singalmasked);
94151.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vfork_singalignored);
94161.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vforkdone_singalmasked);
94171.99Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, vforkdone_singalignored);
94181.99Skamil
94191.151Skamil	ATF_TP_ADD_TC(tp, threads_and_exec);
94201.151Skamil
94211.154Skamil	ATF_TP_ADD_TC(tp, suspend_no_deadlock);
94221.1Skamil
94231.155Skamil	ATF_TP_ADD_TC(tp, resume);
94241.1Skamil
94251.166Skamil	ATF_TP_ADD_TC(tp, syscall);
94261.166Skamil	ATF_TP_ADD_TC(tp, syscall_killed_on_sce);
94271.167Skamil	ATF_TP_ADD_TC(tp, syscall_signal_on_sce);
94281.167Skamil	ATF_TP_ADD_TC(tp, syscall_detach_on_sce);
94291.1Skamil
94301.1Skamil	ATF_TP_ADD_TC(tp, syscallemu1);
94311.1Skamil
94321.106Skamil	ATF_TP_ADD_TC(tp, clone1);
94331.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone2);
94341.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone3);
94351.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone4);
94361.106Skamil	ATF_TP_ADD_TC(tp, clone5);
94371.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone6);
94381.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone7);
94391.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone8);
94401.106Skamil
94411.106Skamil	ATF_TP_ADD_TC(tp, clone_vm1);
94421.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm2);
94431.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm3);
94441.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm4);
94451.106Skamil	ATF_TP_ADD_TC(tp, clone_vm5);
94461.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm6);
94471.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm7);
94481.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm8);
94491.106Skamil
94501.106Skamil	ATF_TP_ADD_TC(tp, clone_fs1);
94511.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs2);
94521.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs3);
94531.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs4);
94541.106Skamil	ATF_TP_ADD_TC(tp, clone_fs5);
94551.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs6);
94561.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs7);
94571.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs8);
94581.106Skamil
94591.106Skamil	ATF_TP_ADD_TC(tp, clone_files1);
94601.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files2);
94611.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files3);
94621.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files4);
94631.106Skamil	ATF_TP_ADD_TC(tp, clone_files5);
94641.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files6);
94651.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files7);
94661.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files8);
94671.106Skamil
94681.106Skamil//	ATF_TP_ADD_TC(tp, clone_sighand1); // XXX
94691.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand2); // XXX
94701.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand3); // XXX
94711.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand4); // XXX
94721.106Skamil//	ATF_TP_ADD_TC(tp, clone_sighand5); // XXX
94731.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand6); // XXX
94741.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand7); // XXX
94751.106Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand8); // XXX
94761.106Skamil
94771.106Skamil	ATF_TP_ADD_TC(tp, clone_vfork1);
94781.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork2);
94791.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork3);
94801.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork4);
94811.106Skamil	ATF_TP_ADD_TC(tp, clone_vfork5);
94821.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork6);
94831.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork7);
94841.106Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork8);
94851.106Skamil
94861.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_signalignored);
94871.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_signalmasked);
94881.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm_signalignored);
94891.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vm_signalmasked);
94901.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs_signalignored);
94911.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_fs_signalmasked);
94921.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files_signalignored);
94931.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_files_signalmasked);
94941.103Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand_signalignored); // XXX
94951.103Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, clone_sighand_signalmasked); // XXX
94961.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork_signalignored);
94971.103Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, clone_vfork_signalmasked);
94981.103Skamil
94991.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone);
95001.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_vm);
95011.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_fs);
95021.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_files);
95031.107Skamil//	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_sighand); // XXX
95041.107Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, traceme_vfork_clone_vfork);
95051.107Skamil
95061.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_continue);
95071.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall);
95081.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach);
95091.122Skamil
95101.130Smgorny	ATF_TP_ADD_TC(tp, core_dump_procinfo);
95111.130Smgorny
95121.138Smgorny#if defined(TWAIT_HAVE_STATUS)
95131.138Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals);
95141.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_sig_ign);
95151.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_handler);
95161.160Smgorny#if defined(__i386__) || defined(__x86_64__)
95171.160Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_breakpoints);
95181.161Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_watchpoints);
95191.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp);
95201.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig);
95211.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_sig_ign);
95221.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_handler);
95231.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig);
95241.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_sig_ign);
95251.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_handler);
95261.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig);
95271.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_sig_ign);
95281.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_handler);
95291.160Smgorny#endif
95301.138Smgorny#endif
95311.138Smgorny
95321.174Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_REGISTER();
95331.174Skamil
95341.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
95351.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_I386();
95361.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_X86();
95371.1Skamil
95381.165Skamil#else
95391.165Skamil	ATF_TP_ADD_TC(tp, dummy);
95401.165Skamil#endif
95411.165Skamil
95421.1Skamil	return atf_no_error();
95431.1Skamil}
9544