t_ptrace_wait.c revision 1.180
11.180Skamil/*	$NetBSD: t_ptrace_wait.c,v 1.180 2020/05/04 22:34:22 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.180Skamil__RCSID("$NetBSD: t_ptrace_wait.c,v 1.180 2020/05/04 22:34:22 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.180Skamilstatic int lwpinfo_thread_sigmask[] = {SIGXCPU, SIGPIPE, SIGALRM, SIGURG};
30021.180Skamil
30031.180Skamilstatic pthread_mutex_t lwpinfo_thread_mtx = PTHREAD_MUTEX_INITIALIZER;
30041.180Skamilstatic pthread_cond_t lwpinfo_thread_cnd = PTHREAD_COND_INITIALIZER;
30051.180Skamilstatic volatile size_t lwpinfo_thread_done;
30061.180Skamil
30071.180Skamilstatic void *
30081.180Skamillwpinfo_thread(void *arg)
30091.180Skamil{
30101.180Skamil	sigset_t s;
30111.180Skamil	volatile void **tcb;
30121.180Skamil
30131.180Skamil	tcb = (volatile void **)arg;
30141.180Skamil
30151.180Skamil	*tcb = _lwp_getprivate();
30161.180Skamil	DPRINTF("Storing tcb[] = %p from thread %d\n", *tcb, _lwp_self());
30171.180Skamil
30181.180Skamil	pthread_setname_np(pthread_self(), "thread %d",
30191.180Skamil	    (void *)(intptr_t)_lwp_self());
30201.180Skamil
30211.180Skamil	sigemptyset(&s);
30221.180Skamil	pthread_mutex_lock(&lwpinfo_thread_mtx);
30231.180Skamil	sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
30241.180Skamil	lwpinfo_thread_done++;
30251.180Skamil	pthread_sigmask(SIG_BLOCK, &s, NULL);
30261.180Skamil	pthread_cond_signal(&lwpinfo_thread_cnd);
30271.180Skamil	pthread_mutex_unlock(&lwpinfo_thread_mtx);
30281.180Skamil
30291.180Skamil	return infinite_thread(NULL);
30301.180Skamil}
30311.180Skamil
30321.28Skamilstatic void
30331.180Skamiltraceme_lwpinfo(const size_t threads, const char *iter)
30341.1Skamil{
30351.1Skamil	const int sigval = SIGSTOP;
30361.180Skamil	const int sigval2 = SIGINT;
30371.180Skamil	pid_t child, wpid;
30381.1Skamil#if defined(TWAIT_HAVE_STATUS)
30391.1Skamil	int status;
30401.1Skamil#endif
30411.180Skamil	struct ptrace_lwpinfo lwp = {0, 0};
30421.180Skamil	struct ptrace_lwpstatus lwpstatus = {0};
30431.180Skamil	struct ptrace_siginfo info;
30441.180Skamil	void *private;
30451.180Skamil	char *name;
30461.180Skamil	char namebuf[PL_LNAMELEN];
30471.180Skamil	volatile void *tcb[4];
30481.180Skamil	bool found;
30491.180Skamil	sigset_t s;
30501.180Skamil
30511.180Skamil	/* Maximum number of supported threads in this test */
30521.180Skamil	pthread_t t[__arraycount(tcb) - 1];
30531.180Skamil	size_t n, m;
30541.180Skamil	int rv;
30551.180Skamil	size_t bytes_read;
30561.180Skamil
30571.180Skamil	struct ptrace_io_desc io;
30581.180Skamil	sigset_t sigmask;
30591.1Skamil
30601.180Skamil	ATF_REQUIRE(__arraycount(t) >= threads);
30611.180Skamil	memset(tcb, 0, sizeof(tcb));
30621.124Skamil
30631.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
30641.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
30651.1Skamil	if (child == 0) {
30661.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
30671.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
30681.1Skamil
30691.180Skamil		tcb[0] = _lwp_getprivate();
30701.180Skamil		DPRINTF("Storing tcb[0] = %p\n", tcb[0]);
30711.180Skamil
30721.180Skamil		pthread_setname_np(pthread_self(), "thread %d",
30731.180Skamil		    (void *)(intptr_t)_lwp_self());
30741.180Skamil
30751.180Skamil		sigemptyset(&s);
30761.180Skamil		sigaddset(&s, lwpinfo_thread_sigmask[lwpinfo_thread_done]);
30771.180Skamil		pthread_sigmask(SIG_BLOCK, &s, NULL);
30781.180Skamil
30791.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
30801.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
30811.1Skamil
30821.180Skamil		for (n = 0; n < threads; n++) {
30831.180Skamil			rv = pthread_create(&t[n], NULL, lwpinfo_thread,
30841.180Skamil			    &tcb[n + 1]);
30851.180Skamil			FORKEE_ASSERT(rv == 0);
30861.180Skamil		}
30871.1Skamil
30881.180Skamil		pthread_mutex_lock(&lwpinfo_thread_mtx);
30891.180Skamil		while (lwpinfo_thread_done < threads) {
30901.180Skamil			pthread_cond_wait(&lwpinfo_thread_cnd,
30911.180Skamil			    &lwpinfo_thread_mtx);
30921.124Skamil		}
30931.180Skamil		pthread_mutex_unlock(&lwpinfo_thread_mtx);
30941.1Skamil
30951.180Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval2));
30961.180Skamil		FORKEE_ASSERT(raise(sigval2) == 0);
30971.1Skamil
30981.180Skamil		/* NOTREACHED */
30991.180Skamil		FORKEE_ASSERTX(0 && "Not reached");
31001.1Skamil	}
31011.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
31021.1Skamil
31031.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
31041.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
31051.1Skamil
31061.1Skamil	validate_status_stopped(status, sigval);
31071.1Skamil
31081.180Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
31091.180Skamil	SYSCALL_REQUIRE(
31101.180Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
31111.1Skamil
31121.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
31131.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
31141.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
31151.180Skamil	    info.psi_siginfo.si_errno);
31161.1Skamil
31171.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
31181.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
31191.1Skamil
31201.180Skamil	if (strstr(iter, "LWPINFO") != NULL) {
31211.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
31221.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
31231.180Skamil		    != -1);
31241.1Skamil
31251.180Skamil		DPRINTF("Assert that there exists a single thread only\n");
31261.180Skamil		ATF_REQUIRE(lwp.pl_lwpid > 0);
31271.1Skamil
31281.180Skamil		DPRINTF("Assert that lwp thread %d received event "
31291.180Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
31301.180Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
31311.1Skamil
31321.180Skamil		if (strstr(iter, "LWPSTATUS") != NULL) {
31331.180Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPSTATUS "
31341.180Skamil			    "for child\n");
31351.180Skamil			lwpstatus.pl_lwpid = lwp.pl_lwpid;
31361.180Skamil			SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child, &lwpstatus,
31371.180Skamil			    sizeof(lwpstatus)) != -1);
31381.30Skamil		}
31391.30Skamil
31401.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
31411.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
31421.180Skamil		    != -1);
31431.29Skamil
31441.180Skamil		DPRINTF("Assert that there exists a single thread only\n");
31451.180Skamil		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
31461.180Skamil	} else {
31471.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
31481.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
31491.180Skamil		    sizeof(lwpstatus)) != -1);
31501.29Skamil
31511.180Skamil		DPRINTF("Assert that there exists a single thread only %d\n", lwpstatus.pl_lwpid);
31521.180Skamil		ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
31531.30Skamil
31541.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
31551.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
31561.180Skamil		    sizeof(lwpstatus)) != -1);
31571.30Skamil
31581.180Skamil		DPRINTF("Assert that there exists a single thread only\n");
31591.180Skamil		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
31601.30Skamil	}
31611.29Skamil
31621.13Schristos	DPRINTF("Before resuming the child process where it left off and "
31631.1Skamil	    "without signal to be sent\n");
31641.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
31651.1Skamil
31661.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
31671.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
31681.1Skamil
31691.180Skamil	validate_status_stopped(status, sigval2);
31701.180Skamil
31711.180Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child");
31721.180Skamil	SYSCALL_REQUIRE(
31731.180Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
31741.180Skamil
31751.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
31761.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
31771.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
31781.180Skamil	    info.psi_siginfo.si_errno);
31791.1Skamil
31801.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval2);
31811.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
31821.28Skamil
31831.180Skamil	memset(&lwp, 0, sizeof(lwp));
31841.180Skamil	memset(&lwpstatus, 0, sizeof(lwpstatus));
31851.32Skamil
31861.180Skamil	memset(&io, 0, sizeof(io));
31871.1Skamil
31881.180Skamil	bytes_read = 0;
31891.180Skamil	io.piod_op = PIOD_READ_D;
31901.180Skamil	io.piod_len = sizeof(tcb);
31911.125Skamil
31921.180Skamil	do {
31931.180Skamil		io.piod_addr = (char *)&tcb + bytes_read;
31941.180Skamil		io.piod_offs = io.piod_addr;
31951.124Skamil
31961.180Skamil		rv = ptrace(PT_IO, child, &io, sizeof(io));
31971.180Skamil		ATF_REQUIRE(rv != -1 && io.piod_len != 0);
31981.31Skamil
31991.180Skamil		bytes_read += io.piod_len;
32001.180Skamil		io.piod_len = sizeof(tcb) - bytes_read;
32011.180Skamil	} while (bytes_read < sizeof(tcb));
32021.149Skamil
32031.180Skamil	for (n = 0; n <= threads; n++) {
32041.180Skamil		if (strstr(iter, "LWPINFO") != NULL) {
32051.180Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
32061.180Skamil			    "child\n");
32071.180Skamil			SYSCALL_REQUIRE(
32081.180Skamil			    ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp)) != -1);
32091.180Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
32101.149Skamil
32111.180Skamil			DPRINTF("Assert that the thread exists\n");
32121.180Skamil			ATF_REQUIRE(lwp.pl_lwpid > 0);
32131.149Skamil
32141.180Skamil			DPRINTF("Assert that lwp thread %d received expected "
32151.180Skamil			    "event\n", lwp.pl_lwpid);
32161.180Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
32171.180Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
32181.180Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
32191.149Skamil
32201.180Skamil			if (strstr(iter, "LWPSTATUS") != NULL) {
32211.180Skamil				DPRINTF("Before calling ptrace(2) with "
32221.180Skamil				    "PT_LWPSTATUS for child\n");
32231.180Skamil				lwpstatus.pl_lwpid = lwp.pl_lwpid;
32241.180Skamil				SYSCALL_REQUIRE(ptrace(PT_LWPSTATUS, child,
32251.180Skamil				    &lwpstatus, sizeof(lwpstatus)) != -1);
32261.149Skamil
32271.180Skamil				goto check_lwpstatus;
32281.180Skamil			}
32291.149Skamil		} else {
32301.180Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for "
32311.180Skamil			    "child\n");
32321.180Skamil			SYSCALL_REQUIRE(
32331.180Skamil			    ptrace(PT_LWPNEXT, child, &lwpstatus,
32341.180Skamil			    sizeof(lwpstatus)) != -1);
32351.180Skamil			DPRINTF("LWP=%d\n", lwpstatus.pl_lwpid);
32361.149Skamil
32371.180Skamil			DPRINTF("Assert that the thread exists\n");
32381.180Skamil			ATF_REQUIRE(lwpstatus.pl_lwpid > 0);
32391.149Skamil
32401.180Skamil		check_lwpstatus:
32411.149Skamil
32421.180Skamil			if (strstr(iter, "pl_sigmask") != NULL) {
32431.180Skamil				sigmask = lwpstatus.pl_sigmask;
32441.149Skamil
32451.180Skamil				DPRINTF("Retrieved sigmask: "
32461.180Skamil				    "%02x%02x%02x%02x\n",
32471.180Skamil				    sigmask.__bits[0], sigmask.__bits[1],
32481.180Skamil				    sigmask.__bits[2], sigmask.__bits[3]);
32491.149Skamil
32501.180Skamil				found = false;
32511.180Skamil				for (m = 0;
32521.180Skamil				     m < __arraycount(lwpinfo_thread_sigmask);
32531.180Skamil				     m++) {
32541.180Skamil					if (sigismember(&sigmask,
32551.180Skamil					    lwpinfo_thread_sigmask[m])) {
32561.180Skamil						found = true;
32571.180Skamil						lwpinfo_thread_sigmask[m] = 0;
32581.180Skamil						break;
32591.180Skamil					}
32601.180Skamil				}
32611.180Skamil				ATF_REQUIRE(found == true);
32621.180Skamil			} else if (strstr(iter, "pl_name") != NULL) {
32631.180Skamil				name = lwpstatus.pl_name;
32641.149Skamil
32651.180Skamil				DPRINTF("Retrieved thread name: "
32661.180Skamil				    "%s\n", name);
32671.149Skamil
32681.180Skamil				snprintf(namebuf, sizeof namebuf, "thread %d",
32691.180Skamil				    lwpstatus.pl_lwpid);
32701.149Skamil
32711.180Skamil				ATF_REQUIRE(strcmp(name, namebuf) == 0);
32721.180Skamil			} else if (strstr(iter, "pl_private") != NULL) {
32731.180Skamil				private = lwpstatus.pl_private;
32741.149Skamil
32751.180Skamil				DPRINTF("Retrieved thread private pointer: "
32761.180Skamil				    "%p\n", private);
32771.149Skamil
32781.180Skamil				found = false;
32791.180Skamil				for (m = 0; m < __arraycount(tcb); m++) {
32801.180Skamil					DPRINTF("Comparing %p and %p\n",
32811.180Skamil					    private, tcb[m]);
32821.180Skamil					if (private == tcb[m]) {
32831.180Skamil						found = true;
32841.180Skamil						break;
32851.180Skamil					}
32861.180Skamil				}
32871.180Skamil				ATF_REQUIRE(found == true);
32881.180Skamil			}
32891.180Skamil		}
32901.180Skamil	}
32911.149Skamil
32921.180Skamil	if (strstr(iter, "LWPINFO") != NULL) {
32931.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
32941.180Skamil		    "child\n");
32951.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPINFO, child, &lwp, sizeof(lwp))
32961.180Skamil		    != -1);
32971.180Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
32981.149Skamil
32991.180Skamil		DPRINTF("Assert that there are no more threads\n");
33001.180Skamil		ATF_REQUIRE_EQ(lwp.pl_lwpid, 0);
33011.180Skamil	} else {
33021.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPNEXT for child\n");
33031.180Skamil		SYSCALL_REQUIRE(ptrace(PT_LWPNEXT, child, &lwpstatus,
33041.180Skamil		    sizeof(lwpstatus)) != -1);
33051.149Skamil
33061.180Skamil		DPRINTF("Assert that there exists a single thread only\n");
33071.180Skamil		ATF_REQUIRE_EQ(lwpstatus.pl_lwpid, 0);
33081.180Skamil	}
33091.149Skamil
33101.180Skamil	DPRINTF("Before resuming the child process where it left off and "
33111.180Skamil	    "without signal to be sent\n");
33121.180Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, SIGKILL) != -1);
33131.149Skamil
33141.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
33151.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
33161.149Skamil
33171.180Skamil	validate_status_signaled(status, SIGKILL, 0);
33181.149Skamil
33191.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
33201.180Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
33211.180Skamil}
33221.149Skamil
33231.180Skamil#define TRACEME_LWPINFO(test, threads, iter)				\
33241.180SkamilATF_TC(test);								\
33251.180SkamilATF_TC_HEAD(test, tc)							\
33261.180Skamil{									\
33271.180Skamil	atf_tc_set_md_var(tc, "descr",					\
33281.180Skamil	    "Verify " iter " with the child with " #threads		\
33291.180Skamil	    " spawned extra threads");					\
33301.180Skamil}									\
33311.180Skamil									\
33321.180SkamilATF_TC_BODY(test, tc)							\
33331.180Skamil{									\
33341.180Skamil									\
33351.180Skamil	traceme_lwpinfo(threads, iter);					\
33361.180Skamil}
33371.149Skamil
33381.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0, 0, "LWPINFO")
33391.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1, 1, "LWPINFO")
33401.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2, 2, "LWPINFO")
33411.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3, 3, "LWPINFO")
33421.149Skamil
33431.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus, 0, "LWPINFO+LWPSTATUS")
33441.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus, 1, "LWPINFO+LWPSTATUS")
33451.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus, 2, "LWPINFO+LWPSTATUS")
33461.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus, 3, "LWPINFO+LWPSTATUS")
33471.149Skamil
33481.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_sigmask, 0,
33491.180Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
33501.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_sigmask, 1,
33511.180Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
33521.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_sigmask, 2,
33531.180Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
33541.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_sigmask, 3,
33551.180Skamil    "LWPINFO+LWPSTATUS+pl_sigmask")
33561.149Skamil
33571.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_name, 0,
33581.180Skamil    "LWPINFO+LWPSTATUS+pl_name")
33591.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_name, 1,
33601.180Skamil    "LWPINFO+LWPSTATUS+pl_name")
33611.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_name, 2,
33621.180Skamil    "LWPINFO+LWPSTATUS+pl_name")
33631.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_name, 3,
33641.180Skamil    "LWPINFO+LWPSTATUS+pl_name")
33651.149Skamil
33661.180SkamilTRACEME_LWPINFO(traceme_lwpinfo0_lwpstatus_pl_private, 0,
33671.180Skamil    "LWPINFO+LWPSTATUS+pl_private")
33681.180SkamilTRACEME_LWPINFO(traceme_lwpinfo1_lwpstatus_pl_private, 1,
33691.180Skamil    "LWPINFO+LWPSTATUS+pl_private")
33701.180SkamilTRACEME_LWPINFO(traceme_lwpinfo2_lwpstatus_pl_private, 2,
33711.180Skamil    "LWPINFO+LWPSTATUS+pl_private")
33721.180SkamilTRACEME_LWPINFO(traceme_lwpinfo3_lwpstatus_pl_private, 3,
33731.180Skamil    "LWPINFO+LWPSTATUS+pl_private")
33741.149Skamil
33751.180SkamilTRACEME_LWPINFO(traceme_lwpnext0, 0, "LWPNEXT")
33761.180SkamilTRACEME_LWPINFO(traceme_lwpnext1, 1, "LWPNEXT")
33771.180SkamilTRACEME_LWPINFO(traceme_lwpnext2, 2, "LWPNEXT")
33781.180SkamilTRACEME_LWPINFO(traceme_lwpnext3, 3, "LWPNEXT")
33791.149Skamil
33801.180SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_sigmask, 0, "LWPNEXT+pl_sigmask")
33811.180SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_sigmask, 1, "LWPNEXT+pl_sigmask")
33821.180SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_sigmask, 2, "LWPNEXT+pl_sigmask")
33831.180SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_sigmask, 3, "LWPNEXT+pl_sigmask")
33841.149Skamil
33851.180SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_name, 0, "LWPNEXT+pl_name")
33861.180SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_name, 1, "LWPNEXT+pl_name")
33871.180SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_name, 2, "LWPNEXT+pl_name")
33881.180SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_name, 3, "LWPNEXT+pl_name")
33891.149Skamil
33901.180SkamilTRACEME_LWPINFO(traceme_lwpnext0_pl_private, 0, "LWPNEXT+pl_private")
33911.180SkamilTRACEME_LWPINFO(traceme_lwpnext1_pl_private, 1, "LWPNEXT+pl_private")
33921.180SkamilTRACEME_LWPINFO(traceme_lwpnext2_pl_private, 2, "LWPNEXT+pl_private")
33931.180SkamilTRACEME_LWPINFO(traceme_lwpnext3_pl_private, 3, "LWPNEXT+pl_private")
33941.149Skamil
33951.180Skamil/// ----------------------------------------------------------------------------
33961.149Skamil
33971.180Skamil#if defined(TWAIT_HAVE_PID)
33981.180Skamilstatic void
33991.180Skamilattach_lwpinfo(const int threads)
34001.180Skamil{
34011.180Skamil	const int sigval = SIGINT;
34021.180Skamil	struct msg_fds parent_tracee, parent_tracer;
34031.180Skamil	const int exitval_tracer = 10;
34041.180Skamil	pid_t tracee, tracer, wpid;
34051.180Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
34061.180Skamil#if defined(TWAIT_HAVE_STATUS)
34071.180Skamil	int status;
34081.180Skamil#endif
34091.180Skamil	struct ptrace_lwpinfo lwp = {0, 0};
34101.180Skamil	struct ptrace_siginfo info;
34111.149Skamil
34121.180Skamil	/* Maximum number of supported threads in this test */
34131.180Skamil	pthread_t t[3];
34141.180Skamil	int n, rv;
34151.149Skamil
34161.180Skamil	DPRINTF("Spawn tracee\n");
34171.180Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
34181.180Skamil	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
34191.180Skamil	tracee = atf_utils_fork();
34201.180Skamil	if (tracee == 0) {
34211.180Skamil		/* Wait for message from the parent */
34221.180Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
34231.149Skamil
34241.180Skamil		CHILD_FROM_PARENT("spawn threads", parent_tracee, msg);
34251.149Skamil
34261.180Skamil		for (n = 0; n < threads; n++) {
34271.180Skamil			rv = pthread_create(&t[n], NULL, infinite_thread, NULL);
34281.180Skamil			FORKEE_ASSERT(rv == 0);
34291.149Skamil		}
34301.149Skamil
34311.180Skamil		CHILD_TO_PARENT("tracee exit", parent_tracee, msg);
34321.149Skamil
34331.180Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
34341.180Skamil		FORKEE_ASSERT(raise(sigval) == 0);
34351.149Skamil
34361.180Skamil		/* NOTREACHED */
34371.180Skamil		FORKEE_ASSERTX(0 && "Not reached");
34381.150Skamil	}
34391.180Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
34401.150Skamil
34411.150Skamil	DPRINTF("Spawn debugger\n");
34421.150Skamil	tracer = atf_utils_fork();
34431.150Skamil	if (tracer == 0) {
34441.180Skamil		/* No IPC to communicate with the child */
34451.150Skamil		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
34461.150Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
34471.150Skamil
34481.150Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
34491.150Skamil		FORKEE_REQUIRE_SUCCESS(
34501.150Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
34511.150Skamil
34521.150Skamil		forkee_status_stopped(status, SIGSTOP);
34531.150Skamil
34541.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
34551.180Skamil		    "tracee");
34561.180Skamil		FORKEE_ASSERT(
34571.150Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
34581.150Skamil
34591.150Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
34601.150Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
34611.180Skamil		    "si_errno=%#x\n",
34621.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
34631.180Skamil		    info.psi_siginfo.si_errno);
34641.150Skamil
34651.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, SIGSTOP);
34661.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_USER);
34671.150Skamil
34681.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for child\n");
34691.180Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
34701.180Skamil		    != -1);
34711.180Skamil
34721.180Skamil		DPRINTF("Assert that there exists a thread\n");
34731.180Skamil		FORKEE_ASSERTX(lwp.pl_lwpid > 0);
34741.180Skamil
34751.180Skamil		DPRINTF("Assert that lwp thread %d received event "
34761.180Skamil		    "PL_EVENT_SIGNAL\n", lwp.pl_lwpid);
34771.180Skamil		FORKEE_ASSERT_EQ(lwp.pl_event, PL_EVENT_SIGNAL);
34781.180Skamil
34791.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
34801.180Skamil		    "tracee\n");
34811.180Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
34821.180Skamil		    != -1);
34831.180Skamil
34841.180Skamil		DPRINTF("Assert that there are no more lwp threads in "
34851.180Skamil		    "tracee\n");
34861.180Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
34871.180Skamil
34881.150Skamil		/* Resume tracee with PT_CONTINUE */
34891.150Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
34901.150Skamil
34911.150Skamil		/* Inform parent that tracer has attached to tracee */
34921.150Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
34931.150Skamil
34941.180Skamil		/* Wait for parent */
34951.180Skamil		CHILD_FROM_PARENT("tracer wait", parent_tracer, msg);
34961.150Skamil
34971.180Skamil		/* Wait for tracee and assert that it raised a signal */
34981.150Skamil		FORKEE_REQUIRE_SUCCESS(
34991.150Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
35001.150Skamil
35011.180Skamil		forkee_status_stopped(status, SIGINT);
35021.150Skamil
35031.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
35041.180Skamil		    "child");
35051.180Skamil		FORKEE_ASSERT(
35061.150Skamil		    ptrace(PT_GET_SIGINFO, tracee, &info, sizeof(info)) != -1);
35071.150Skamil
35081.150Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
35091.150Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
35101.180Skamil		    "si_errno=%#x\n",
35111.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
35121.180Skamil		    info.psi_siginfo.si_errno);
35131.150Skamil
35141.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_signo, sigval);
35151.150Skamil		FORKEE_ASSERT_EQ(info.psi_siginfo.si_code, SI_LWP);
35161.150Skamil
35171.180Skamil		memset(&lwp, 0, sizeof(lwp));
35181.150Skamil
35191.180Skamil		for (n = 0; n <= threads; n++) {
35201.180Skamil			DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
35211.180Skamil			    "child\n");
35221.180Skamil			FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp,
35231.180Skamil			    sizeof(lwp)) != -1);
35241.180Skamil			DPRINTF("LWP=%d\n", lwp.pl_lwpid);
35251.150Skamil
35261.180Skamil			DPRINTF("Assert that the thread exists\n");
35271.180Skamil			FORKEE_ASSERT(lwp.pl_lwpid > 0);
35281.150Skamil
35291.180Skamil			DPRINTF("Assert that lwp thread %d received expected "
35301.180Skamil			    "event\n", lwp.pl_lwpid);
35311.180Skamil			FORKEE_ASSERT_EQ(lwp.pl_event,
35321.180Skamil			    info.psi_lwpid == lwp.pl_lwpid ?
35331.180Skamil			    PL_EVENT_SIGNAL : PL_EVENT_NONE);
35341.180Skamil		}
35351.180Skamil		DPRINTF("Before calling ptrace(2) with PT_LWPINFO for "
35361.180Skamil		    "tracee\n");
35371.180Skamil		FORKEE_ASSERT(ptrace(PT_LWPINFO, tracee, &lwp, sizeof(lwp))
35381.180Skamil		    != -1);
35391.180Skamil		DPRINTF("LWP=%d\n", lwp.pl_lwpid);
35401.150Skamil
35411.180Skamil		DPRINTF("Assert that there are no more threads\n");
35421.180Skamil		FORKEE_ASSERT_EQ(lwp.pl_lwpid, 0);
35431.150Skamil
35441.180Skamil		DPRINTF("Before resuming the child process where it left off "
35451.150Skamil		    "and without signal to be sent\n");
35461.180Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, SIGKILL)
35471.180Skamil		    != -1);
35481.150Skamil
35491.180Skamil		/* Wait for tracee and assert that it exited */
35501.180Skamil		FORKEE_REQUIRE_SUCCESS(
35511.180Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
35521.150Skamil
35531.180Skamil		forkee_status_signaled(status, SIGKILL, 0);
35541.150Skamil
35551.150Skamil		DPRINTF("Before exiting of the tracer process\n");
35561.180Skamil		_exit(exitval_tracer);
35571.97Skamil	}
35581.97Skamil
35591.180Skamil	DPRINTF("Wait for the tracer to attach to the tracee\n");
35601.180Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
35611.97Skamil
35621.180Skamil	DPRINTF("Resume the tracee and spawn threads\n");
35631.180Skamil	PARENT_TO_CHILD("spawn threads", parent_tracee, msg);
35641.97Skamil
35651.180Skamil	DPRINTF("Resume the tracee and let it exit\n");
35661.180Skamil	PARENT_FROM_CHILD("tracee exit", parent_tracee, msg);
35671.97Skamil
35681.180Skamil	DPRINTF("Resume the tracer and let it detect multiple threads\n");
35691.180Skamil	PARENT_TO_CHILD("tracer wait", parent_tracer, msg);
35701.1Skamil
35711.180Skamil	DPRINTF("Wait for tracer to finish its job and exit - calling %s()\n",
35721.180Skamil	    TWAIT_FNAME);
35731.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
35741.180Skamil	    tracer);
35751.1Skamil
35761.180Skamil	validate_status_exited(status, exitval_tracer);
35771.1Skamil
35781.180Skamil	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
35791.180Skamil	    TWAIT_FNAME);
35801.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
35811.180Skamil	    tracee);
35821.1Skamil
35831.180Skamil	validate_status_signaled(status, SIGKILL, 0);
35841.1Skamil
35851.180Skamil	msg_close(&parent_tracer);
35861.180Skamil	msg_close(&parent_tracee);
35871.1Skamil}
35881.1Skamil
35891.180Skamil#define ATTACH_LWPINFO(test, threads)					\
35901.97SkamilATF_TC(test);								\
35911.97SkamilATF_TC_HEAD(test, tc)							\
35921.97Skamil{									\
35931.180Skamil	atf_tc_set_md_var(tc, "descr",					\
35941.180Skamil	    "Verify LWPINFO with the child with " #threads		\
35951.180Skamil	    " spawned extra threads (tracer is not the original "	\
35961.180Skamil	    "parent)");							\
35971.97Skamil}									\
35981.97Skamil									\
35991.97SkamilATF_TC_BODY(test, tc)							\
36001.97Skamil{									\
36011.97Skamil									\
36021.180Skamil	attach_lwpinfo(threads);					\
36031.97Skamil}
36041.97Skamil
36051.180SkamilATTACH_LWPINFO(attach_lwpinfo0, 0)
36061.180SkamilATTACH_LWPINFO(attach_lwpinfo1, 1)
36071.180SkamilATTACH_LWPINFO(attach_lwpinfo2, 2)
36081.180SkamilATTACH_LWPINFO(attach_lwpinfo3, 3)
36091.180Skamil#endif
36101.97Skamil
36111.82Skamil/// ----------------------------------------------------------------------------
36121.82Skamil
36131.83Skamilstatic void
36141.180Skamilptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c), int *signal_caught)
36151.1Skamil{
36161.180Skamil	const int exitval = 5;
36171.180Skamil	const int sigval = SIGINT;
36181.180Skamil	const int sigfaked = SIGTRAP;
36191.180Skamil	const int sicodefaked = TRAP_BRKPT;
36201.1Skamil	pid_t child, wpid;
36211.180Skamil	struct sigaction sa;
36221.1Skamil#if defined(TWAIT_HAVE_STATUS)
36231.1Skamil	int status;
36241.1Skamil#endif
36251.83Skamil	struct ptrace_siginfo info;
36261.180Skamil	memset(&info, 0, sizeof(info));
36271.83Skamil
36281.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
36291.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
36301.1Skamil	if (child == 0) {
36311.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
36321.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
36331.1Skamil
36341.180Skamil		sa.sa_sigaction = sah;
36351.180Skamil		sa.sa_flags = SA_SIGINFO;
36361.180Skamil		sigemptyset(&sa.sa_mask);
36371.180Skamil
36381.180Skamil		FORKEE_ASSERT(sigaction(faked ? sigfaked : sigval, &sa, NULL)
36391.180Skamil		    != -1);
36401.153Skamil
36411.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
36421.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
36431.1Skamil
36441.180Skamil		FORKEE_ASSERT_EQ(*signal_caught, 1);
36451.1Skamil
36461.180Skamil		DPRINTF("Before exiting of the child process\n");
36471.180Skamil		_exit(exitval);
36481.1Skamil	}
36491.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
36501.1Skamil
36511.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
36521.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
36531.1Skamil
36541.1Skamil	validate_status_stopped(status, sigval);
36551.1Skamil
36561.83Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
36571.83Skamil	SYSCALL_REQUIRE(
36581.83Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
36591.1Skamil
36601.83Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
36611.83Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
36621.83Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
36631.83Skamil	    info.psi_siginfo.si_errno);
36641.1Skamil
36651.180Skamil	if (faked) {
36661.180Skamil		DPRINTF("Before setting new faked signal to signo=%d "
36671.180Skamil		    "si_code=%d\n", sigfaked, sicodefaked);
36681.180Skamil		info.psi_siginfo.si_signo = sigfaked;
36691.180Skamil		info.psi_siginfo.si_code = sicodefaked;
36701.83Skamil	}
36711.1Skamil
36721.180Skamil	DPRINTF("Before calling ptrace(2) with PT_SET_SIGINFO for child\n");
36731.180Skamil	SYSCALL_REQUIRE(
36741.180Skamil	    ptrace(PT_SET_SIGINFO, child, &info, sizeof(info)) != -1);
36751.1Skamil
36761.180Skamil	if (faked) {
36771.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
36781.83Skamil		    "child\n");
36791.180Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
36801.180Skamil		    sizeof(info)) != -1);
36811.1Skamil
36821.180Skamil		DPRINTF("Before checking siginfo_t\n");
36831.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigfaked);
36841.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, sicodefaked);
36851.83Skamil	}
36861.1Skamil
36871.180Skamil	DPRINTF("Before resuming the child process where it left off and "
36881.180Skamil	    "without signal to be sent\n");
36891.180Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
36901.180Skamil	    faked ? sigfaked : sigval) != -1);
36911.1Skamil
36921.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
36931.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
36941.1Skamil
36951.180Skamil	validate_status_exited(status, exitval);
36961.1Skamil
36971.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
36981.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
36991.1Skamil}
37001.1Skamil
37011.180Skamil#define PTRACE_SIGINFO(test, faked)					\
37021.83SkamilATF_TC(test);								\
37031.83SkamilATF_TC_HEAD(test, tc)							\
37041.83Skamil{									\
37051.180Skamil	atf_tc_set_md_var(tc, "descr",					\
37061.180Skamil	    "Verify basic PT_GET_SIGINFO and PT_SET_SIGINFO calls"	\
37071.180Skamil	    "with%s setting signal to new value", faked ? "" : "out");	\
37081.180Skamil}									\
37091.180Skamil									\
37101.180Skamilstatic int test##_caught = 0;						\
37111.180Skamil									\
37121.180Skamilstatic void								\
37131.180Skamiltest##_sighandler(int sig, siginfo_t *info, void *ctx)			\
37141.180Skamil{									\
37151.180Skamil	if (faked) {							\
37161.180Skamil		FORKEE_ASSERT_EQ(sig, SIGTRAP);				\
37171.180Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGTRAP);		\
37181.180Skamil		FORKEE_ASSERT_EQ(info->si_code, TRAP_BRKPT);		\
37191.180Skamil	} else {							\
37201.180Skamil		FORKEE_ASSERT_EQ(sig, SIGINT);				\
37211.180Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGINT);		\
37221.180Skamil		FORKEE_ASSERT_EQ(info->si_code, SI_LWP);		\
37231.180Skamil	}								\
37241.180Skamil									\
37251.180Skamil	++ test##_caught;						\
37261.83Skamil}									\
37271.83Skamil									\
37281.83SkamilATF_TC_BODY(test, tc)							\
37291.83Skamil{									\
37301.83Skamil									\
37311.180Skamil	ptrace_siginfo(faked, test##_sighandler, & test##_caught); 	\
37321.83Skamil}
37331.83Skamil
37341.180SkamilPTRACE_SIGINFO(siginfo_set_unmodified, false)
37351.180SkamilPTRACE_SIGINFO(siginfo_set_faked, true)
37361.83Skamil
37371.83Skamil/// ----------------------------------------------------------------------------
37381.83Skamil
37391.180Skamilstatic void
37401.180Skamiltraceme_exec(bool masked, bool ignored)
37411.1Skamil{
37421.180Skamil	const int sigval = SIGTRAP;
37431.1Skamil	pid_t child, wpid;
37441.1Skamil#if defined(TWAIT_HAVE_STATUS)
37451.1Skamil	int status;
37461.1Skamil#endif
37471.180Skamil	struct sigaction sa;
37481.180Skamil	struct ptrace_siginfo info;
37491.1Skamil	sigset_t intmask;
37501.180Skamil	struct kinfo_proc2 kp;
37511.180Skamil	size_t len = sizeof(kp);
37521.180Skamil
37531.180Skamil	int name[6];
37541.180Skamil	const size_t namelen = __arraycount(name);
37551.180Skamil	ki_sigset_t kp_sigmask;
37561.180Skamil	ki_sigset_t kp_sigignore;
37571.180Skamil
37581.180Skamil	memset(&info, 0, sizeof(info));
37591.1Skamil
37601.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
37611.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
37621.1Skamil	if (child == 0) {
37631.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
37641.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
37651.1Skamil
37661.180Skamil		if (masked) {
37671.180Skamil			sigemptyset(&intmask);
37681.180Skamil			sigaddset(&intmask, sigval);
37691.180Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
37701.180Skamil		}
37711.1Skamil
37721.180Skamil		if (ignored) {
37731.180Skamil			memset(&sa, 0, sizeof(sa));
37741.180Skamil			sa.sa_handler = SIG_IGN;
37751.180Skamil			sigemptyset(&sa.sa_mask);
37761.180Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
37771.180Skamil		}
37781.1Skamil
37791.180Skamil		DPRINTF("Before calling execve(2) from child\n");
37801.180Skamil		execlp("/bin/echo", "/bin/echo", NULL);
37811.1Skamil
37821.180Skamil		FORKEE_ASSERT(0 && "Not reached");
37831.1Skamil	}
37841.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
37851.1Skamil
37861.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
37871.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
37881.1Skamil
37891.1Skamil	validate_status_stopped(status, sigval);
37901.1Skamil
37911.180Skamil	name[0] = CTL_KERN,
37921.180Skamil	name[1] = KERN_PROC2,
37931.180Skamil	name[2] = KERN_PROC_PID;
37941.180Skamil	name[3] = getpid();
37951.180Skamil	name[4] = sizeof(kp);
37961.180Skamil	name[5] = 1;
37971.180Skamil
37981.180Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
37991.180Skamil
38001.180Skamil	if (masked)
38011.180Skamil		kp_sigmask = kp.p_sigmask;
38021.180Skamil
38031.180Skamil	if (ignored)
38041.180Skamil		kp_sigignore = kp.p_sigignore;
38051.180Skamil
38061.180Skamil	name[3] = getpid();
38071.180Skamil
38081.180Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
38091.180Skamil
38101.180Skamil	if (masked) {
38111.180Skamil		DPRINTF("kp_sigmask="
38121.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
38131.180Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
38141.180Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
38151.180Skamil
38161.180Skamil		DPRINTF("kp.p_sigmask="
38171.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
38181.180Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
38191.180Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
38201.180Skamil
38211.180Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
38221.180Skamil		    sizeof(kp_sigmask)));
38231.180Skamil	}
38241.180Skamil
38251.180Skamil	if (ignored) {
38261.180Skamil		DPRINTF("kp_sigignore="
38271.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
38281.180Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
38291.180Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
38301.180Skamil
38311.180Skamil		DPRINTF("kp.p_sigignore="
38321.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
38331.180Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
38341.180Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
38351.180Skamil
38361.180Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
38371.180Skamil		    sizeof(kp_sigignore)));
38381.180Skamil	}
38391.180Skamil
38401.180Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
38411.180Skamil	SYSCALL_REQUIRE(
38421.180Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
38431.1Skamil
38441.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
38451.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
38461.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
38471.180Skamil	    info.psi_siginfo.si_errno);
38481.1Skamil
38491.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
38501.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
38511.1Skamil
38521.13Schristos	DPRINTF("Before resuming the child process where it left off and "
38531.1Skamil	    "without signal to be sent\n");
38541.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
38551.1Skamil
38561.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
38571.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
38581.1Skamil
38591.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
38601.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
38611.1Skamil}
38621.1Skamil
38631.180Skamil#define TRACEME_EXEC(test, masked, ignored)				\
38641.180SkamilATF_TC(test);								\
38651.180SkamilATF_TC_HEAD(test, tc)							\
38661.180Skamil{									\
38671.180Skamil       atf_tc_set_md_var(tc, "descr",					\
38681.180Skamil           "Detect SIGTRAP TRAP_EXEC from "				\
38691.180Skamil           "child%s%s", masked ? " with masked signal" : "",		\
38701.180Skamil           masked ? " with ignored signal" : "");			\
38711.180Skamil}									\
38721.180Skamil									\
38731.180SkamilATF_TC_BODY(test, tc)							\
38741.180Skamil{									\
38751.180Skamil									\
38761.180Skamil       traceme_exec(masked, ignored);					\
38771.180Skamil}
38781.180Skamil
38791.180SkamilTRACEME_EXEC(traceme_exec, false, false)
38801.180SkamilTRACEME_EXEC(traceme_signalmasked_exec, true, false)
38811.180SkamilTRACEME_EXEC(traceme_signalignored_exec, false, true)
38821.180Skamil
38831.84Skamil/// ----------------------------------------------------------------------------
38841.84Skamil
38851.180Skamil#define TRACE_THREADS_NUM 100
38861.180Skamil
38871.180Skamilstatic volatile int done;
38881.180Skamilpthread_mutex_t trace_threads_mtx = PTHREAD_MUTEX_INITIALIZER;
38891.180Skamil
38901.180Skamilstatic void *
38911.180Skamiltrace_threads_cb(void *arg __unused)
38921.180Skamil{
38931.180Skamil
38941.180Skamil	pthread_mutex_lock(&trace_threads_mtx);
38951.180Skamil	done++;
38961.180Skamil	pthread_mutex_unlock(&trace_threads_mtx);
38971.180Skamil
38981.180Skamil	while (done < TRACE_THREADS_NUM)
38991.180Skamil		sched_yield();
39001.180Skamil
39011.180Skamil	return NULL;
39021.180Skamil}
39031.180Skamil
39041.99Skamilstatic void
39051.180Skamiltrace_threads(bool trace_create, bool trace_exit, bool masked)
39061.1Skamil{
39071.1Skamil	const int sigval = SIGSTOP;
39081.180Skamil	pid_t child, wpid;
39091.1Skamil#if defined(TWAIT_HAVE_STATUS)
39101.1Skamil	int status;
39111.1Skamil#endif
39121.1Skamil	ptrace_state_t state;
39131.1Skamil	const int slen = sizeof(state);
39141.1Skamil	ptrace_event_t event;
39151.1Skamil	const int elen = sizeof(event);
39161.99Skamil	struct ptrace_siginfo info;
39171.180Skamil
39181.99Skamil	sigset_t intmask;
39191.99Skamil
39201.180Skamil	pthread_t t[TRACE_THREADS_NUM];
39211.180Skamil	int rv;
39221.180Skamil	size_t n;
39231.180Skamil	lwpid_t lid;
39241.1Skamil
39251.180Skamil	/* Track created and exited threads */
39261.180Skamil	struct lwp_event_count traced_lwps[__arraycount(t)] = {{0, 0}};
39271.14Schristos
39281.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
39291.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
39301.1Skamil	if (child == 0) {
39311.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
39321.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
39331.1Skamil
39341.99Skamil		if (masked) {
39351.99Skamil			sigemptyset(&intmask);
39361.99Skamil			sigaddset(&intmask, SIGTRAP);
39371.99Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
39381.99Skamil		}
39391.99Skamil
39401.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
39411.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
39421.1Skamil
39431.180Skamil		for (n = 0; n < __arraycount(t); n++) {
39441.180Skamil			rv = pthread_create(&t[n], NULL, trace_threads_cb,
39451.180Skamil			    NULL);
39461.180Skamil			FORKEE_ASSERT(rv == 0);
39471.126Skamil		}
39481.1Skamil
39491.180Skamil		for (n = 0; n < __arraycount(t); n++) {
39501.180Skamil			rv = pthread_join(t[n], NULL);
39511.180Skamil			FORKEE_ASSERT(rv == 0);
39521.180Skamil		}
39531.1Skamil
39541.180Skamil		/*
39551.180Skamil		 * There is race between _exit() and pthread_join() detaching
39561.180Skamil		 * a thread. For simplicity kill the process after detecting
39571.180Skamil		 * LWP events.
39581.180Skamil		 */
39591.180Skamil		while (true)
39601.180Skamil			continue;
39611.1Skamil
39621.180Skamil		FORKEE_ASSERT(0 && "Not reached");
39631.1Skamil	}
39641.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
39651.1Skamil
39661.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
39671.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
39681.1Skamil
39691.1Skamil	validate_status_stopped(status, sigval);
39701.1Skamil
39711.99Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
39721.99Skamil	SYSCALL_REQUIRE(
39731.99Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
39741.99Skamil
39751.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
39761.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
39771.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
39781.180Skamil	    info.psi_siginfo.si_errno);
39791.180Skamil
39801.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
39811.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
39821.1Skamil
39831.180Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
39841.180Skamil	memset(&event, 0, sizeof(event));
39851.180Skamil	if (trace_create)
39861.180Skamil		event.pe_set_event |= PTRACE_LWP_CREATE;
39871.180Skamil	if (trace_exit)
39881.180Skamil		event.pe_set_event |= PTRACE_LWP_EXIT;
39891.99Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
39901.1Skamil
39911.99Skamil	DPRINTF("Before resuming the child process where it left off and "
39921.99Skamil	    "without signal to be sent\n");
39931.99Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
39941.1Skamil
39951.180Skamil	for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
39961.180Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
39971.180Skamil		    "SIGTRAP\n", TWAIT_FNAME);
39981.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
39991.99Skamil		    child);
40001.1Skamil
40011.99Skamil		validate_status_stopped(status, SIGTRAP);
40021.1Skamil
40031.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
40041.180Skamil		    "child\n");
40051.180Skamil		SYSCALL_REQUIRE(
40061.180Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
40071.180Skamil
40081.180Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
40091.180Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
40101.180Skamil		    "si_errno=%#x\n",
40111.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
40121.180Skamil		    info.psi_siginfo.si_errno);
40131.1Skamil
40141.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
40151.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
40161.1Skamil
40171.180Skamil		SYSCALL_REQUIRE(
40181.180Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
40191.1Skamil
40201.180Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
40211.180Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
40221.1Skamil
40231.180Skamil		lid = state.pe_lwp;
40241.180Skamil		DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
40251.1Skamil
40261.180Skamil		*FIND_EVENT_COUNT(traced_lwps, lid) += 1;
40271.1Skamil
40281.180Skamil		DPRINTF("Before resuming the child process where it left off "
40291.180Skamil		    "and without signal to be sent\n");
40301.180Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
40311.180Skamil	}
40321.1Skamil
40331.180Skamil	for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
40341.180Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
40351.180Skamil		    "SIGTRAP\n", TWAIT_FNAME);
40361.180Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
40371.180Skamil		    child);
40381.1Skamil
40391.99Skamil		validate_status_stopped(status, SIGTRAP);
40401.1Skamil
40411.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
40421.180Skamil		    "child\n");
40431.180Skamil		SYSCALL_REQUIRE(
40441.180Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
40451.1Skamil
40461.180Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
40471.180Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
40481.180Skamil		    "si_errno=%#x\n",
40491.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
40501.180Skamil		    info.psi_siginfo.si_errno);
40511.1Skamil
40521.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
40531.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
40541.14Schristos
40551.180Skamil		SYSCALL_REQUIRE(
40561.180Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
40571.1Skamil
40581.180Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
40591.180Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
40601.1Skamil
40611.180Skamil		lid = state.pe_lwp;
40621.180Skamil		DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
40631.1Skamil
40641.180Skamil		if (trace_create) {
40651.180Skamil			int *count = FIND_EVENT_COUNT(traced_lwps, lid);
40661.180Skamil			ATF_REQUIRE_EQ(*count, 1);
40671.180Skamil			*count = 0;
40681.99Skamil		}
40691.1Skamil
40701.99Skamil		DPRINTF("Before resuming the child process where it left off "
40711.99Skamil		    "and without signal to be sent\n");
40721.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
40731.1Skamil	}
40741.1Skamil
40751.180Skamil	kill(child, SIGKILL);
40761.180Skamil
40771.180Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
40781.180Skamil	    TWAIT_FNAME);
40791.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
40801.180Skamil
40811.180Skamil	validate_status_signaled(status, SIGKILL, 0);
40821.1Skamil
40831.180Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
40841.180Skamil	    TWAIT_FNAME);
40851.180Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
40861.180Skamil}
40871.1Skamil
40881.180Skamil#define TRACE_THREADS(test, trace_create, trace_exit, mask)		\
40891.180SkamilATF_TC(test);								\
40901.180SkamilATF_TC_HEAD(test, tc)							\
40911.180Skamil{									\
40921.180Skamil        atf_tc_set_md_var(tc, "descr",					\
40931.180Skamil            "Verify spawning threads with%s tracing LWP create and"	\
40941.180Skamil	    "with%s tracing LWP exit", trace_create ? "" : "out",	\
40951.180Skamil	    trace_exit ? "" : "out");					\
40961.180Skamil}									\
40971.180Skamil									\
40981.180SkamilATF_TC_BODY(test, tc)							\
40991.180Skamil{									\
41001.180Skamil									\
41011.180Skamil        trace_threads(trace_create, trace_exit, mask);			\
41021.180Skamil}
41031.1Skamil
41041.180SkamilTRACE_THREADS(trace_thread_nolwpevents, false, false, false)
41051.180SkamilTRACE_THREADS(trace_thread_lwpexit, false, true, false)
41061.180SkamilTRACE_THREADS(trace_thread_lwpcreate, true, false, false)
41071.180SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true, false)
41081.102Skamil
41091.180SkamilTRACE_THREADS(trace_thread_lwpexit_masked_sigtrap, false, true, true)
41101.180SkamilTRACE_THREADS(trace_thread_lwpcreate_masked_sigtrap, true, false, true)
41111.180SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit_masked_sigtrap, true, true, true)
41121.1Skamil
41131.180Skamil/// ----------------------------------------------------------------------------
41141.1Skamil
41151.180SkamilATF_TC(signal_mask_unrelated);
41161.180SkamilATF_TC_HEAD(signal_mask_unrelated, tc)
41171.180Skamil{
41181.180Skamil	atf_tc_set_md_var(tc, "descr",
41191.180Skamil	    "Verify that masking single unrelated signal does not stop tracer "
41201.180Skamil	    "from catching other signals");
41211.180Skamil}
41221.1Skamil
41231.180SkamilATF_TC_BODY(signal_mask_unrelated, tc)
41241.180Skamil{
41251.180Skamil	const int exitval = 5;
41261.180Skamil	const int sigval = SIGSTOP;
41271.180Skamil	const int sigmasked = SIGTRAP;
41281.180Skamil	const int signotmasked = SIGINT;
41291.180Skamil	pid_t child, wpid;
41301.180Skamil#if defined(TWAIT_HAVE_STATUS)
41311.180Skamil	int status;
41321.180Skamil#endif
41331.180Skamil	sigset_t intmask;
41341.1Skamil
41351.180Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
41361.180Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
41371.180Skamil	if (child == 0) {
41381.180Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
41391.180Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
41401.1Skamil
41411.180Skamil		sigemptyset(&intmask);
41421.180Skamil		sigaddset(&intmask, sigmasked);
41431.180Skamil		sigprocmask(SIG_BLOCK, &intmask, NULL);
41441.1Skamil
41451.180Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
41461.180Skamil		FORKEE_ASSERT(raise(sigval) == 0);
41471.1Skamil
41481.180Skamil		DPRINTF("Before raising %s from child\n",
41491.180Skamil		    strsignal(signotmasked));
41501.180Skamil		FORKEE_ASSERT(raise(signotmasked) == 0);
41511.1Skamil
41521.180Skamil		DPRINTF("Before exiting of the child process\n");
41531.180Skamil		_exit(exitval);
41541.99Skamil	}
41551.180Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
41561.1Skamil
41571.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
41581.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
41591.1Skamil
41601.180Skamil	validate_status_stopped(status, sigval);
41611.1Skamil
41621.180Skamil	DPRINTF("Before resuming the child process where it left off and "
41631.180Skamil	    "without signal to be sent\n");
41641.180Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
41651.1Skamil
41661.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
41671.57Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
41681.1Skamil
41691.180Skamil	validate_status_stopped(status, signotmasked);
41701.1Skamil
41711.57Skamil	DPRINTF("Before resuming the child process where it left off and "
41721.1Skamil	    "without signal to be sent\n");
41731.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
41741.1Skamil
41751.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
41761.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
41771.1Skamil
41781.1Skamil	validate_status_exited(status, exitval);
41791.1Skamil
41801.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
41811.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
41821.1Skamil}
41831.1Skamil
41841.99Skamil/// ----------------------------------------------------------------------------
41851.1Skamil
41861.151Skamilstatic void *
41871.151Skamilthread_and_exec_thread_cb(void *arg __unused)
41881.151Skamil{
41891.151Skamil
41901.151Skamil	execlp("/bin/echo", "/bin/echo", NULL);
41911.151Skamil
41921.151Skamil	abort();
41931.151Skamil}
41941.151Skamil
41951.151Skamilstatic void
41961.151Skamilthreads_and_exec(void)
41971.151Skamil{
41981.151Skamil	const int sigval = SIGSTOP;
41991.151Skamil	pid_t child, wpid;
42001.151Skamil#if defined(TWAIT_HAVE_STATUS)
42011.151Skamil	int status;
42021.151Skamil#endif
42031.151Skamil	ptrace_state_t state;
42041.151Skamil	const int slen = sizeof(state);
42051.151Skamil	ptrace_event_t event;
42061.151Skamil	const int elen = sizeof(event);
42071.151Skamil	struct ptrace_siginfo info;
42081.151Skamil
42091.151Skamil	pthread_t t;
42101.151Skamil	lwpid_t lid;
42111.151Skamil
42121.151Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
42131.151Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
42141.151Skamil	if (child == 0) {
42151.151Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
42161.151Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
42171.151Skamil
42181.151Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
42191.151Skamil		FORKEE_ASSERT(raise(sigval) == 0);
42201.151Skamil
42211.151Skamil		FORKEE_ASSERT(pthread_create(&t, NULL,
42221.151Skamil		    thread_and_exec_thread_cb, NULL) == 0);
42231.151Skamil
42241.151Skamil		for (;;)
42251.151Skamil			continue;
42261.151Skamil
42271.151Skamil		FORKEE_ASSERT(0 && "Not reached");
42281.151Skamil	}
42291.151Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
42301.151Skamil
42311.151Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
42321.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
42331.151Skamil
42341.151Skamil	validate_status_stopped(status, sigval);
42351.151Skamil
42361.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
42371.151Skamil	SYSCALL_REQUIRE(
42381.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
42391.151Skamil
42401.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
42411.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
42421.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
42431.151Skamil	    info.psi_siginfo.si_errno);
42441.151Skamil
42451.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
42461.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
42471.151Skamil
42481.151Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
42491.151Skamil	memset(&event, 0, sizeof(event));
42501.151Skamil	event.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
42511.151Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
42521.151Skamil
42531.151Skamil	DPRINTF("Before resuming the child process where it left off and "
42541.151Skamil	    "without signal to be sent\n");
42551.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
42561.151Skamil
42571.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
42581.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
42591.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
42601.151Skamil	    child);
42611.151Skamil
42621.151Skamil	validate_status_stopped(status, SIGTRAP);
42631.151Skamil
42641.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
42651.151Skamil	    "child\n");
42661.151Skamil	SYSCALL_REQUIRE(
42671.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
42681.151Skamil
42691.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
42701.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
42711.151Skamil	    "si_errno=%#x\n",
42721.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
42731.151Skamil	    info.psi_siginfo.si_errno);
42741.151Skamil
42751.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
42761.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
42771.151Skamil
42781.151Skamil	SYSCALL_REQUIRE(
42791.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
42801.151Skamil
42811.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
42821.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
42831.151Skamil
42841.151Skamil	lid = state.pe_lwp;
42851.151Skamil	DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
42861.151Skamil
42871.151Skamil	DPRINTF("Before resuming the child process where it left off "
42881.151Skamil	    "and without signal to be sent\n");
42891.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
42901.151Skamil
42911.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
42921.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
42931.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
42941.151Skamil	    child);
42951.151Skamil
42961.151Skamil	validate_status_stopped(status, SIGTRAP);
42971.151Skamil
42981.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
42991.151Skamil	    "child\n");
43001.151Skamil	SYSCALL_REQUIRE(
43011.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
43021.151Skamil
43031.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
43041.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
43051.151Skamil	    "si_errno=%#x\n",
43061.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
43071.151Skamil	    info.psi_siginfo.si_errno);
43081.151Skamil
43091.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
43101.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
43111.151Skamil
43121.151Skamil	SYSCALL_REQUIRE(
43131.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
43141.151Skamil
43151.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
43161.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
43171.151Skamil
43181.151Skamil	lid = state.pe_lwp;
43191.151Skamil	DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
43201.151Skamil
43211.151Skamil	DPRINTF("Before resuming the child process where it left off "
43221.151Skamil	    "and without signal to be sent\n");
43231.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
43241.151Skamil
43251.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
43261.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
43271.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
43281.151Skamil	    child);
43291.151Skamil
43301.151Skamil	validate_status_stopped(status, SIGTRAP);
43311.151Skamil
43321.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
43331.151Skamil	    "child\n");
43341.151Skamil	SYSCALL_REQUIRE(
43351.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
43361.151Skamil
43371.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
43381.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
43391.151Skamil	    "si_errno=%#x\n",
43401.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
43411.151Skamil	    info.psi_siginfo.si_errno);
43421.151Skamil
43431.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
43441.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
43451.151Skamil
43461.151Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
43471.151Skamil
43481.151Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
43491.151Skamil	    TWAIT_FNAME);
43501.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
43511.151Skamil
43521.151Skamil	validate_status_signaled(status, SIGKILL, 0);
43531.151Skamil
43541.151Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
43551.151Skamil	    TWAIT_FNAME);
43561.151Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
43571.151Skamil}
43581.151Skamil
43591.151SkamilATF_TC(threads_and_exec);
43601.151SkamilATF_TC_HEAD(threads_and_exec, tc)
43611.151Skamil{
43621.151Skamil        atf_tc_set_md_var(tc, "descr",
43631.151Skamil            "Verify that multithreaded application on exec() will report "
43641.151Skamil	    "LWP_EXIT events");
43651.151Skamil}
43661.151Skamil
43671.151SkamilATF_TC_BODY(threads_and_exec, tc)
43681.151Skamil{
43691.151Skamil
43701.151Skamil        threads_and_exec();
43711.151Skamil}
43721.151Skamil
43731.151Skamil/// ----------------------------------------------------------------------------
43741.151Skamil
43751.154SkamilATF_TC(suspend_no_deadlock);
43761.154SkamilATF_TC_HEAD(suspend_no_deadlock, tc)
43771.1Skamil{
43781.1Skamil	atf_tc_set_md_var(tc, "descr",
43791.1Skamil	    "Verify that the while the only thread within a process is "
43801.1Skamil	    "suspended, the whole process cannot be unstopped");
43811.1Skamil}
43821.1Skamil
43831.154SkamilATF_TC_BODY(suspend_no_deadlock, tc)
43841.1Skamil{
43851.1Skamil	const int exitval = 5;
43861.1Skamil	const int sigval = SIGSTOP;
43871.1Skamil	pid_t child, wpid;
43881.1Skamil#if defined(TWAIT_HAVE_STATUS)
43891.1Skamil	int status;
43901.1Skamil#endif
43911.1Skamil	struct ptrace_siginfo psi;
43921.1Skamil
43931.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
43941.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
43951.1Skamil	if (child == 0) {
43961.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
43971.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
43981.1Skamil
43991.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
44001.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
44011.1Skamil
44021.13Schristos		DPRINTF("Before exiting of the child process\n");
44031.1Skamil		_exit(exitval);
44041.1Skamil	}
44051.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
44061.1Skamil
44071.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
44081.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
44091.1Skamil
44101.1Skamil	validate_status_stopped(status, sigval);
44111.1Skamil
44121.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
44131.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
44141.1Skamil
44151.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
44161.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
44171.1Skamil
44181.13Schristos	DPRINTF("Before resuming the child process where it left off and "
44191.1Skamil	    "without signal to be sent\n");
44201.1Skamil	ATF_REQUIRE_ERRNO(EDEADLK,
44211.1Skamil	    ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
44221.1Skamil
44231.13Schristos	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
44241.13Schristos	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
44251.1Skamil
44261.13Schristos	DPRINTF("Before resuming the child process where it left off and "
44271.1Skamil	    "without signal to be sent\n");
44281.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
44291.1Skamil
44301.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
44311.1Skamil	    TWAIT_FNAME);
44321.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
44331.1Skamil
44341.1Skamil	validate_status_exited(status, exitval);
44351.1Skamil
44361.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
44371.1Skamil	    TWAIT_FNAME);
44381.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
44391.1Skamil}
44401.1Skamil
44411.154Skamil/// ----------------------------------------------------------------------------
44421.154Skamil
44431.155Skamilstatic pthread_barrier_t barrier1_resume;
44441.155Skamilstatic pthread_barrier_t barrier2_resume;
44451.154Skamil
44461.155Skamilstatic void *
44471.155Skamilresume_thread(void *arg)
44481.154Skamil{
44491.154Skamil
44501.155Skamil	raise(SIGUSR1);
44511.155Skamil
44521.155Skamil	pthread_barrier_wait(&barrier1_resume);
44531.155Skamil
44541.155Skamil	/* Debugger will suspend the process here */
44551.155Skamil
44561.155Skamil	pthread_barrier_wait(&barrier2_resume);
44571.154Skamil
44581.155Skamil	raise(SIGUSR2);
44591.155Skamil
44601.155Skamil	return infinite_thread(arg);
44611.154Skamil}
44621.154Skamil
44631.155SkamilATF_TC(resume);
44641.155SkamilATF_TC_HEAD(resume, tc)
44651.1Skamil{
44661.1Skamil	atf_tc_set_md_var(tc, "descr",
44671.1Skamil	    "Verify that a thread can be suspended by a debugger and later "
44681.1Skamil	    "resumed by the debugger");
44691.1Skamil}
44701.1Skamil
44711.155SkamilATF_TC_BODY(resume, tc)
44721.1Skamil{
44731.1Skamil	const int sigval = SIGSTOP;
44741.1Skamil	pid_t child, wpid;
44751.1Skamil#if defined(TWAIT_HAVE_STATUS)
44761.1Skamil	int status;
44771.1Skamil#endif
44781.1Skamil	lwpid_t lid;
44791.1Skamil	struct ptrace_siginfo psi;
44801.155Skamil	pthread_t t;
44811.1Skamil
44821.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
44831.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
44841.1Skamil	if (child == 0) {
44851.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
44861.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
44871.1Skamil
44881.155Skamil		pthread_barrier_init(&barrier1_resume, NULL, 2);
44891.155Skamil		pthread_barrier_init(&barrier2_resume, NULL, 2);
44901.155Skamil
44911.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
44921.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
44931.1Skamil
44941.155Skamil		DPRINTF("Before creating new thread in child\n");
44951.155Skamil		FORKEE_ASSERT(pthread_create(&t, NULL, resume_thread, NULL) == 0);
44961.1Skamil
44971.155Skamil		pthread_barrier_wait(&barrier1_resume);
44981.1Skamil
44991.155Skamil		pthread_barrier_wait(&barrier2_resume);
45001.1Skamil
45011.155Skamil		infinite_thread(NULL);
45021.1Skamil	}
45031.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
45041.1Skamil
45051.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
45061.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
45071.1Skamil
45081.1Skamil	validate_status_stopped(status, sigval);
45091.1Skamil
45101.13Schristos	DPRINTF("Before resuming the child process where it left off and "
45111.1Skamil	    "without signal to be sent\n");
45121.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
45131.1Skamil
45141.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
45151.155Skamil	    "SIGUSR1\n", TWAIT_FNAME);
45161.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
45171.1Skamil
45181.155Skamil	validate_status_stopped(status, SIGUSR1);
45191.1Skamil
45201.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
45211.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
45221.1Skamil
45231.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
45241.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
45251.1Skamil
45261.155Skamil	lid = psi.psi_lwpid;
45271.1Skamil
45281.13Schristos	DPRINTF("Before resuming the child process where it left off and "
45291.1Skamil	    "without signal to be sent\n");
45301.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
45311.1Skamil
45321.155Skamil	DPRINTF("Before suspending the parent for 1 second, we expect no signals\n");
45331.155Skamil	SYSCALL_REQUIRE(sleep(1) == 0);
45341.155Skamil
45351.155Skamil#if defined(TWAIT_HAVE_OPTIONS)
45361.155Skamil	DPRINTF("Before calling %s() for the child - expected no status\n",
45371.155Skamil	    TWAIT_FNAME);
45381.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, WNOHANG), 0);
45391.155Skamil#endif
45401.155Skamil
45411.155Skamil	DPRINTF("Before resuming the child process where it left off and "
45421.155Skamil	    "without signal to be sent\n");
45431.155Skamil	SYSCALL_REQUIRE(ptrace(PT_STOP, child, NULL, 0) != -1);
45441.155Skamil
45451.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
45461.155Skamil	    "SIGSTOP\n", TWAIT_FNAME);
45471.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
45481.1Skamil
45491.155Skamil	validate_status_stopped(status, SIGSTOP);
45501.1Skamil
45511.155Skamil	DPRINTF("Before resuming LWP %d\n", lid);
45521.155Skamil	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, lid) != -1);
45531.155Skamil
45541.155Skamil	DPRINTF("Before resuming the child process where it left off and "
45551.155Skamil	    "without signal to be sent\n");
45561.155Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
45571.1Skamil
45581.155Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
45591.155Skamil	    "SIGUSR2\n", TWAIT_FNAME);
45601.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
45611.1Skamil
45621.155Skamil	validate_status_stopped(status, SIGUSR2);
45631.1Skamil
45641.13Schristos	DPRINTF("Before resuming the child process where it left off and "
45651.1Skamil	    "without signal to be sent\n");
45661.155Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
45671.1Skamil
45681.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
45691.1Skamil	    TWAIT_FNAME);
45701.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
45711.1Skamil
45721.155Skamil	validate_status_signaled(status, SIGKILL, 0);
45731.1Skamil
45741.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
45751.1Skamil	    TWAIT_FNAME);
45761.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
45771.155Skamil}
45781.1Skamil
45791.155Skamil/// ----------------------------------------------------------------------------
45801.1Skamil
45811.106Skamilstatic void
45821.122Skamiluser_va0_disable(int operation)
45831.122Skamil{
45841.122Skamil	pid_t child, wpid;
45851.122Skamil#if defined(TWAIT_HAVE_STATUS)
45861.122Skamil	int status;
45871.122Skamil#endif
45881.122Skamil	const int sigval = SIGSTOP;
45891.122Skamil	int rv;
45901.122Skamil
45911.122Skamil	struct ptrace_siginfo info;
45921.122Skamil
45931.122Skamil	if (get_user_va0_disable() == 0)
45941.122Skamil		atf_tc_skip("vm.user_va0_disable is set to 0");
45951.122Skamil
45961.122Skamil	memset(&info, 0, sizeof(info));
45971.122Skamil
45981.122Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
45991.122Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
46001.122Skamil	if (child == 0) {
46011.122Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
46021.122Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
46031.122Skamil
46041.122Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
46051.122Skamil		FORKEE_ASSERT(raise(sigval) == 0);
46061.122Skamil
46071.122Skamil		/* NOTREACHED */
46081.122Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
46091.122Skamil		__unreachable();
46101.122Skamil	}
46111.122Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
46121.122Skamil
46131.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46141.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
46151.122Skamil
46161.122Skamil	validate_status_stopped(status, sigval);
46171.122Skamil
46181.122Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
46191.122Skamil		"child\n");
46201.122Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
46211.122Skamil		sizeof(info)) != -1);
46221.122Skamil
46231.122Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
46241.122Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
46251.122Skamil		"si_errno=%#x\n",
46261.122Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
46271.122Skamil		info.psi_siginfo.si_errno);
46281.122Skamil
46291.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
46301.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
46311.122Skamil
46321.122Skamil	DPRINTF("Before resuming the child process in PC=0x0 "
46331.122Skamil	    "and without signal to be sent\n");
46341.122Skamil	errno = 0;
46351.122Skamil	rv = ptrace(operation, child, (void *)0, 0);
46361.122Skamil	ATF_REQUIRE_EQ(errno, EINVAL);
46371.122Skamil	ATF_REQUIRE_EQ(rv, -1);
46381.122Skamil
46391.122Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
46401.122Skamil
46411.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46421.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
46431.122Skamil	validate_status_signaled(status, SIGKILL, 0);
46441.122Skamil
46451.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
46461.122Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
46471.122Skamil}
46481.122Skamil
46491.122Skamil#define USER_VA0_DISABLE(test, operation)				\
46501.122SkamilATF_TC(test);								\
46511.122SkamilATF_TC_HEAD(test, tc)							\
46521.122Skamil{									\
46531.122Skamil	atf_tc_set_md_var(tc, "descr",					\
46541.122Skamil	    "Verify behavior of " #operation " with PC set to 0x0");	\
46551.122Skamil}									\
46561.122Skamil									\
46571.122SkamilATF_TC_BODY(test, tc)							\
46581.122Skamil{									\
46591.122Skamil									\
46601.122Skamil	user_va0_disable(operation);					\
46611.122Skamil}
46621.122Skamil
46631.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_continue, PT_CONTINUE)
46641.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_syscall, PT_SYSCALL)
46651.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_detach, PT_DETACH)
46661.122Skamil
46671.122Skamil/// ----------------------------------------------------------------------------
46681.122Skamil
46691.130Smgorny/*
46701.130Smgorny * Parse the core file and find the requested note.  If the reading or parsing
46711.130Smgorny * fails, the test is failed.  If the note is found, it is read onto buf, up to
46721.130Smgorny * buf_len.  The actual length of the note is returned (which can be greater
46731.130Smgorny * than buf_len, indicating that it has been truncated).  If the note is not
46741.130Smgorny * found, -1 is returned.
46751.172Sthorpej *
46761.172Sthorpej * If the note_name ends in '*', then we find the first note that matches
46771.172Sthorpej * the note_name prefix up to the '*' character, e.g.:
46781.172Sthorpej *
46791.172Sthorpej *	NetBSD-CORE@*
46801.172Sthorpej *
46811.172Sthorpej * finds the first note whose name prefix matches "NetBSD-CORE@".
46821.130Smgorny */
46831.130Smgornystatic ssize_t core_find_note(const char *core_path,
46841.130Smgorny    const char *note_name, uint64_t note_type, void *buf, size_t buf_len)
46851.130Smgorny{
46861.130Smgorny	int core_fd;
46871.130Smgorny	Elf *core_elf;
46881.130Smgorny	size_t core_numhdr, i;
46891.130Smgorny	ssize_t ret = -1;
46901.172Sthorpej	size_t name_len = strlen(note_name);
46911.172Sthorpej	bool prefix_match = false;
46921.172Sthorpej
46931.172Sthorpej	if (note_name[name_len - 1] == '*') {
46941.172Sthorpej		prefix_match = true;
46951.172Sthorpej		name_len--;
46961.172Sthorpej	} else {
46971.172Sthorpej		/* note: we assume note name will be null-terminated */
46981.172Sthorpej		name_len++;
46991.172Sthorpej	}
47001.130Smgorny
47011.130Smgorny	SYSCALL_REQUIRE((core_fd = open(core_path, O_RDONLY)) != -1);
47021.130Smgorny	SYSCALL_REQUIRE(elf_version(EV_CURRENT) != EV_NONE);
47031.130Smgorny	SYSCALL_REQUIRE((core_elf = elf_begin(core_fd, ELF_C_READ, NULL)));
47041.130Smgorny
47051.130Smgorny	SYSCALL_REQUIRE(elf_getphnum(core_elf, &core_numhdr) != 0);
47061.130Smgorny	for (i = 0; i < core_numhdr && ret == -1; i++) {
47071.130Smgorny		GElf_Phdr core_hdr;
47081.130Smgorny		size_t offset;
47091.130Smgorny		SYSCALL_REQUIRE(gelf_getphdr(core_elf, i, &core_hdr));
47101.130Smgorny		if (core_hdr.p_type != PT_NOTE)
47111.130Smgorny		    continue;
47121.130Smgorny
47131.130Smgorny		for (offset = core_hdr.p_offset;
47141.130Smgorny		    offset < core_hdr.p_offset + core_hdr.p_filesz;) {
47151.130Smgorny			Elf64_Nhdr note_hdr;
47161.130Smgorny			char name_buf[64];
47171.130Smgorny
47181.130Smgorny			switch (gelf_getclass(core_elf)) {
47191.130Smgorny			case ELFCLASS64:
47201.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &note_hdr,
47211.130Smgorny				    sizeof(note_hdr), offset)
47221.130Smgorny				    == sizeof(note_hdr));
47231.130Smgorny				offset += sizeof(note_hdr);
47241.130Smgorny				break;
47251.130Smgorny			case ELFCLASS32:
47261.130Smgorny				{
47271.130Smgorny				Elf32_Nhdr tmp_hdr;
47281.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &tmp_hdr,
47291.130Smgorny				    sizeof(tmp_hdr), offset)
47301.130Smgorny				    == sizeof(tmp_hdr));
47311.130Smgorny				offset += sizeof(tmp_hdr);
47321.130Smgorny				note_hdr.n_namesz = tmp_hdr.n_namesz;
47331.130Smgorny				note_hdr.n_descsz = tmp_hdr.n_descsz;
47341.130Smgorny				note_hdr.n_type = tmp_hdr.n_type;
47351.130Smgorny				}
47361.130Smgorny				break;
47371.130Smgorny			}
47381.130Smgorny
47391.130Smgorny			/* indicates end of notes */
47401.130Smgorny			if (note_hdr.n_namesz == 0 || note_hdr.n_descsz == 0)
47411.130Smgorny				break;
47421.172Sthorpej			if (((prefix_match &&
47431.172Sthorpej			      note_hdr.n_namesz > name_len) ||
47441.172Sthorpej			     (!prefix_match &&
47451.172Sthorpej			      note_hdr.n_namesz == name_len)) &&
47461.130Smgorny			    note_hdr.n_namesz <= sizeof(name_buf)) {
47471.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, name_buf,
47481.130Smgorny				    note_hdr.n_namesz, offset)
47491.131Skamil				    == (ssize_t)(size_t)note_hdr.n_namesz);
47501.130Smgorny
47511.130Smgorny				if (!strncmp(note_name, name_buf, name_len) &&
47521.130Smgorny				    note_hdr.n_type == note_type)
47531.130Smgorny					ret = note_hdr.n_descsz;
47541.130Smgorny			}
47551.130Smgorny
47561.130Smgorny			offset += note_hdr.n_namesz;
47571.130Smgorny			/* fix to alignment */
47581.146Smgorny			offset = roundup(offset, core_hdr.p_align);
47591.130Smgorny
47601.130Smgorny			/* if name & type matched above */
47611.130Smgorny			if (ret != -1) {
47621.130Smgorny				ssize_t read_len = MIN(buf_len,
47631.130Smgorny				    note_hdr.n_descsz);
47641.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, buf,
47651.130Smgorny				    read_len, offset) == read_len);
47661.130Smgorny				break;
47671.130Smgorny			}
47681.130Smgorny
47691.130Smgorny			offset += note_hdr.n_descsz;
47701.146Smgorny			/* fix to alignment */
47711.146Smgorny			offset = roundup(offset, core_hdr.p_align);
47721.130Smgorny		}
47731.130Smgorny	}
47741.130Smgorny
47751.130Smgorny	elf_end(core_elf);
47761.130Smgorny	close(core_fd);
47771.130Smgorny
47781.130Smgorny	return ret;
47791.130Smgorny}
47801.130Smgorny
47811.130SmgornyATF_TC(core_dump_procinfo);
47821.130SmgornyATF_TC_HEAD(core_dump_procinfo, tc)
47831.130Smgorny{
47841.130Smgorny	atf_tc_set_md_var(tc, "descr",
47851.130Smgorny		"Trigger a core dump and verify its contents.");
47861.130Smgorny}
47871.130Smgorny
47881.130SmgornyATF_TC_BODY(core_dump_procinfo, tc)
47891.130Smgorny{
47901.130Smgorny	const int exitval = 5;
47911.130Smgorny	pid_t child, wpid;
47921.130Smgorny#if defined(TWAIT_HAVE_STATUS)
47931.130Smgorny	const int sigval = SIGTRAP;
47941.130Smgorny	int status;
47951.130Smgorny#endif
47961.130Smgorny	char core_path[] = "/tmp/core.XXXXXX";
47971.130Smgorny	int core_fd;
47981.130Smgorny	struct netbsd_elfcore_procinfo procinfo;
47991.130Smgorny
48001.130Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
48011.130Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
48021.130Smgorny	if (child == 0) {
48031.130Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
48041.130Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
48051.130Smgorny
48061.130Smgorny		DPRINTF("Before triggering SIGTRAP\n");
48071.130Smgorny		trigger_trap();
48081.130Smgorny
48091.130Smgorny		DPRINTF("Before exiting of the child process\n");
48101.130Smgorny		_exit(exitval);
48111.130Smgorny	}
48121.130Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
48131.130Smgorny
48141.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48151.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
48161.130Smgorny
48171.130Smgorny	validate_status_stopped(status, sigval);
48181.130Smgorny
48191.130Smgorny	SYSCALL_REQUIRE((core_fd = mkstemp(core_path)) != -1);
48201.130Smgorny	close(core_fd);
48211.130Smgorny
48221.130Smgorny	DPRINTF("Call DUMPCORE for the child process\n");
48231.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_DUMPCORE, child, core_path, strlen(core_path))
48241.130Smgorny	    != -1);
48251.130Smgorny
48261.130Smgorny	DPRINTF("Read core file\n");
48271.130Smgorny	ATF_REQUIRE_EQ(core_find_note(core_path, "NetBSD-CORE",
48281.130Smgorny	    ELF_NOTE_NETBSD_CORE_PROCINFO, &procinfo, sizeof(procinfo)),
48291.130Smgorny	    sizeof(procinfo));
48301.130Smgorny
48311.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_version, 1);
48321.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_cpisize, sizeof(procinfo));
48331.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_signo, SIGTRAP);
48341.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pid, child);
48351.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ppid, getpid());
48361.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pgrp, getpgid(child));
48371.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_sid, getsid(child));
48381.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ruid, getuid());
48391.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_euid, geteuid());
48401.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_rgid, getgid());
48411.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_egid, getegid());
48421.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_nlwps, 1);
48431.173Skamil	ATF_CHECK(procinfo.cpi_siglwp > 0);
48441.130Smgorny
48451.130Smgorny	unlink(core_path);
48461.130Smgorny
48471.130Smgorny	DPRINTF("Before resuming the child process where it left off and "
48481.130Smgorny	    "without signal to be sent\n");
48491.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
48501.130Smgorny
48511.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48521.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
48531.130Smgorny
48541.130Smgorny	validate_status_exited(status, exitval);
48551.130Smgorny
48561.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
48571.130Smgorny	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
48581.130Smgorny}
48591.130Smgorny
48601.130Smgorny/// ----------------------------------------------------------------------------
48611.130Smgorny
48621.138Smgorny#if defined(TWAIT_HAVE_STATUS)
48631.138Smgorny
48641.160Smgorny#define THREAD_CONCURRENT_BREAKPOINT_NUM 50
48651.156Smgorny#define THREAD_CONCURRENT_SIGNALS_NUM 50
48661.161Smgorny#define THREAD_CONCURRENT_WATCHPOINT_NUM 50
48671.138Smgorny
48681.138Smgorny/* List of signals to use for the test */
48691.138Smgornyconst int thread_concurrent_signals_list[] = {
48701.138Smgorny	SIGIO,
48711.138Smgorny	SIGXCPU,
48721.138Smgorny	SIGXFSZ,
48731.138Smgorny	SIGVTALRM,
48741.138Smgorny	SIGPROF,
48751.138Smgorny	SIGWINCH,
48761.138Smgorny	SIGINFO,
48771.138Smgorny	SIGUSR1,
48781.138Smgorny	SIGUSR2
48791.138Smgorny};
48801.138Smgorny
48811.157Smgornyenum thread_concurrent_signal_handling {
48821.157Smgorny	/* the signal is discarded by debugger */
48831.157Smgorny	TCSH_DISCARD,
48841.157Smgorny	/* the handler is set to SIG_IGN */
48851.157Smgorny	TCSH_SIG_IGN,
48861.157Smgorny	/* an actual handler is used */
48871.157Smgorny	TCSH_HANDLER
48881.157Smgorny};
48891.157Smgorny
48901.156Smgornystatic pthread_barrier_t thread_concurrent_barrier;
48911.158Smgornystatic pthread_key_t thread_concurrent_key;
48921.161Smgornystatic uint32_t thread_concurrent_watchpoint_var = 0;
48931.138Smgorny
48941.160Smgornystatic void *
48951.160Smgornythread_concurrent_breakpoint_thread(void *arg)
48961.160Smgorny{
48971.160Smgorny	static volatile int watchme = 1;
48981.160Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
48991.160Smgorny	DPRINTF("Before entering breakpoint func from LWP %d\n", _lwp_self());
49001.160Smgorny	check_happy(watchme);
49011.160Smgorny	return NULL;
49021.160Smgorny}
49031.160Smgorny
49041.157Smgornystatic void
49051.157Smgornythread_concurrent_sig_handler(int sig)
49061.157Smgorny{
49071.158Smgorny	void *tls_val = pthread_getspecific(thread_concurrent_key);
49081.158Smgorny	DPRINTF("Before increment, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
49091.158Smgorny	FORKEE_ASSERT(pthread_setspecific(thread_concurrent_key,
49101.158Smgorny	    (void*)((uintptr_t)tls_val + 1)) == 0);
49111.157Smgorny}
49121.157Smgorny
49131.138Smgornystatic void *
49141.138Smgornythread_concurrent_signals_thread(void *arg)
49151.138Smgorny{
49161.138Smgorny	int sigval = thread_concurrent_signals_list[
49171.138Smgorny	    _lwp_self() % __arraycount(thread_concurrent_signals_list)];
49181.158Smgorny	enum thread_concurrent_signal_handling *signal_handle = arg;
49191.158Smgorny	void *tls_val;
49201.158Smgorny
49211.156Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
49221.138Smgorny	DPRINTF("Before raising %s from LWP %d\n", strsignal(sigval),
49231.138Smgorny		_lwp_self());
49241.138Smgorny	pthread_kill(pthread_self(), sigval);
49251.158Smgorny	if (*signal_handle == TCSH_HANDLER) {
49261.158Smgorny	    tls_val = pthread_getspecific(thread_concurrent_key);
49271.158Smgorny	    DPRINTF("After raising, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
49281.158Smgorny	    FORKEE_ASSERT(tls_val == (void*)1);
49291.158Smgorny	}
49301.138Smgorny	return NULL;
49311.138Smgorny}
49321.138Smgorny
49331.161Smgornystatic void *
49341.161Smgornythread_concurrent_watchpoint_thread(void *arg)
49351.161Smgorny{
49361.161Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
49371.161Smgorny	DPRINTF("Before modifying var from LWP %d\n", _lwp_self());
49381.161Smgorny	thread_concurrent_watchpoint_var = 1;
49391.161Smgorny	return NULL;
49401.161Smgorny}
49411.161Smgorny
49421.160Smgorny#if defined(__i386__) || defined(__x86_64__)
49431.160Smgornyenum thread_concurrent_sigtrap_event {
49441.160Smgorny	TCSE_UNKNOWN,
49451.161Smgorny	TCSE_BREAKPOINT,
49461.161Smgorny	TCSE_WATCHPOINT
49471.160Smgorny};
49481.160Smgorny
49491.160Smgornystatic void
49501.160Smgornythread_concurrent_lwp_setup(pid_t child, lwpid_t lwpid);
49511.160Smgornystatic enum thread_concurrent_sigtrap_event
49521.160Smgornythread_concurrent_handle_sigtrap(pid_t child, ptrace_siginfo_t *info);
49531.160Smgorny#endif
49541.160Smgorny
49551.156Smgornystatic void
49561.157Smgornythread_concurrent_test(enum thread_concurrent_signal_handling signal_handle,
49571.161Smgorny    int breakpoint_threads, int signal_threads, int watchpoint_threads)
49581.138Smgorny{
49591.138Smgorny	const int exitval = 5;
49601.138Smgorny	const int sigval = SIGSTOP;
49611.138Smgorny	pid_t child, wpid;
49621.138Smgorny	int status;
49631.141Skamil	struct lwp_event_count signal_counts[THREAD_CONCURRENT_SIGNALS_NUM]
49641.141Skamil	    = {{0, 0}};
49651.160Smgorny	struct lwp_event_count bp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
49661.160Smgorny	    = {{0, 0}};
49671.161Smgorny	struct lwp_event_count wp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
49681.161Smgorny	    = {{0, 0}};
49691.159Smgorny	ptrace_event_t event;
49701.156Smgorny	int i;
49711.156Smgorny
49721.164Skamil#if defined(HAVE_DBREGS)
49731.164Skamil	if (!can_we_set_dbregs()) {
49741.164Skamil		atf_tc_skip("Either run this test as root or set sysctl(3) "
49751.164Skamil		            "security.models.extensions.user_set_dbregs to 1");
49761.164Skamil        }
49771.164Skamil#endif
49781.164Skamil
49791.164Skamil	atf_tc_skip("PR kern/54960");
49801.157Smgorny
49811.156Smgorny	/* Protect against out-of-bounds array access. */
49821.160Smgorny	ATF_REQUIRE(breakpoint_threads <= THREAD_CONCURRENT_BREAKPOINT_NUM);
49831.156Smgorny	ATF_REQUIRE(signal_threads <= THREAD_CONCURRENT_SIGNALS_NUM);
49841.161Smgorny	ATF_REQUIRE(watchpoint_threads <= THREAD_CONCURRENT_WATCHPOINT_NUM);
49851.138Smgorny
49861.138Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
49871.138Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
49881.138Smgorny	if (child == 0) {
49891.160Smgorny		pthread_t bp_threads[THREAD_CONCURRENT_BREAKPOINT_NUM];
49901.156Smgorny		pthread_t sig_threads[THREAD_CONCURRENT_SIGNALS_NUM];
49911.161Smgorny		pthread_t wp_threads[THREAD_CONCURRENT_WATCHPOINT_NUM];
49921.138Smgorny
49931.138Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
49941.138Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
49951.138Smgorny
49961.138Smgorny		DPRINTF("Before raising %s from child\n", strsignal(sigval));
49971.138Smgorny		FORKEE_ASSERT(raise(sigval) == 0);
49981.138Smgorny
49991.157Smgorny		if (signal_handle != TCSH_DISCARD) {
50001.157Smgorny			struct sigaction sa;
50011.157Smgorny			unsigned int j;
50021.157Smgorny
50031.157Smgorny			memset(&sa, 0, sizeof(sa));
50041.157Smgorny			if (signal_handle == TCSH_SIG_IGN)
50051.157Smgorny				sa.sa_handler = SIG_IGN;
50061.157Smgorny			else
50071.157Smgorny				sa.sa_handler = thread_concurrent_sig_handler;
50081.157Smgorny			sigemptyset(&sa.sa_mask);
50091.157Smgorny
50101.157Smgorny			for (j = 0;
50111.157Smgorny			    j < __arraycount(thread_concurrent_signals_list);
50121.157Smgorny			    j++)
50131.157Smgorny				FORKEE_ASSERT(sigaction(
50141.157Smgorny				    thread_concurrent_signals_list[j], &sa, NULL)
50151.157Smgorny				    != -1);
50161.157Smgorny		}
50171.157Smgorny
50181.138Smgorny		DPRINTF("Before starting threads from the child\n");
50191.138Smgorny		FORKEE_ASSERT(pthread_barrier_init(
50201.156Smgorny		    &thread_concurrent_barrier, NULL,
50211.161Smgorny		    breakpoint_threads + signal_threads + watchpoint_threads)
50221.161Smgorny		    == 0);
50231.158Smgorny		FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL)
50241.158Smgorny		    == 0);
50251.138Smgorny
50261.156Smgorny		for (i = 0; i < signal_threads; i++) {
50271.156Smgorny			FORKEE_ASSERT(pthread_create(&sig_threads[i], NULL,
50281.158Smgorny			    thread_concurrent_signals_thread,
50291.158Smgorny			    &signal_handle) == 0);
50301.138Smgorny		}
50311.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
50321.160Smgorny			FORKEE_ASSERT(pthread_create(&bp_threads[i], NULL,
50331.160Smgorny			    thread_concurrent_breakpoint_thread, NULL) == 0);
50341.160Smgorny		}
50351.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
50361.161Smgorny			FORKEE_ASSERT(pthread_create(&wp_threads[i], NULL,
50371.161Smgorny			    thread_concurrent_watchpoint_thread, NULL) == 0);
50381.161Smgorny		}
50391.138Smgorny
50401.138Smgorny		DPRINTF("Before joining threads from the child\n");
50411.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
50421.161Smgorny			FORKEE_ASSERT(pthread_join(wp_threads[i], NULL) == 0);
50431.161Smgorny		}
50441.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
50451.160Smgorny			FORKEE_ASSERT(pthread_join(bp_threads[i], NULL) == 0);
50461.160Smgorny		}
50471.156Smgorny		for (i = 0; i < signal_threads; i++) {
50481.156Smgorny			FORKEE_ASSERT(pthread_join(sig_threads[i], NULL) == 0);
50491.138Smgorny		}
50501.138Smgorny
50511.158Smgorny		FORKEE_ASSERT(pthread_key_delete(thread_concurrent_key) == 0);
50521.138Smgorny		FORKEE_ASSERT(pthread_barrier_destroy(
50531.156Smgorny		    &thread_concurrent_barrier) == 0);
50541.138Smgorny
50551.138Smgorny		DPRINTF("Before exiting of the child process\n");
50561.138Smgorny		_exit(exitval);
50571.138Smgorny	}
50581.138Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
50591.138Smgorny
50601.138Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
50611.138Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
50621.138Smgorny
50631.138Smgorny	validate_status_stopped(status, sigval);
50641.138Smgorny
50651.159Smgorny	DPRINTF("Set LWP event mask for the child process\n");
50661.159Smgorny	memset(&event, 0, sizeof(event));
50671.159Smgorny	event.pe_set_event |= PTRACE_LWP_CREATE;
50681.159Smgorny	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, sizeof(event))
50691.159Smgorny	    != -1);
50701.159Smgorny
50711.138Smgorny	DPRINTF("Before resuming the child process where it left off\n");
50721.138Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
50731.138Smgorny
50741.138Smgorny	DPRINTF("Before entering signal collection loop\n");
50751.138Smgorny	while (1) {
50761.138Smgorny		ptrace_siginfo_t info;
50771.138Smgorny
50781.138Smgorny		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
50791.138Smgorny		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
50801.138Smgorny		    child);
50811.138Smgorny		if (WIFEXITED(status))
50821.138Smgorny			break;
50831.138Smgorny		/* Note: we use validate_status_stopped() to get nice error
50841.138Smgorny		 * message.  Signal is irrelevant since it won't be reached.
50851.138Smgorny		 */
50861.138Smgorny		else if (!WIFSTOPPED(status))
50871.138Smgorny			validate_status_stopped(status, 0);
50881.138Smgorny
50891.138Smgorny		DPRINTF("Before calling PT_GET_SIGINFO\n");
50901.138Smgorny		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
50911.138Smgorny		    sizeof(info)) != -1);
50921.138Smgorny
50931.138Smgorny		DPRINTF("Received signal %d from LWP %d (wait: %d)\n",
50941.138Smgorny		    info.psi_siginfo.si_signo, info.psi_lwpid,
50951.138Smgorny		    WSTOPSIG(status));
50961.138Smgorny
50971.159Smgorny		ATF_CHECK_EQ_MSG(info.psi_siginfo.si_signo, WSTOPSIG(status),
50981.159Smgorny		    "lwp=%d, WSTOPSIG=%d, psi_siginfo=%d", info.psi_lwpid,
50991.159Smgorny		    WSTOPSIG(status), info.psi_siginfo.si_signo);
51001.159Smgorny
51011.159Smgorny		if (WSTOPSIG(status) != SIGTRAP) {
51021.159Smgorny			int expected_sig =
51031.159Smgorny			    thread_concurrent_signals_list[info.psi_lwpid %
51041.159Smgorny			    __arraycount(thread_concurrent_signals_list)];
51051.159Smgorny			ATF_CHECK_EQ_MSG(WSTOPSIG(status), expected_sig,
51061.159Smgorny				"lwp=%d, expected %d, got %d", info.psi_lwpid,
51071.159Smgorny				expected_sig, WSTOPSIG(status));
51081.138Smgorny
51091.159Smgorny			*FIND_EVENT_COUNT(signal_counts, info.psi_lwpid) += 1;
51101.160Smgorny		} else if (info.psi_siginfo.si_code == TRAP_LWP) {
51111.160Smgorny#if defined(__i386__) || defined(__x86_64__)
51121.160Smgorny			thread_concurrent_lwp_setup(child, info.psi_lwpid);
51131.160Smgorny#endif
51141.159Smgorny		} else {
51151.160Smgorny#if defined(__i386__) || defined(__x86_64__)
51161.160Smgorny			switch (thread_concurrent_handle_sigtrap(child, &info)) {
51171.160Smgorny				case TCSE_UNKNOWN:
51181.160Smgorny					/* already reported inside the function */
51191.160Smgorny					break;
51201.160Smgorny				case TCSE_BREAKPOINT:
51211.160Smgorny					*FIND_EVENT_COUNT(bp_counts,
51221.160Smgorny					    info.psi_lwpid) += 1;
51231.160Smgorny					break;
51241.161Smgorny				case TCSE_WATCHPOINT:
51251.161Smgorny					*FIND_EVENT_COUNT(wp_counts,
51261.161Smgorny					    info.psi_lwpid) += 1;
51271.161Smgorny					break;
51281.160Smgorny			}
51291.160Smgorny#else
51301.160Smgorny			ATF_CHECK_MSG(0, "Unexpected SIGTRAP, si_code=%d\n",
51311.160Smgorny			    info.psi_siginfo.si_code);
51321.160Smgorny#endif
51331.159Smgorny		}
51341.138Smgorny
51351.138Smgorny		DPRINTF("Before resuming the child process\n");
51361.157Smgorny		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
51371.159Smgorny		     signal_handle != TCSH_DISCARD && WSTOPSIG(status) != SIGTRAP
51381.159Smgorny		     ? WSTOPSIG(status) : 0) != -1);
51391.138Smgorny	}
51401.138Smgorny
51411.156Smgorny	for (i = 0; i < signal_threads; i++)
51421.141Skamil		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 1,
51431.141Skamil		    "signal_counts[%d].lec_count=%d; lec_lwp=%d",
51441.141Skamil		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
51451.156Smgorny	for (i = signal_threads; i < THREAD_CONCURRENT_SIGNALS_NUM; i++)
51461.156Smgorny		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 0,
51471.156Smgorny		    "extraneous signal_counts[%d].lec_count=%d; lec_lwp=%d",
51481.156Smgorny		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
51491.138Smgorny
51501.160Smgorny	for (i = 0; i < breakpoint_threads; i++)
51511.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 1,
51521.160Smgorny		    "bp_counts[%d].lec_count=%d; lec_lwp=%d",
51531.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
51541.160Smgorny	for (i = breakpoint_threads; i < THREAD_CONCURRENT_BREAKPOINT_NUM; i++)
51551.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 0,
51561.160Smgorny		    "extraneous bp_counts[%d].lec_count=%d; lec_lwp=%d",
51571.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
51581.160Smgorny
51591.161Smgorny	for (i = 0; i < watchpoint_threads; i++)
51601.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 1,
51611.161Smgorny		    "wp_counts[%d].lec_count=%d; lec_lwp=%d",
51621.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
51631.161Smgorny	for (i = watchpoint_threads; i < THREAD_CONCURRENT_WATCHPOINT_NUM; i++)
51641.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 0,
51651.161Smgorny		    "extraneous wp_counts[%d].lec_count=%d; lec_lwp=%d",
51661.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
51671.161Smgorny
51681.138Smgorny	validate_status_exited(status, exitval);
51691.138Smgorny}
51701.138Smgorny
51711.161Smgorny#define THREAD_CONCURRENT_TEST(test, sig_hdl, bps, sigs, wps, descr)	\
51721.156SmgornyATF_TC(test);								\
51731.156SmgornyATF_TC_HEAD(test, tc)							\
51741.156Smgorny{									\
51751.156Smgorny	atf_tc_set_md_var(tc, "descr", descr);				\
51761.156Smgorny}									\
51771.156Smgorny									\
51781.156SmgornyATF_TC_BODY(test, tc)							\
51791.156Smgorny{									\
51801.161Smgorny	thread_concurrent_test(sig_hdl, bps, sigs, wps);		\
51811.156Smgorny}
51821.156Smgorny
51831.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals, TCSH_DISCARD,
51841.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
51851.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
51861.157Smgorny    "correctly");
51871.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_sig_ign, TCSH_SIG_IGN,
51881.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
51891.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
51901.157Smgorny    "correctly and passed back to SIG_IGN handler");
51911.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_handler, TCSH_HANDLER,
51921.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
51931.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
51941.157Smgorny    "correctly and passed back to a handler function");
51951.156Smgorny
51961.163Skamil#if defined(__i386__) || defined(__x86_64__)
51971.160SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_breakpoints, TCSH_DISCARD,
51981.161Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, 0,
51991.161Smgorny    "Verify that concurrent breakpoints are reported correctly");
52001.161SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_watchpoints, TCSH_DISCARD,
52011.161Smgorny    0, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
52021.160Smgorny    "Verify that concurrent breakpoints are reported correctly");
52031.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp, TCSH_DISCARD,
52041.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
52051.162Smgorny    "Verify that concurrent breakpoints and watchpoints are reported "
52061.162Smgorny    "correctly");
52071.162Smgorny
52081.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig, TCSH_DISCARD,
52091.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
52101.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly");
52111.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_sig_ign, TCSH_SIG_IGN,
52121.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
52131.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
52141.162Smgorny    "and passed back to SIG_IGN handler");
52151.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_handler, TCSH_HANDLER,
52161.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
52171.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
52181.162Smgorny    "and passed back to a handler function");
52191.162Smgorny
52201.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig, TCSH_DISCARD,
52211.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
52221.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly");
52231.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_sig_ign, TCSH_SIG_IGN,
52241.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
52251.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
52261.162Smgorny    "and passed back to SIG_IGN handler");
52271.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_handler, TCSH_HANDLER,
52281.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
52291.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
52301.162Smgorny    "and passed back to a handler function");
52311.162Smgorny
52321.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig, TCSH_DISCARD,
52331.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
52341.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
52351.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
52361.162Smgorny    "correctly");
52371.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_sig_ign, TCSH_SIG_IGN,
52381.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
52391.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
52401.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
52411.162Smgorny    "correctly and passed back to SIG_IGN handler");
52421.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_handler, TCSH_HANDLER,
52431.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
52441.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
52451.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
52461.162Smgorny    "correctly and passed back to a handler function");
52471.163Skamil#endif
52481.160Smgorny
52491.138Smgorny#endif /*defined(TWAIT_HAVE_STATUS)*/
52501.138Smgorny
52511.138Smgorny/// ----------------------------------------------------------------------------
52521.138Smgorny
52531.174Skamil#include "t_ptrace_register_wait.h"
52541.175Skamil#include "t_ptrace_syscall_wait.h"
52551.176Skamil#include "t_ptrace_step_wait.h"
52561.177Skamil#include "t_ptrace_kill_wait.h"
52571.178Skamil#include "t_ptrace_bytetransfer_wait.h"
52581.179Skamil#include "t_ptrace_clone_wait.h"
52591.180Skamil#include "t_ptrace_fork_wait.h"
52601.174Skamil
52611.174Skamil/// ----------------------------------------------------------------------------
52621.174Skamil
52631.1Skamil#include "t_ptrace_amd64_wait.h"
52641.1Skamil#include "t_ptrace_i386_wait.h"
52651.1Skamil#include "t_ptrace_x86_wait.h"
52661.1Skamil
52671.165Skamil/// ----------------------------------------------------------------------------
52681.165Skamil
52691.165Skamil#else
52701.165SkamilATF_TC(dummy);
52711.165SkamilATF_TC_HEAD(dummy, tc)
52721.165Skamil{
52731.165Skamil	atf_tc_set_md_var(tc, "descr", "A dummy test");
52741.165Skamil}
52751.165Skamil
52761.165SkamilATF_TC_BODY(dummy, tc)
52771.165Skamil{
52781.165Skamil
52791.165Skamil	// Dummy, skipped
52801.165Skamil	// The ATF framework requires at least a single defined test.
52811.165Skamil}
52821.165Skamil#endif
52831.165Skamil
52841.1SkamilATF_TP_ADD_TCS(tp)
52851.1Skamil{
52861.1Skamil	setvbuf(stdout, NULL, _IONBF, 0);
52871.1Skamil	setvbuf(stderr, NULL, _IONBF, 0);
52881.33Skamil
52891.165Skamil#ifdef ENABLE_TESTS
52901.36Skamil	ATF_TP_ADD_TC(tp, traceme_raise1);
52911.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise2);
52921.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise3);
52931.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise4);
52941.33Skamil	ATF_TP_ADD_TC(tp, traceme_raise5);
52951.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise6);
52961.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise7);
52971.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise8);
52981.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise9);
52991.85Skamil	ATF_TP_ADD_TC(tp, traceme_raise10);
53001.33Skamil
53011.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored1);
53021.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored2);
53031.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored3);
53041.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored4);
53051.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored5);
53061.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored6);
53071.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored7);
53081.87Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_ignored8);
53091.87Skamil
53101.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked1);
53111.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked2);
53121.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked3);
53131.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked4);
53141.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked5);
53151.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked6);
53161.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked7);
53171.86Skamil	ATF_TP_ADD_TC(tp, traceme_raisesignal_masked8);
53181.86Skamil
53191.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_trap);
53201.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_segv);
53211.71Skamil	ATF_TP_ADD_TC(tp, traceme_crash_ill);
53221.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_fpe);
53231.59Skamil	ATF_TP_ADD_TC(tp, traceme_crash_bus);
53241.59Skamil
53251.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_trap);
53261.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_segv);
53271.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_ill);
53281.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_fpe);
53291.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_crash_bus);
53301.88Skamil
53311.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_trap);
53321.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_segv);
53331.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_ill);
53341.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_fpe);
53351.88Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_crash_bus);
53361.88Skamil
53371.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle1);
53381.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle2);
53391.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle3);
53401.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle4);
53411.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle5);
53421.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle6);
53431.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle7);
53441.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_handle8);
53451.50Skamil
53461.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked1);
53471.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked2);
53481.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked3);
53491.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked4);
53501.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked5);
53511.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked6);
53521.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked7);
53531.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_masked8);
53541.50Skamil
53551.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored1);
53561.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored2);
53571.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored3);
53581.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored4);
53591.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored5);
53601.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored6);
53611.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored7);
53621.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_ignored8);
53631.50Skamil
53641.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple1);
53651.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple2);
53661.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple3);
53671.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple4);
53681.50Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple5);
53691.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple6);
53701.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple7);
53711.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple8);
53721.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple9);
53731.85Skamil	ATF_TP_ADD_TC(tp, traceme_sendsignal_simple10);
53741.1Skamil
53751.37Skamil	ATF_TP_ADD_TC(tp, traceme_pid1_parent);
53761.37Skamil
53771.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise1);
53781.46Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise2);
53791.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise3);
53801.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise4);
53811.40Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise5);
53821.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise6);
53831.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise7);
53841.47Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise8);
53851.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise9);
53861.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise10);
53871.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise11);
53881.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise12);
53891.85Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_raise13);
53901.40Skamil
53911.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_trap);
53921.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_segv);
53931.71Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_ill);
53941.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_fpe);
53951.52Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_crash_bus);
53961.41Skamil
53971.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_trap);
53981.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_segv);
53991.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_ill);
54001.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_fpe);
54011.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_crash_bus);
54021.92Skamil
54031.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_trap);
54041.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_segv);
54051.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_ill);
54061.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_fpe);
54071.92Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_crash_bus);
54081.92Skamil
54091.43Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_exec);
54101.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_exec);
54111.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_exec);
54121.43Skamil
54131.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_trap);
54141.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_segv);
54151.71Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_ill);
54161.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_fpe);
54171.59Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, unrelated_tracer_sees_crash_bus);
54181.59Skamil
54191.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
54201.94Skamil	    unrelated_tracer_sees_signalmasked_crash_trap);
54211.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
54221.94Skamil	    unrelated_tracer_sees_signalmasked_crash_segv);
54231.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
54241.94Skamil	    unrelated_tracer_sees_signalmasked_crash_ill);
54251.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
54261.94Skamil	    unrelated_tracer_sees_signalmasked_crash_fpe);
54271.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
54281.94Skamil	    unrelated_tracer_sees_signalmasked_crash_bus);
54291.94Skamil
54301.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
54311.94Skamil	    unrelated_tracer_sees_signalignored_crash_trap);
54321.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
54331.94Skamil	    unrelated_tracer_sees_signalignored_crash_segv);
54341.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
54351.94Skamil	    unrelated_tracer_sees_signalignored_crash_ill);
54361.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
54371.94Skamil	    unrelated_tracer_sees_signalignored_crash_fpe);
54381.94Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
54391.94Skamil	    unrelated_tracer_sees_signalignored_crash_bus);
54401.94Skamil
54411.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sees_terminaton_before_the_parent);
54421.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sysctl_lookup_without_duplicates);
54431.61Skre	ATF_TP_ADD_TC_HAVE_PID(tp,
54441.61Skre		unrelated_tracer_sees_terminaton_before_the_parent);
54451.67Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_attach_to_unrelated_stopped_process);
54461.51Skamil
54471.51Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_child);
54481.66Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_stopped_child);
54491.51Skamil
54501.51Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_parent);
54511.65Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_stopped_parent);
54521.51Skamil
54531.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
54541.51Skamil		tracee_sees_its_original_parent_getppid);
54551.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
54561.51Skamil		tracee_sees_its_original_parent_sysctl_kinfo_proc2);
54571.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
54581.51Skamil		tracee_sees_its_original_parent_procfs_status);
54591.1Skamil
54601.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_empty);
54611.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_fork);
54621.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork);
54631.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_vfork_done);
54641.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_create);
54651.53Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_lwp_exit);
54661.125Skamil	ATF_TP_ADD_TC(tp, eventmask_preserved_posix_spawn);
54671.1Skamil
54681.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8);
54691.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16);
54701.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32);
54711.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64);
54721.54Skamil
54731.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8);
54741.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16);
54751.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32);
54761.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64);
54771.54Skamil
54781.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8);
54791.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16);
54801.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32);
54811.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64);
54821.54Skamil
54831.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8);
54841.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16);
54851.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32);
54861.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64);
54871.54Skamil
54881.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d);
54891.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i);
54901.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d);
54911.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i);
54921.54Skamil
54931.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8_text);
54941.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16_text);
54951.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_32_text);
54961.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_64_text);
54971.54Skamil
54981.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_8_text);
54991.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_16_text);
55001.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_32_text);
55011.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_i_64_text);
55021.54Skamil
55031.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_8_text);
55041.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_16_text);
55051.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_32_text);
55061.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_d_64_text);
55071.54Skamil
55081.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_8_text);
55091.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_16_text);
55101.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_32_text);
55111.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_write_i_64_text);
55121.54Skamil
55131.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_d_text);
55141.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_read_i_text);
55151.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_d_text);
55161.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_write_i_text);
55171.1Skamil
55181.54Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_auxv);
55191.1Skamil
55201.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_i);
55211.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_read_d);
55221.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_i);
55231.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_pt_write_d);
55241.101Skamil
55251.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_i);
55261.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_d);
55271.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_i);
55281.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_write_d);
55291.101Skamil
55301.101Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_alignment_piod_read_auxv);
55311.101Skamil
55321.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_i);
55331.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_read_d);
55341.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_i);
55351.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_pt_write_d);
55361.115Skamil
55371.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_i);
55381.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_read_d);
55391.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_i);
55401.115Skamil	ATF_TP_ADD_TC(tp, bytes_transfer_eof_piod_write_d);
55411.115Skamil
55421.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0);
55431.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1);
55441.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2);
55451.77Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3);
55461.77Skamil
55471.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus);
55481.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus);
55491.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus);
55501.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus);
55511.143Skamil
55521.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_sigmask);
55531.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_sigmask);
55541.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_sigmask);
55551.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_sigmask);
55561.143Skamil
55571.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_name);
55581.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_name);
55591.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_name);
55601.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_name);
55611.143Skamil
55621.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo0_lwpstatus_pl_private);
55631.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo1_lwpstatus_pl_private);
55641.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo2_lwpstatus_pl_private);
55651.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpinfo3_lwpstatus_pl_private);
55661.143Skamil
55671.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0);
55681.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1);
55691.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2);
55701.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3);
55711.143Skamil
55721.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_sigmask);
55731.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_sigmask);
55741.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_sigmask);
55751.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_sigmask);
55761.143Skamil
55771.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_name);
55781.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_name);
55791.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_name);
55801.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_name);
55811.143Skamil
55821.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext0_pl_private);
55831.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext1_pl_private);
55841.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext2_pl_private);
55851.143Skamil	ATF_TP_ADD_TC(tp, traceme_lwpnext3_pl_private);
55861.143Skamil
55871.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo0);
55881.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo1);
55891.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo2);
55901.77Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, attach_lwpinfo3);
55911.1Skamil
55921.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_unmodified);
55931.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_faked);
55941.79Skamil
55951.82Skamil	ATF_TP_ADD_TC(tp, traceme_exec);
55961.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_exec);
55971.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_exec);
55981.1Skamil
55991.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_nolwpevents);
56001.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit);
56011.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate);
56021.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit);
56031.1Skamil
56041.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit_masked_sigtrap);
56051.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_masked_sigtrap);
56061.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit_masked_sigtrap);
56071.153Skamil
56081.84Skamil	ATF_TP_ADD_TC(tp, signal_mask_unrelated);
56091.84Skamil
56101.151Skamil	ATF_TP_ADD_TC(tp, threads_and_exec);
56111.151Skamil
56121.154Skamil	ATF_TP_ADD_TC(tp, suspend_no_deadlock);
56131.1Skamil
56141.155Skamil	ATF_TP_ADD_TC(tp, resume);
56151.1Skamil
56161.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_continue);
56171.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall);
56181.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach);
56191.122Skamil
56201.130Smgorny	ATF_TP_ADD_TC(tp, core_dump_procinfo);
56211.130Smgorny
56221.138Smgorny#if defined(TWAIT_HAVE_STATUS)
56231.138Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals);
56241.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_sig_ign);
56251.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_handler);
56261.160Smgorny#if defined(__i386__) || defined(__x86_64__)
56271.160Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_breakpoints);
56281.161Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_watchpoints);
56291.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp);
56301.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig);
56311.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_sig_ign);
56321.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_handler);
56331.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig);
56341.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_sig_ign);
56351.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_handler);
56361.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig);
56371.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_sig_ign);
56381.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_handler);
56391.160Smgorny#endif
56401.138Smgorny#endif
56411.138Smgorny
56421.174Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_REGISTER();
56431.175Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_SYSCALL();
56441.176Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_STEP();
56451.177Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_KILL();
56461.178Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_BYTETRANSFER();
56471.179Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_CLONE();
56481.180Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_FORK();
56491.174Skamil
56501.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
56511.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_I386();
56521.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_X86();
56531.1Skamil
56541.165Skamil#else
56551.165Skamil	ATF_TP_ADD_TC(tp, dummy);
56561.165Skamil#endif
56571.165Skamil
56581.1Skamil	return atf_no_error();
56591.1Skamil}
5660