t_ptrace_wait.c revision 1.185
11.185Skamil/*	$NetBSD: t_ptrace_wait.c,v 1.185 2020/05/05 00:15:45 kamil Exp $	*/
21.1Skamil
31.1Skamil/*-
41.181Skamil * Copyright (c) 2016, 2017, 2018, 2019, 2020 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.185Skamil__RCSID("$NetBSD: t_ptrace_wait.c,v 1.185 2020/05/05 00:15:45 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.37SkamilATF_TC(traceme_pid1_parent);
1071.37SkamilATF_TC_HEAD(traceme_pid1_parent, tc)
1081.37Skamil{
1091.181Skamil	atf_tc_set_md_var(tc, "descr",
1101.181Skamil	    "Verify that PT_TRACE_ME is not allowed when our parent is PID1");
1111.43Skamil}
1121.43Skamil
1131.181SkamilATF_TC_BODY(traceme_pid1_parent, tc)
1141.59Skamil{
1151.181Skamil	struct msg_fds parent_child;
1161.181Skamil	int exitval_child1 = 1, exitval_child2 = 2;
1171.181Skamil	pid_t child1, child2, wpid;
1181.59Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
1191.59Skamil#if defined(TWAIT_HAVE_STATUS)
1201.59Skamil	int status;
1211.59Skamil#endif
1221.94Skamil
1231.181Skamil	SYSCALL_REQUIRE(msg_open(&parent_child) == 0);
1241.61Skre
1251.181Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
1261.181Skamil	SYSCALL_REQUIRE((child1 = fork()) != -1);
1271.181Skamil	if (child1 == 0) {
1281.181Skamil		DPRINTF("Before forking process PID=%d\n", getpid());
1291.181Skamil		SYSCALL_REQUIRE((child2 = fork()) != -1);
1301.181Skamil		if (child2 != 0) {
1311.181Skamil			DPRINTF("Parent process PID=%d, child2's PID=%d\n",
1321.181Skamil			    getpid(), child2);
1331.181Skamil			_exit(exitval_child1);
1341.94Skamil		}
1351.181Skamil		CHILD_FROM_PARENT("exit child1", parent_child, msg);
1361.94Skamil
1371.181Skamil		DPRINTF("Assert that our parent is PID1 (initproc)\n");
1381.181Skamil		FORKEE_ASSERT_EQ(getppid(), 1);
1391.94Skamil
1401.181Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1411.181Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) == -1);
1421.181Skamil		SYSCALL_REQUIRE_ERRNO(errno, EPERM);
1431.94Skamil
1441.181Skamil		CHILD_TO_PARENT("child2 exiting", parent_child, msg);
1451.94Skamil
1461.181Skamil		_exit(exitval_child2);
1471.181Skamil	}
1481.181Skamil	DPRINTF("Parent process PID=%d, child1's PID=%d\n", getpid(), child1);
1491.94Skamil
1501.181Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
1511.181Skamil	TWAIT_REQUIRE_SUCCESS(
1521.181Skamil	    wpid = TWAIT_GENERIC(child1, &status, WEXITED), child1);
1531.94Skamil
1541.181Skamil	validate_status_exited(status, exitval_child1);
1551.94Skamil
1561.181Skamil	DPRINTF("Notify that child1 is dead\n");
1571.181Skamil	PARENT_TO_CHILD("exit child1", parent_child, msg);
1581.94Skamil
1591.181Skamil	DPRINTF("Wait for exiting of child2\n");
1601.181Skamil	PARENT_FROM_CHILD("child2 exiting", parent_child, msg);
1611.181Skamil}
1621.94Skamil
1631.181Skamil/// ----------------------------------------------------------------------------
1641.59Skamil
1651.181Skamilstatic void
1661.181Skamiltraceme_vfork_exec(bool masked, bool ignored)
1671.181Skamil{
1681.181Skamil	const int sigval = SIGTRAP;
1691.181Skamil	pid_t child, wpid;
1701.181Skamil#if defined(TWAIT_HAVE_STATUS)
1711.181Skamil	int status;
1721.181Skamil#endif
1731.181Skamil	struct sigaction sa;
1741.181Skamil	struct ptrace_siginfo info;
1751.181Skamil	sigset_t intmask;
1761.181Skamil	struct kinfo_proc2 kp;
1771.181Skamil	size_t len = sizeof(kp);
1781.59Skamil
1791.181Skamil	int name[6];
1801.181Skamil	const size_t namelen = __arraycount(name);
1811.181Skamil	ki_sigset_t kp_sigmask;
1821.181Skamil	ki_sigset_t kp_sigignore;
1831.59Skamil
1841.181Skamil	memset(&info, 0, sizeof(info));
1851.94Skamil
1861.181Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
1871.181Skamil	SYSCALL_REQUIRE((child = vfork()) != -1);
1881.181Skamil	if (child == 0) {
1891.181Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
1901.181Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
1911.94Skamil
1921.94Skamil		if (masked) {
1931.181Skamil			sigemptyset(&intmask);
1941.181Skamil			sigaddset(&intmask, sigval);
1951.181Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
1961.181Skamil		}
1971.94Skamil
1981.181Skamil		if (ignored) {
1991.181Skamil			memset(&sa, 0, sizeof(sa));
2001.181Skamil			sa.sa_handler = SIG_IGN;
2011.181Skamil			sigemptyset(&sa.sa_mask);
2021.181Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
2031.94Skamil		}
2041.94Skamil
2051.181Skamil		DPRINTF("Before calling execve(2) from child\n");
2061.181Skamil		execlp("/bin/echo", "/bin/echo", NULL);
2071.181Skamil
2081.181Skamil		/* NOTREACHED */
2091.181Skamil		FORKEE_ASSERTX(0 && "Not reached");
2101.181Skamil	}
2111.181Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
2121.181Skamil
2131.181Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2141.181Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2151.94Skamil
2161.181Skamil	validate_status_stopped(status, sigval);
2171.94Skamil
2181.181Skamil	name[0] = CTL_KERN,
2191.181Skamil	name[1] = KERN_PROC2,
2201.181Skamil	name[2] = KERN_PROC_PID;
2211.181Skamil	name[3] = getpid();
2221.181Skamil	name[4] = sizeof(kp);
2231.181Skamil	name[5] = 1;
2241.59Skamil
2251.181Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
2261.59Skamil
2271.181Skamil	if (masked)
2281.181Skamil		kp_sigmask = kp.p_sigmask;
2291.59Skamil
2301.181Skamil	if (ignored)
2311.181Skamil		kp_sigignore = kp.p_sigignore;
2321.71Skamil
2331.181Skamil	name[3] = getpid();
2341.59Skamil
2351.181Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
2361.59Skamil
2371.181Skamil	if (masked) {
2381.181Skamil		DPRINTF("kp_sigmask="
2391.181Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
2401.181Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
2411.181Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
2421.59Skamil
2431.181Skamil	        DPRINTF("kp.p_sigmask="
2441.181Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
2451.181Skamil	            kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
2461.181Skamil	            kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
2471.59Skamil
2481.181Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
2491.181Skamil		    sizeof(kp_sigmask)));
2501.181Skamil	}
2511.59Skamil
2521.181Skamil	if (ignored) {
2531.181Skamil		DPRINTF("kp_sigignore="
2541.181Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
2551.181Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
2561.181Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
2571.59Skamil
2581.181Skamil	        DPRINTF("kp.p_sigignore="
2591.181Skamil	            "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
2601.181Skamil	            kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
2611.181Skamil	            kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
2621.59Skamil
2631.181Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
2641.181Skamil		    sizeof(kp_sigignore)));
2651.181Skamil	}
2661.59Skamil
2671.181Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
2681.181Skamil	SYSCALL_REQUIRE(
2691.181Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
2701.59Skamil
2711.181Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
2721.181Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
2731.181Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
2741.181Skamil	    info.psi_siginfo.si_errno);
2751.71Skamil
2761.181Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
2771.181Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
2781.59Skamil
2791.181Skamil	DPRINTF("Before resuming the child process where it left off and "
2801.181Skamil	    "without signal to be sent\n");
2811.181Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
2821.59Skamil
2831.181Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2841.181Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
2851.94Skamil
2861.181Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
2871.181Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
2881.94Skamil}
2891.94Skamil
2901.181Skamil#define TRACEME_VFORK_EXEC(test, masked, ignored)			\
2911.94SkamilATF_TC(test);								\
2921.94SkamilATF_TC_HEAD(test, tc)							\
2931.94Skamil{									\
2941.94Skamil	atf_tc_set_md_var(tc, "descr",					\
2951.181Skamil	    "Verify PT_TRACE_ME followed by exec(3) in a vfork(2)ed "	\
2961.181Skamil	    "child%s%s", masked ? " with masked signal" : "",		\
2971.181Skamil	    masked ? " with ignored signal" : "");			\
2981.94Skamil}									\
2991.94Skamil									\
3001.94SkamilATF_TC_BODY(test, tc)							\
3011.94Skamil{									\
3021.94Skamil									\
3031.181Skamil	traceme_vfork_exec(masked, ignored);				\
3041.94Skamil}
3051.94Skamil
3061.181SkamilTRACEME_VFORK_EXEC(traceme_vfork_exec, false, false)
3071.181SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalmasked_exec, true, false)
3081.181SkamilTRACEME_VFORK_EXEC(traceme_vfork_signalignored_exec, false, true)
3091.59Skamil
3101.59Skamil/// ----------------------------------------------------------------------------
3111.59Skamil
3121.59Skamil#if defined(TWAIT_HAVE_PID)
3131.59Skamilstatic void
3141.67Skamiltracer_sees_terminaton_before_the_parent_raw(bool notimeout, bool unrelated,
3151.67Skamil                                             bool stopped)
3161.1Skamil{
3171.51Skamil	/*
3181.51Skamil	 * notimeout - disable timeout in await zombie function
3191.51Skamil	 * unrelated - attach from unrelated tracer reparented to initproc
3201.67Skamil	 * stopped - attach to a stopped process
3211.51Skamil	 */
3221.1Skamil
3231.1Skamil	struct msg_fds parent_tracee, parent_tracer;
3241.1Skamil	const int exitval_tracee = 5;
3251.1Skamil	const int exitval_tracer = 10;
3261.1Skamil	pid_t tracee, tracer, wpid;
3271.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
3281.1Skamil#if defined(TWAIT_HAVE_STATUS)
3291.1Skamil	int status;
3301.1Skamil#endif
3311.1Skamil
3321.67Skamil	/*
3331.67Skamil	 * Only a subset of options are supported.
3341.67Skamil	 */
3351.67Skamil	ATF_REQUIRE((!notimeout && !unrelated && !stopped) ||
3361.67Skamil	            (!notimeout && unrelated && !stopped) ||
3371.67Skamil	            (notimeout && !unrelated && !stopped) ||
3381.67Skamil	            (!notimeout && unrelated && stopped));
3391.67Skamil
3401.13Schristos	DPRINTF("Spawn tracee\n");
3411.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
3421.1Skamil	tracee = atf_utils_fork();
3431.1Skamil	if (tracee == 0) {
3441.67Skamil		if (stopped) {
3451.67Skamil			DPRINTF("Stop self PID %d\n", getpid());
3461.67Skamil			raise(SIGSTOP);
3471.67Skamil		}
3481.67Skamil
3491.1Skamil		// Wait for parent to let us exit
3501.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
3511.1Skamil		_exit(exitval_tracee);
3521.1Skamil	}
3531.1Skamil
3541.13Schristos	DPRINTF("Spawn debugger\n");
3551.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
3561.1Skamil	tracer = atf_utils_fork();
3571.1Skamil	if (tracer == 0) {
3581.51Skamil		if(unrelated) {
3591.51Skamil			/* Fork again and drop parent to reattach to PID 1 */
3601.51Skamil			tracer = atf_utils_fork();
3611.51Skamil			if (tracer != 0)
3621.51Skamil				_exit(exitval_tracer);
3631.51Skamil		}
3641.51Skamil
3651.67Skamil		if (stopped) {
3661.67Skamil			DPRINTF("Await for a stopped parent PID %d\n", tracee);
3671.67Skamil			await_stopped(tracee);
3681.67Skamil		}
3691.67Skamil
3701.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
3711.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
3721.1Skamil
3731.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
3741.1Skamil		FORKEE_REQUIRE_SUCCESS(
3751.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
3761.1Skamil
3771.1Skamil		forkee_status_stopped(status, SIGSTOP);
3781.1Skamil
3791.1Skamil		/* Resume tracee with PT_CONTINUE */
3801.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
3811.1Skamil
3821.1Skamil		/* Inform parent that tracer has attached to tracee */
3831.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
3841.1Skamil
3851.1Skamil		/* Wait for parent to tell use that tracee should have exited */
3861.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
3871.1Skamil
3881.1Skamil		/* Wait for tracee and assert that it exited */
3891.1Skamil		FORKEE_REQUIRE_SUCCESS(
3901.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
3911.1Skamil
3921.1Skamil		forkee_status_exited(status, exitval_tracee);
3931.13Schristos		DPRINTF("Tracee %d exited with %d\n", tracee, exitval_tracee);
3941.1Skamil
3951.13Schristos		DPRINTF("Before exiting of the tracer process\n");
3961.51Skamil		_exit(unrelated ? 0 /* collect by initproc */ : exitval_tracer);
3971.51Skamil	}
3981.51Skamil
3991.51Skamil	if (unrelated) {
4001.51Skamil		DPRINTF("Wait for the tracer process (direct child) to exit "
4011.51Skamil		    "calling %s()\n", TWAIT_FNAME);
4021.51Skamil		TWAIT_REQUIRE_SUCCESS(
4031.51Skamil		    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
4041.51Skamil
4051.51Skamil		validate_status_exited(status, exitval_tracer);
4061.51Skamil
4071.51Skamil		DPRINTF("Wait for the non-exited tracee process with %s()\n",
4081.51Skamil		    TWAIT_FNAME);
4091.51Skamil		TWAIT_REQUIRE_SUCCESS(
4101.51Skamil		    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
4111.1Skamil	}
4121.1Skamil
4131.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
4141.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
4151.1Skamil
4161.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
4171.1Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
4181.1Skamil
4191.13Schristos	DPRINTF("Detect that tracee is zombie\n");
4201.51Skamil	if (notimeout)
4211.26Skamil		await_zombie_raw(tracee, 0);
4221.26Skamil	else
4231.26Skamil		await_zombie(tracee);
4241.1Skamil
4251.13Schristos	DPRINTF("Assert that there is no status about tracee %d - "
4261.1Skamil	    "Tracer must detect zombie first - calling %s()\n", tracee,
4271.1Skamil	    TWAIT_FNAME);
4281.1Skamil	TWAIT_REQUIRE_SUCCESS(
4291.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
4301.1Skamil
4311.51Skamil	if (unrelated) {
4321.51Skamil		DPRINTF("Resume the tracer and let it detect exited tracee\n");
4331.51Skamil		PARENT_TO_CHILD("Message 2", parent_tracer, msg);
4341.51Skamil	} else {
4351.51Skamil		DPRINTF("Tell the tracer child should have exited\n");
4361.51Skamil		PARENT_TO_CHILD("wait for tracee exit", parent_tracer,  msg);
4371.51Skamil		DPRINTF("Wait for tracer to finish its job and exit - calling "
4381.59Skamil			"%s()\n", TWAIT_FNAME);
4391.51Skamil
4401.51Skamil		DPRINTF("Wait from tracer child to complete waiting for "
4411.59Skamil			"tracee\n");
4421.51Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
4431.51Skamil		    tracer);
4441.1Skamil
4451.51Skamil		validate_status_exited(status, exitval_tracer);
4461.51Skamil	}
4471.1Skamil
4481.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
4491.1Skamil	    TWAIT_FNAME);
4501.51Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
4511.1Skamil
4521.1Skamil	validate_status_exited(status, exitval_tracee);
4531.1Skamil
4541.1Skamil	msg_close(&parent_tracer);
4551.1Skamil	msg_close(&parent_tracee);
4561.1Skamil}
4571.26Skamil
4581.51SkamilATF_TC(tracer_sees_terminaton_before_the_parent);
4591.51SkamilATF_TC_HEAD(tracer_sees_terminaton_before_the_parent, tc)
4601.51Skamil{
4611.51Skamil	atf_tc_set_md_var(tc, "descr",
4621.51Skamil	    "Assert that tracer sees process termination before the parent");
4631.51Skamil}
4641.51Skamil
4651.51SkamilATF_TC_BODY(tracer_sees_terminaton_before_the_parent, tc)
4661.26Skamil{
4671.26Skamil
4681.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, false, false);
4691.26Skamil}
4701.26Skamil
4711.51SkamilATF_TC(tracer_sysctl_lookup_without_duplicates);
4721.51SkamilATF_TC_HEAD(tracer_sysctl_lookup_without_duplicates, tc)
4731.1Skamil{
4741.164Skamil	atf_tc_set_md_var(tc, "timeout", "15");
4751.1Skamil	atf_tc_set_md_var(tc, "descr",
4761.51Skamil	    "Assert that await_zombie() in attach1 always finds a single "
4771.51Skamil	    "process and no other error is reported");
4781.1Skamil}
4791.1Skamil
4801.51SkamilATF_TC_BODY(tracer_sysctl_lookup_without_duplicates, tc)
4811.1Skamil{
4821.51Skamil	time_t start, end;
4831.51Skamil	double diff;
4841.51Skamil	unsigned long N = 0;
4851.1Skamil
4861.51Skamil	/*
4871.51Skamil	 * Reuse this test with tracer_sees_terminaton_before_the_parent_raw().
4881.51Skamil	 * This test body isn't specific to this race, however it's just good
4891.51Skamil	 * enough for this purposes, no need to invent a dedicated code flow.
4901.51Skamil	 */
4911.1Skamil
4921.51Skamil	start = time(NULL);
4931.51Skamil	while (true) {
4941.51Skamil		DPRINTF("Step: %lu\n", N);
4951.67Skamil		tracer_sees_terminaton_before_the_parent_raw(true, false,
4961.67Skamil		                                             false);
4971.51Skamil		end = time(NULL);
4981.51Skamil		diff = difftime(end, start);
4991.51Skamil		if (diff >= 5.0)
5001.51Skamil			break;
5011.51Skamil		++N;
5021.1Skamil	}
5031.51Skamil	DPRINTF("Iterations: %lu\n", N);
5041.51Skamil}
5051.1Skamil
5061.51SkamilATF_TC(unrelated_tracer_sees_terminaton_before_the_parent);
5071.51SkamilATF_TC_HEAD(unrelated_tracer_sees_terminaton_before_the_parent, tc)
5081.51Skamil{
5091.51Skamil	atf_tc_set_md_var(tc, "descr",
5101.51Skamil	    "Assert that tracer sees process termination before the parent");
5111.51Skamil}
5121.1Skamil
5131.51SkamilATF_TC_BODY(unrelated_tracer_sees_terminaton_before_the_parent, tc)
5141.51Skamil{
5151.1Skamil
5161.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, false);
5171.67Skamil}
5181.67Skamil
5191.67SkamilATF_TC(tracer_attach_to_unrelated_stopped_process);
5201.67SkamilATF_TC_HEAD(tracer_attach_to_unrelated_stopped_process, tc)
5211.67Skamil{
5221.67Skamil	atf_tc_set_md_var(tc, "descr",
5231.67Skamil	    "Assert that tracer can attach to an unrelated stopped process");
5241.67Skamil}
5251.67Skamil
5261.67SkamilATF_TC_BODY(tracer_attach_to_unrelated_stopped_process, tc)
5271.67Skamil{
5281.67Skamil
5291.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, true);
5301.1Skamil}
5311.1Skamil#endif
5321.1Skamil
5331.51Skamil/// ----------------------------------------------------------------------------
5341.51Skamil
5351.66Skamilstatic void
5361.66Skamilparent_attach_to_its_child(bool stopped)
5371.1Skamil{
5381.1Skamil	struct msg_fds parent_tracee;
5391.1Skamil	const int exitval_tracee = 5;
5401.1Skamil	pid_t tracee, wpid;
5411.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
5421.1Skamil#if defined(TWAIT_HAVE_STATUS)
5431.1Skamil	int status;
5441.1Skamil#endif
5451.1Skamil
5461.13Schristos	DPRINTF("Spawn tracee\n");
5471.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
5481.1Skamil	tracee = atf_utils_fork();
5491.1Skamil	if (tracee == 0) {
5501.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
5511.13Schristos		DPRINTF("Parent should now attach to tracee\n");
5521.1Skamil
5531.66Skamil		if (stopped) {
5541.66Skamil			DPRINTF("Stop self PID %d\n", getpid());
5551.66Skamil			SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
5561.66Skamil		}
5571.66Skamil
5581.1Skamil		CHILD_FROM_PARENT("Message 2", parent_tracee, msg);
5591.1Skamil		/* Wait for message from the parent */
5601.1Skamil		_exit(exitval_tracee);
5611.1Skamil	}
5621.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
5631.57Skamil
5641.66Skamil	if (stopped) {
5651.66Skamil		DPRINTF("Await for a stopped tracee PID %d\n", tracee);
5661.66Skamil		await_stopped(tracee);
5671.66Skamil	}
5681.66Skamil
5691.13Schristos	DPRINTF("Before calling PT_ATTACH for tracee %d\n", tracee);
5701.13Schristos	SYSCALL_REQUIRE(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
5711.1Skamil
5721.13Schristos	DPRINTF("Wait for the stopped tracee process with %s()\n",
5731.1Skamil	    TWAIT_FNAME);
5741.1Skamil	TWAIT_REQUIRE_SUCCESS(
5751.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
5761.1Skamil
5771.1Skamil	validate_status_stopped(status, SIGSTOP);
5781.1Skamil
5791.13Schristos	DPRINTF("Resume tracee with PT_CONTINUE\n");
5801.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
5811.1Skamil
5821.13Schristos	DPRINTF("Let the tracee exit now\n");
5831.1Skamil	PARENT_TO_CHILD("Message 2", parent_tracee, msg);
5841.1Skamil
5851.13Schristos	DPRINTF("Wait for tracee to exit with %s()\n", TWAIT_FNAME);
5861.1Skamil	TWAIT_REQUIRE_SUCCESS(
5871.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
5881.1Skamil
5891.1Skamil	validate_status_exited(status, exitval_tracee);
5901.1Skamil
5911.13Schristos	DPRINTF("Before calling %s() for tracee\n", TWAIT_FNAME);
5921.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
5931.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0));
5941.1Skamil
5951.1Skamil	msg_close(&parent_tracee);
5961.1Skamil}
5971.1Skamil
5981.66SkamilATF_TC(parent_attach_to_its_child);
5991.66SkamilATF_TC_HEAD(parent_attach_to_its_child, tc)
6001.66Skamil{
6011.66Skamil	atf_tc_set_md_var(tc, "descr",
6021.66Skamil	    "Assert that tracer parent can PT_ATTACH to its child");
6031.66Skamil}
6041.66Skamil
6051.66SkamilATF_TC_BODY(parent_attach_to_its_child, tc)
6061.66Skamil{
6071.66Skamil
6081.66Skamil	parent_attach_to_its_child(false);
6091.66Skamil}
6101.66Skamil
6111.66SkamilATF_TC(parent_attach_to_its_stopped_child);
6121.66SkamilATF_TC_HEAD(parent_attach_to_its_stopped_child, tc)
6131.66Skamil{
6141.66Skamil	atf_tc_set_md_var(tc, "descr",
6151.66Skamil	    "Assert that tracer parent can PT_ATTACH to its stopped child");
6161.66Skamil}
6171.66Skamil
6181.66SkamilATF_TC_BODY(parent_attach_to_its_stopped_child, tc)
6191.66Skamil{
6201.66Skamil
6211.66Skamil	parent_attach_to_its_child(true);
6221.66Skamil}
6231.66Skamil
6241.51Skamil/// ----------------------------------------------------------------------------
6251.51Skamil
6261.65Skamilstatic void
6271.65Skamilchild_attach_to_its_parent(bool stopped)
6281.1Skamil{
6291.1Skamil	struct msg_fds parent_tracee;
6301.1Skamil	const int exitval_tracer = 5;
6311.1Skamil	pid_t tracer, wpid;
6321.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
6331.1Skamil#if defined(TWAIT_HAVE_STATUS)
6341.1Skamil	int status;
6351.1Skamil#endif
6361.1Skamil
6371.13Schristos	DPRINTF("Spawn tracer\n");
6381.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
6391.1Skamil	tracer = atf_utils_fork();
6401.1Skamil	if (tracer == 0) {
6411.1Skamil		/* Wait for message from the parent */
6421.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
6431.1Skamil
6441.65Skamil		if (stopped) {
6451.65Skamil			DPRINTF("Await for a stopped parent PID %d\n",
6461.65Skamil			        getppid());
6471.65Skamil			await_stopped(getppid());
6481.65Skamil		}
6491.65Skamil
6501.13Schristos		DPRINTF("Attach to parent PID %d with PT_ATTACH from child\n",
6511.1Skamil		    getppid());
6521.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, getppid(), NULL, 0) != -1);
6531.1Skamil
6541.13Schristos		DPRINTF("Wait for the stopped parent process with %s()\n",
6551.1Skamil		    TWAIT_FNAME);
6561.1Skamil		FORKEE_REQUIRE_SUCCESS(
6571.1Skamil		    wpid = TWAIT_GENERIC(getppid(), &status, 0), getppid());
6581.1Skamil
6591.1Skamil		forkee_status_stopped(status, SIGSTOP);
6601.1Skamil
6611.13Schristos		DPRINTF("Resume parent with PT_DETACH\n");
6621.1Skamil		FORKEE_ASSERT(ptrace(PT_DETACH, getppid(), (void *)1, 0)
6631.1Skamil		    != -1);
6641.1Skamil
6651.1Skamil		/* Tell parent we are ready */
6661.1Skamil		CHILD_TO_PARENT("Message 1", parent_tracee, msg);
6671.1Skamil
6681.1Skamil		_exit(exitval_tracer);
6691.1Skamil	}
6701.1Skamil
6711.13Schristos	DPRINTF("Wait for the tracer to become ready\n");
6721.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
6731.65Skamil
6741.65Skamil	if (stopped) {
6751.65Skamil		DPRINTF("Stop self PID %d\n", getpid());
6761.65Skamil		SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
6771.65Skamil	}
6781.65Skamil
6791.13Schristos	DPRINTF("Allow the tracer to exit now\n");
6801.1Skamil	PARENT_FROM_CHILD("Message 1", parent_tracee, msg);
6811.1Skamil
6821.13Schristos	DPRINTF("Wait for tracer to exit with %s()\n", TWAIT_FNAME);
6831.1Skamil	TWAIT_REQUIRE_SUCCESS(
6841.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
6851.1Skamil
6861.1Skamil	validate_status_exited(status, exitval_tracer);
6871.1Skamil
6881.13Schristos	DPRINTF("Before calling %s() for tracer\n", TWAIT_FNAME);
6891.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
6901.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0));
6911.1Skamil
6921.1Skamil	msg_close(&parent_tracee);
6931.1Skamil}
6941.1Skamil
6951.65SkamilATF_TC(child_attach_to_its_parent);
6961.65SkamilATF_TC_HEAD(child_attach_to_its_parent, tc)
6971.65Skamil{
6981.65Skamil	atf_tc_set_md_var(tc, "descr",
6991.65Skamil	    "Assert that tracer child can PT_ATTACH to its parent");
7001.65Skamil}
7011.65Skamil
7021.65SkamilATF_TC_BODY(child_attach_to_its_parent, tc)
7031.65Skamil{
7041.65Skamil
7051.65Skamil	child_attach_to_its_parent(false);
7061.65Skamil}
7071.65Skamil
7081.65SkamilATF_TC(child_attach_to_its_stopped_parent);
7091.65SkamilATF_TC_HEAD(child_attach_to_its_stopped_parent, tc)
7101.65Skamil{
7111.65Skamil	atf_tc_set_md_var(tc, "descr",
7121.65Skamil	    "Assert that tracer child can PT_ATTACH to its stopped parent");
7131.65Skamil}
7141.65Skamil
7151.65SkamilATF_TC_BODY(child_attach_to_its_stopped_parent, tc)
7161.65Skamil{
7171.65Skamil	/*
7181.65Skamil	 * The ATF framework (atf-run) does not tolerate raise(SIGSTOP), as
7191.65Skamil	 * this causes a pipe (established from atf-run) to be broken.
7201.65Skamil	 * atf-run uses this mechanism to monitor whether a test is alive.
7211.65Skamil	 *
7221.65Skamil	 * As a workaround spawn this test as a subprocess.
7231.65Skamil	 */
7241.65Skamil
7251.65Skamil	const int exitval = 15;
7261.65Skamil	pid_t child, wpid;
7271.65Skamil#if defined(TWAIT_HAVE_STATUS)
7281.65Skamil	int status;
7291.65Skamil#endif
7301.65Skamil
7311.65Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
7321.65Skamil	if (child == 0) {
7331.65Skamil		child_attach_to_its_parent(true);
7341.65Skamil		_exit(exitval);
7351.65Skamil	} else {
7361.65Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
7371.65Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
7381.65Skamil
7391.65Skamil		validate_status_exited(status, exitval);
7401.65Skamil
7411.65Skamil		DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
7421.65Skamil		TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
7431.65Skamil	}
7441.65Skamil}
7451.65Skamil
7461.51Skamil/// ----------------------------------------------------------------------------
7471.51Skamil
7481.1Skamil#if defined(TWAIT_HAVE_PID)
7491.1Skamil
7501.51Skamilenum tracee_sees_its_original_parent_type {
7511.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
7521.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
7531.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS
7541.51Skamil};
7551.51Skamil
7561.51Skamilstatic void
7571.51Skamiltracee_sees_its_original_parent(enum tracee_sees_its_original_parent_type type)
7581.1Skamil{
7591.1Skamil	struct msg_fds parent_tracer, parent_tracee;
7601.1Skamil	const int exitval_tracee = 5;
7611.1Skamil	const int exitval_tracer = 10;
7621.1Skamil	pid_t parent, tracee, tracer, wpid;
7631.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
7641.1Skamil#if defined(TWAIT_HAVE_STATUS)
7651.1Skamil	int status;
7661.1Skamil#endif
7671.51Skamil	/* sysctl(3) - kinfo_proc2 */
7681.51Skamil	int name[CTL_MAXNAME];
7691.51Skamil	struct kinfo_proc2 kp;
7701.51Skamil	size_t len = sizeof(kp);
7711.51Skamil	unsigned int namelen;
7721.51Skamil
7731.51Skamil	/* procfs - status  */
7741.51Skamil	FILE *fp;
7751.51Skamil	struct stat st;
7761.51Skamil	const char *fname = "/proc/curproc/status";
7771.51Skamil	char s_executable[MAXPATHLEN];
7781.51Skamil	int s_pid, s_ppid;
7791.51Skamil	int rv;
7801.51Skamil
7811.51Skamil	if (type == TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS) {
7821.61Skre		SYSCALL_REQUIRE(
7831.61Skre		    (rv = stat(fname, &st)) == 0 || (errno == ENOENT));
7841.61Skre		if (rv != 0)
7851.51Skamil			atf_tc_skip("/proc/curproc/status not found");
7861.51Skamil	}
7871.1Skamil
7881.13Schristos	DPRINTF("Spawn tracee\n");
7891.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
7901.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
7911.1Skamil	tracee = atf_utils_fork();
7921.1Skamil	if (tracee == 0) {
7931.1Skamil		parent = getppid();
7941.1Skamil
7951.1Skamil		/* Emit message to the parent */
7961.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
7971.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
7981.1Skamil
7991.51Skamil		switch (type) {
8001.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID:
8011.51Skamil			FORKEE_ASSERT_EQ(parent, getppid());
8021.51Skamil			break;
8031.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2:
8041.51Skamil			namelen = 0;
8051.51Skamil			name[namelen++] = CTL_KERN;
8061.51Skamil			name[namelen++] = KERN_PROC2;
8071.51Skamil			name[namelen++] = KERN_PROC_PID;
8081.51Skamil			name[namelen++] = getpid();
8091.51Skamil			name[namelen++] = len;
8101.51Skamil			name[namelen++] = 1;
8111.51Skamil
8121.61Skre			FORKEE_ASSERT_EQ(
8131.61Skre			    sysctl(name, namelen, &kp, &len, NULL, 0), 0);
8141.51Skamil			FORKEE_ASSERT_EQ(parent, kp.p_ppid);
8151.51Skamil			break;
8161.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS:
8171.51Skamil			/*
8181.51Skamil			 * Format:
8191.51Skamil			 *  EXECUTABLE PID PPID ...
8201.51Skamil			 */
8211.51Skamil			FORKEE_ASSERT((fp = fopen(fname, "r")) != NULL);
8221.51Skamil			fscanf(fp, "%s %d %d", s_executable, &s_pid, &s_ppid);
8231.51Skamil			FORKEE_ASSERT_EQ(fclose(fp), 0);
8241.51Skamil			FORKEE_ASSERT_EQ(parent, s_ppid);
8251.51Skamil			break;
8261.51Skamil		}
8271.1Skamil
8281.1Skamil		_exit(exitval_tracee);
8291.1Skamil	}
8301.13Schristos	DPRINTF("Wait for child to record its parent identifier (pid)\n");
8311.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
8321.1Skamil
8331.13Schristos	DPRINTF("Spawn debugger\n");
8341.1Skamil	tracer = atf_utils_fork();
8351.1Skamil	if (tracer == 0) {
8361.1Skamil		/* No IPC to communicate with the child */
8371.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
8381.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
8391.1Skamil
8401.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
8411.1Skamil		FORKEE_REQUIRE_SUCCESS(
8421.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
8431.1Skamil
8441.1Skamil		forkee_status_stopped(status, SIGSTOP);
8451.1Skamil
8461.1Skamil		/* Resume tracee with PT_CONTINUE */
8471.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
8481.1Skamil
8491.1Skamil		/* Inform parent that tracer has attached to tracee */
8501.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
8511.1Skamil
8521.1Skamil		/* Wait for parent to tell use that tracee should have exited */
8531.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
8541.1Skamil
8551.1Skamil		/* Wait for tracee and assert that it exited */
8561.1Skamil		FORKEE_REQUIRE_SUCCESS(
8571.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
8581.1Skamil
8591.1Skamil		forkee_status_exited(status, exitval_tracee);
8601.1Skamil
8611.13Schristos		DPRINTF("Before exiting of the tracer process\n");
8621.1Skamil		_exit(exitval_tracer);
8631.1Skamil	}
8641.1Skamil
8651.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
8661.1Skamil	PARENT_FROM_CHILD("tracer ready",  parent_tracer, msg);
8671.1Skamil
8681.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
8691.1Skamil	PARENT_TO_CHILD("exit tracee",  parent_tracee, msg);
8701.1Skamil
8711.13Schristos	DPRINTF("Detect that tracee is zombie\n");
8721.1Skamil	await_zombie(tracee);
8731.1Skamil
8741.13Schristos	DPRINTF("Assert that there is no status about tracee - "
8751.1Skamil	    "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
8761.1Skamil	TWAIT_REQUIRE_SUCCESS(
8771.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
8781.1Skamil
8791.13Schristos	DPRINTF("Tell the tracer child should have exited\n");
8801.1Skamil	PARENT_TO_CHILD("wait for tracee exit",  parent_tracer, msg);
8811.1Skamil
8821.13Schristos	DPRINTF("Wait from tracer child to complete waiting for tracee\n");
8831.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
8841.1Skamil	    tracer);
8851.1Skamil
8861.1Skamil	validate_status_exited(status, exitval_tracer);
8871.1Skamil
8881.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
8891.1Skamil	    TWAIT_FNAME);
8901.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
8911.1Skamil	    tracee);
8921.1Skamil
8931.1Skamil	validate_status_exited(status, exitval_tracee);
8941.1Skamil
8951.1Skamil	msg_close(&parent_tracer);
8961.1Skamil	msg_close(&parent_tracee);
8971.1Skamil}
8981.1Skamil
8991.61Skre#define TRACEE_SEES_ITS_ORIGINAL_PARENT(test, type, descr)		\
9001.61SkreATF_TC(test);								\
9011.61SkreATF_TC_HEAD(test, tc)							\
9021.61Skre{									\
9031.61Skre	atf_tc_set_md_var(tc, "descr",					\
9041.61Skre	    "Assert that tracee sees its original parent when being traced " \
9051.61Skre	    "(check " descr ")");					\
9061.61Skre}									\
9071.61Skre									\
9081.61SkreATF_TC_BODY(test, tc)							\
9091.61Skre{									\
9101.61Skre									\
9111.61Skre	tracee_sees_its_original_parent(type);				\
9121.1Skamil}
9131.1Skamil
9141.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
9151.51Skamil	tracee_sees_its_original_parent_getppid,
9161.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
9171.51Skamil	"getppid(2)");
9181.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
9191.51Skamil	tracee_sees_its_original_parent_sysctl_kinfo_proc2,
9201.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
9211.51Skamil	"sysctl(3) and kinfo_proc2");
9221.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
9231.51Skamil	tracee_sees_its_original_parent_procfs_status,
9241.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS,
9251.51Skamil	"the status file in procfs");
9261.1Skamil#endif
9271.1Skamil
9281.51Skamil/// ----------------------------------------------------------------------------
9291.1Skamil
9301.83Skamilstatic void
9311.180Skamilptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c), int *signal_caught)
9321.1Skamil{
9331.180Skamil	const int exitval = 5;
9341.180Skamil	const int sigval = SIGINT;
9351.180Skamil	const int sigfaked = SIGTRAP;
9361.180Skamil	const int sicodefaked = TRAP_BRKPT;
9371.1Skamil	pid_t child, wpid;
9381.180Skamil	struct sigaction sa;
9391.1Skamil#if defined(TWAIT_HAVE_STATUS)
9401.1Skamil	int status;
9411.1Skamil#endif
9421.83Skamil	struct ptrace_siginfo info;
9431.180Skamil	memset(&info, 0, sizeof(info));
9441.83Skamil
9451.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
9461.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
9471.1Skamil	if (child == 0) {
9481.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
9491.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
9501.1Skamil
9511.180Skamil		sa.sa_sigaction = sah;
9521.180Skamil		sa.sa_flags = SA_SIGINFO;
9531.180Skamil		sigemptyset(&sa.sa_mask);
9541.180Skamil
9551.180Skamil		FORKEE_ASSERT(sigaction(faked ? sigfaked : sigval, &sa, NULL)
9561.180Skamil		    != -1);
9571.153Skamil
9581.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
9591.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
9601.1Skamil
9611.180Skamil		FORKEE_ASSERT_EQ(*signal_caught, 1);
9621.1Skamil
9631.180Skamil		DPRINTF("Before exiting of the child process\n");
9641.180Skamil		_exit(exitval);
9651.1Skamil	}
9661.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
9671.1Skamil
9681.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9691.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9701.1Skamil
9711.1Skamil	validate_status_stopped(status, sigval);
9721.1Skamil
9731.83Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
9741.83Skamil	SYSCALL_REQUIRE(
9751.83Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
9761.1Skamil
9771.83Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
9781.83Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
9791.83Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
9801.83Skamil	    info.psi_siginfo.si_errno);
9811.1Skamil
9821.180Skamil	if (faked) {
9831.180Skamil		DPRINTF("Before setting new faked signal to signo=%d "
9841.180Skamil		    "si_code=%d\n", sigfaked, sicodefaked);
9851.180Skamil		info.psi_siginfo.si_signo = sigfaked;
9861.180Skamil		info.psi_siginfo.si_code = sicodefaked;
9871.83Skamil	}
9881.1Skamil
9891.180Skamil	DPRINTF("Before calling ptrace(2) with PT_SET_SIGINFO for child\n");
9901.180Skamil	SYSCALL_REQUIRE(
9911.180Skamil	    ptrace(PT_SET_SIGINFO, child, &info, sizeof(info)) != -1);
9921.1Skamil
9931.180Skamil	if (faked) {
9941.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
9951.83Skamil		    "child\n");
9961.180Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
9971.180Skamil		    sizeof(info)) != -1);
9981.1Skamil
9991.180Skamil		DPRINTF("Before checking siginfo_t\n");
10001.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigfaked);
10011.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, sicodefaked);
10021.83Skamil	}
10031.1Skamil
10041.180Skamil	DPRINTF("Before resuming the child process where it left off and "
10051.180Skamil	    "without signal to be sent\n");
10061.180Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
10071.180Skamil	    faked ? sigfaked : sigval) != -1);
10081.1Skamil
10091.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10101.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
10111.1Skamil
10121.180Skamil	validate_status_exited(status, exitval);
10131.1Skamil
10141.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
10151.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
10161.1Skamil}
10171.1Skamil
10181.180Skamil#define PTRACE_SIGINFO(test, faked)					\
10191.83SkamilATF_TC(test);								\
10201.83SkamilATF_TC_HEAD(test, tc)							\
10211.83Skamil{									\
10221.180Skamil	atf_tc_set_md_var(tc, "descr",					\
10231.180Skamil	    "Verify basic PT_GET_SIGINFO and PT_SET_SIGINFO calls"	\
10241.180Skamil	    "with%s setting signal to new value", faked ? "" : "out");	\
10251.180Skamil}									\
10261.180Skamil									\
10271.180Skamilstatic int test##_caught = 0;						\
10281.180Skamil									\
10291.180Skamilstatic void								\
10301.180Skamiltest##_sighandler(int sig, siginfo_t *info, void *ctx)			\
10311.180Skamil{									\
10321.180Skamil	if (faked) {							\
10331.180Skamil		FORKEE_ASSERT_EQ(sig, SIGTRAP);				\
10341.180Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGTRAP);		\
10351.180Skamil		FORKEE_ASSERT_EQ(info->si_code, TRAP_BRKPT);		\
10361.180Skamil	} else {							\
10371.180Skamil		FORKEE_ASSERT_EQ(sig, SIGINT);				\
10381.180Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGINT);		\
10391.180Skamil		FORKEE_ASSERT_EQ(info->si_code, SI_LWP);		\
10401.180Skamil	}								\
10411.180Skamil									\
10421.180Skamil	++ test##_caught;						\
10431.83Skamil}									\
10441.83Skamil									\
10451.83SkamilATF_TC_BODY(test, tc)							\
10461.83Skamil{									\
10471.83Skamil									\
10481.180Skamil	ptrace_siginfo(faked, test##_sighandler, & test##_caught); 	\
10491.83Skamil}
10501.83Skamil
10511.180SkamilPTRACE_SIGINFO(siginfo_set_unmodified, false)
10521.180SkamilPTRACE_SIGINFO(siginfo_set_faked, true)
10531.83Skamil
10541.83Skamil/// ----------------------------------------------------------------------------
10551.83Skamil
10561.180Skamilstatic void
10571.180Skamiltraceme_exec(bool masked, bool ignored)
10581.1Skamil{
10591.180Skamil	const int sigval = SIGTRAP;
10601.1Skamil	pid_t child, wpid;
10611.1Skamil#if defined(TWAIT_HAVE_STATUS)
10621.1Skamil	int status;
10631.1Skamil#endif
10641.180Skamil	struct sigaction sa;
10651.180Skamil	struct ptrace_siginfo info;
10661.1Skamil	sigset_t intmask;
10671.180Skamil	struct kinfo_proc2 kp;
10681.180Skamil	size_t len = sizeof(kp);
10691.180Skamil
10701.180Skamil	int name[6];
10711.180Skamil	const size_t namelen = __arraycount(name);
10721.180Skamil	ki_sigset_t kp_sigmask;
10731.180Skamil	ki_sigset_t kp_sigignore;
10741.180Skamil
10751.180Skamil	memset(&info, 0, sizeof(info));
10761.1Skamil
10771.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
10781.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
10791.1Skamil	if (child == 0) {
10801.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
10811.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
10821.1Skamil
10831.180Skamil		if (masked) {
10841.180Skamil			sigemptyset(&intmask);
10851.180Skamil			sigaddset(&intmask, sigval);
10861.180Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
10871.180Skamil		}
10881.1Skamil
10891.180Skamil		if (ignored) {
10901.180Skamil			memset(&sa, 0, sizeof(sa));
10911.180Skamil			sa.sa_handler = SIG_IGN;
10921.180Skamil			sigemptyset(&sa.sa_mask);
10931.180Skamil			FORKEE_ASSERT(sigaction(sigval, &sa, NULL) != -1);
10941.180Skamil		}
10951.1Skamil
10961.180Skamil		DPRINTF("Before calling execve(2) from child\n");
10971.180Skamil		execlp("/bin/echo", "/bin/echo", NULL);
10981.1Skamil
10991.180Skamil		FORKEE_ASSERT(0 && "Not reached");
11001.1Skamil	}
11011.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
11021.1Skamil
11031.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11041.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11051.1Skamil
11061.1Skamil	validate_status_stopped(status, sigval);
11071.1Skamil
11081.180Skamil	name[0] = CTL_KERN,
11091.180Skamil	name[1] = KERN_PROC2,
11101.180Skamil	name[2] = KERN_PROC_PID;
11111.180Skamil	name[3] = getpid();
11121.180Skamil	name[4] = sizeof(kp);
11131.180Skamil	name[5] = 1;
11141.180Skamil
11151.180Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
11161.180Skamil
11171.180Skamil	if (masked)
11181.180Skamil		kp_sigmask = kp.p_sigmask;
11191.180Skamil
11201.180Skamil	if (ignored)
11211.180Skamil		kp_sigignore = kp.p_sigignore;
11221.180Skamil
11231.180Skamil	name[3] = getpid();
11241.180Skamil
11251.180Skamil	ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
11261.180Skamil
11271.180Skamil	if (masked) {
11281.180Skamil		DPRINTF("kp_sigmask="
11291.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
11301.180Skamil		    kp_sigmask.__bits[0], kp_sigmask.__bits[1],
11311.180Skamil		    kp_sigmask.__bits[2], kp_sigmask.__bits[3]);
11321.180Skamil
11331.180Skamil		DPRINTF("kp.p_sigmask="
11341.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
11351.180Skamil		    kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
11361.180Skamil		    kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
11371.180Skamil
11381.180Skamil		ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask,
11391.180Skamil		    sizeof(kp_sigmask)));
11401.180Skamil	}
11411.180Skamil
11421.180Skamil	if (ignored) {
11431.180Skamil		DPRINTF("kp_sigignore="
11441.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
11451.180Skamil		    kp_sigignore.__bits[0], kp_sigignore.__bits[1],
11461.180Skamil		    kp_sigignore.__bits[2], kp_sigignore.__bits[3]);
11471.180Skamil
11481.180Skamil		DPRINTF("kp.p_sigignore="
11491.180Skamil		    "%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
11501.180Skamil		    kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
11511.180Skamil		    kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
11521.180Skamil
11531.180Skamil		ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore,
11541.180Skamil		    sizeof(kp_sigignore)));
11551.180Skamil	}
11561.180Skamil
11571.180Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
11581.180Skamil	SYSCALL_REQUIRE(
11591.180Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
11601.1Skamil
11611.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
11621.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
11631.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
11641.180Skamil	    info.psi_siginfo.si_errno);
11651.1Skamil
11661.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
11671.180Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
11681.1Skamil
11691.13Schristos	DPRINTF("Before resuming the child process where it left off and "
11701.1Skamil	    "without signal to be sent\n");
11711.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
11721.1Skamil
11731.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11741.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11751.1Skamil
11761.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11771.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
11781.1Skamil}
11791.1Skamil
11801.180Skamil#define TRACEME_EXEC(test, masked, ignored)				\
11811.180SkamilATF_TC(test);								\
11821.180SkamilATF_TC_HEAD(test, tc)							\
11831.180Skamil{									\
11841.180Skamil       atf_tc_set_md_var(tc, "descr",					\
11851.180Skamil           "Detect SIGTRAP TRAP_EXEC from "				\
11861.180Skamil           "child%s%s", masked ? " with masked signal" : "",		\
11871.180Skamil           masked ? " with ignored signal" : "");			\
11881.180Skamil}									\
11891.180Skamil									\
11901.180SkamilATF_TC_BODY(test, tc)							\
11911.180Skamil{									\
11921.180Skamil									\
11931.180Skamil       traceme_exec(masked, ignored);					\
11941.180Skamil}
11951.180Skamil
11961.180SkamilTRACEME_EXEC(traceme_exec, false, false)
11971.180SkamilTRACEME_EXEC(traceme_signalmasked_exec, true, false)
11981.180SkamilTRACEME_EXEC(traceme_signalignored_exec, false, true)
11991.180Skamil
12001.84Skamil/// ----------------------------------------------------------------------------
12011.84Skamil
12021.180Skamil#define TRACE_THREADS_NUM 100
12031.180Skamil
12041.180Skamilstatic volatile int done;
12051.180Skamilpthread_mutex_t trace_threads_mtx = PTHREAD_MUTEX_INITIALIZER;
12061.180Skamil
12071.180Skamilstatic void *
12081.180Skamiltrace_threads_cb(void *arg __unused)
12091.180Skamil{
12101.180Skamil
12111.180Skamil	pthread_mutex_lock(&trace_threads_mtx);
12121.180Skamil	done++;
12131.180Skamil	pthread_mutex_unlock(&trace_threads_mtx);
12141.180Skamil
12151.180Skamil	while (done < TRACE_THREADS_NUM)
12161.180Skamil		sched_yield();
12171.180Skamil
12181.180Skamil	return NULL;
12191.180Skamil}
12201.180Skamil
12211.99Skamilstatic void
12221.180Skamiltrace_threads(bool trace_create, bool trace_exit, bool masked)
12231.1Skamil{
12241.1Skamil	const int sigval = SIGSTOP;
12251.180Skamil	pid_t child, wpid;
12261.1Skamil#if defined(TWAIT_HAVE_STATUS)
12271.1Skamil	int status;
12281.1Skamil#endif
12291.1Skamil	ptrace_state_t state;
12301.1Skamil	const int slen = sizeof(state);
12311.1Skamil	ptrace_event_t event;
12321.1Skamil	const int elen = sizeof(event);
12331.99Skamil	struct ptrace_siginfo info;
12341.180Skamil
12351.99Skamil	sigset_t intmask;
12361.99Skamil
12371.180Skamil	pthread_t t[TRACE_THREADS_NUM];
12381.180Skamil	int rv;
12391.180Skamil	size_t n;
12401.180Skamil	lwpid_t lid;
12411.1Skamil
12421.180Skamil	/* Track created and exited threads */
12431.180Skamil	struct lwp_event_count traced_lwps[__arraycount(t)] = {{0, 0}};
12441.14Schristos
12451.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
12461.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
12471.1Skamil	if (child == 0) {
12481.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
12491.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
12501.1Skamil
12511.99Skamil		if (masked) {
12521.99Skamil			sigemptyset(&intmask);
12531.99Skamil			sigaddset(&intmask, SIGTRAP);
12541.99Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
12551.99Skamil		}
12561.99Skamil
12571.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
12581.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
12591.1Skamil
12601.180Skamil		for (n = 0; n < __arraycount(t); n++) {
12611.180Skamil			rv = pthread_create(&t[n], NULL, trace_threads_cb,
12621.180Skamil			    NULL);
12631.180Skamil			FORKEE_ASSERT(rv == 0);
12641.126Skamil		}
12651.1Skamil
12661.180Skamil		for (n = 0; n < __arraycount(t); n++) {
12671.180Skamil			rv = pthread_join(t[n], NULL);
12681.180Skamil			FORKEE_ASSERT(rv == 0);
12691.180Skamil		}
12701.1Skamil
12711.180Skamil		/*
12721.180Skamil		 * There is race between _exit() and pthread_join() detaching
12731.180Skamil		 * a thread. For simplicity kill the process after detecting
12741.180Skamil		 * LWP events.
12751.180Skamil		 */
12761.180Skamil		while (true)
12771.180Skamil			continue;
12781.1Skamil
12791.180Skamil		FORKEE_ASSERT(0 && "Not reached");
12801.1Skamil	}
12811.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
12821.1Skamil
12831.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
12841.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
12851.1Skamil
12861.1Skamil	validate_status_stopped(status, sigval);
12871.1Skamil
12881.99Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
12891.99Skamil	SYSCALL_REQUIRE(
12901.99Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
12911.99Skamil
12921.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12931.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
12941.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12951.180Skamil	    info.psi_siginfo.si_errno);
12961.180Skamil
12971.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
12981.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
12991.1Skamil
13001.180Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
13011.180Skamil	memset(&event, 0, sizeof(event));
13021.180Skamil	if (trace_create)
13031.180Skamil		event.pe_set_event |= PTRACE_LWP_CREATE;
13041.180Skamil	if (trace_exit)
13051.180Skamil		event.pe_set_event |= PTRACE_LWP_EXIT;
13061.99Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
13071.1Skamil
13081.99Skamil	DPRINTF("Before resuming the child process where it left off and "
13091.99Skamil	    "without signal to be sent\n");
13101.99Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
13111.1Skamil
13121.180Skamil	for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
13131.180Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
13141.180Skamil		    "SIGTRAP\n", TWAIT_FNAME);
13151.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
13161.99Skamil		    child);
13171.1Skamil
13181.99Skamil		validate_status_stopped(status, SIGTRAP);
13191.1Skamil
13201.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
13211.180Skamil		    "child\n");
13221.180Skamil		SYSCALL_REQUIRE(
13231.180Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
13241.180Skamil
13251.180Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
13261.180Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
13271.180Skamil		    "si_errno=%#x\n",
13281.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
13291.180Skamil		    info.psi_siginfo.si_errno);
13301.1Skamil
13311.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
13321.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
13331.1Skamil
13341.180Skamil		SYSCALL_REQUIRE(
13351.180Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
13361.1Skamil
13371.180Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
13381.180Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
13391.1Skamil
13401.180Skamil		lid = state.pe_lwp;
13411.180Skamil		DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
13421.1Skamil
13431.180Skamil		*FIND_EVENT_COUNT(traced_lwps, lid) += 1;
13441.1Skamil
13451.180Skamil		DPRINTF("Before resuming the child process where it left off "
13461.180Skamil		    "and without signal to be sent\n");
13471.180Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
13481.180Skamil	}
13491.1Skamil
13501.180Skamil	for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
13511.180Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
13521.180Skamil		    "SIGTRAP\n", TWAIT_FNAME);
13531.180Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
13541.180Skamil		    child);
13551.1Skamil
13561.99Skamil		validate_status_stopped(status, SIGTRAP);
13571.1Skamil
13581.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
13591.180Skamil		    "child\n");
13601.180Skamil		SYSCALL_REQUIRE(
13611.180Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
13621.1Skamil
13631.180Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
13641.180Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
13651.180Skamil		    "si_errno=%#x\n",
13661.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
13671.180Skamil		    info.psi_siginfo.si_errno);
13681.1Skamil
13691.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
13701.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
13711.14Schristos
13721.180Skamil		SYSCALL_REQUIRE(
13731.180Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
13741.1Skamil
13751.180Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
13761.180Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
13771.1Skamil
13781.180Skamil		lid = state.pe_lwp;
13791.180Skamil		DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
13801.1Skamil
13811.180Skamil		if (trace_create) {
13821.180Skamil			int *count = FIND_EVENT_COUNT(traced_lwps, lid);
13831.180Skamil			ATF_REQUIRE_EQ(*count, 1);
13841.180Skamil			*count = 0;
13851.99Skamil		}
13861.1Skamil
13871.99Skamil		DPRINTF("Before resuming the child process where it left off "
13881.99Skamil		    "and without signal to be sent\n");
13891.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
13901.1Skamil	}
13911.1Skamil
13921.180Skamil	kill(child, SIGKILL);
13931.180Skamil
13941.180Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
13951.180Skamil	    TWAIT_FNAME);
13961.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
13971.180Skamil
13981.180Skamil	validate_status_signaled(status, SIGKILL, 0);
13991.1Skamil
14001.180Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
14011.180Skamil	    TWAIT_FNAME);
14021.180Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
14031.180Skamil}
14041.1Skamil
14051.180Skamil#define TRACE_THREADS(test, trace_create, trace_exit, mask)		\
14061.180SkamilATF_TC(test);								\
14071.180SkamilATF_TC_HEAD(test, tc)							\
14081.180Skamil{									\
14091.180Skamil        atf_tc_set_md_var(tc, "descr",					\
14101.180Skamil            "Verify spawning threads with%s tracing LWP create and"	\
14111.180Skamil	    "with%s tracing LWP exit", trace_create ? "" : "out",	\
14121.180Skamil	    trace_exit ? "" : "out");					\
14131.180Skamil}									\
14141.180Skamil									\
14151.180SkamilATF_TC_BODY(test, tc)							\
14161.180Skamil{									\
14171.180Skamil									\
14181.180Skamil        trace_threads(trace_create, trace_exit, mask);			\
14191.180Skamil}
14201.1Skamil
14211.180SkamilTRACE_THREADS(trace_thread_nolwpevents, false, false, false)
14221.180SkamilTRACE_THREADS(trace_thread_lwpexit, false, true, false)
14231.180SkamilTRACE_THREADS(trace_thread_lwpcreate, true, false, false)
14241.180SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true, false)
14251.102Skamil
14261.180SkamilTRACE_THREADS(trace_thread_lwpexit_masked_sigtrap, false, true, true)
14271.180SkamilTRACE_THREADS(trace_thread_lwpcreate_masked_sigtrap, true, false, true)
14281.180SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit_masked_sigtrap, true, true, true)
14291.1Skamil
14301.180Skamil/// ----------------------------------------------------------------------------
14311.1Skamil
14321.151Skamilstatic void *
14331.151Skamilthread_and_exec_thread_cb(void *arg __unused)
14341.151Skamil{
14351.151Skamil
14361.151Skamil	execlp("/bin/echo", "/bin/echo", NULL);
14371.151Skamil
14381.151Skamil	abort();
14391.151Skamil}
14401.151Skamil
14411.151Skamilstatic void
14421.151Skamilthreads_and_exec(void)
14431.151Skamil{
14441.151Skamil	const int sigval = SIGSTOP;
14451.151Skamil	pid_t child, wpid;
14461.151Skamil#if defined(TWAIT_HAVE_STATUS)
14471.151Skamil	int status;
14481.151Skamil#endif
14491.151Skamil	ptrace_state_t state;
14501.151Skamil	const int slen = sizeof(state);
14511.151Skamil	ptrace_event_t event;
14521.151Skamil	const int elen = sizeof(event);
14531.151Skamil	struct ptrace_siginfo info;
14541.151Skamil
14551.151Skamil	pthread_t t;
14561.151Skamil	lwpid_t lid;
14571.151Skamil
14581.151Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
14591.151Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
14601.151Skamil	if (child == 0) {
14611.151Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
14621.151Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
14631.151Skamil
14641.151Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
14651.151Skamil		FORKEE_ASSERT(raise(sigval) == 0);
14661.151Skamil
14671.151Skamil		FORKEE_ASSERT(pthread_create(&t, NULL,
14681.151Skamil		    thread_and_exec_thread_cb, NULL) == 0);
14691.151Skamil
14701.151Skamil		for (;;)
14711.151Skamil			continue;
14721.151Skamil
14731.151Skamil		FORKEE_ASSERT(0 && "Not reached");
14741.151Skamil	}
14751.151Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
14761.151Skamil
14771.151Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14781.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
14791.151Skamil
14801.151Skamil	validate_status_stopped(status, sigval);
14811.151Skamil
14821.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
14831.151Skamil	SYSCALL_REQUIRE(
14841.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
14851.151Skamil
14861.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
14871.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
14881.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
14891.151Skamil	    info.psi_siginfo.si_errno);
14901.151Skamil
14911.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
14921.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
14931.151Skamil
14941.151Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
14951.151Skamil	memset(&event, 0, sizeof(event));
14961.151Skamil	event.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
14971.151Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
14981.151Skamil
14991.151Skamil	DPRINTF("Before resuming the child process where it left off and "
15001.151Skamil	    "without signal to be sent\n");
15011.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
15021.151Skamil
15031.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
15041.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
15051.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
15061.151Skamil	    child);
15071.151Skamil
15081.151Skamil	validate_status_stopped(status, SIGTRAP);
15091.151Skamil
15101.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
15111.151Skamil	    "child\n");
15121.151Skamil	SYSCALL_REQUIRE(
15131.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
15141.151Skamil
15151.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
15161.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
15171.151Skamil	    "si_errno=%#x\n",
15181.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
15191.151Skamil	    info.psi_siginfo.si_errno);
15201.151Skamil
15211.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
15221.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
15231.151Skamil
15241.151Skamil	SYSCALL_REQUIRE(
15251.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
15261.151Skamil
15271.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
15281.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
15291.151Skamil
15301.151Skamil	lid = state.pe_lwp;
15311.151Skamil	DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
15321.151Skamil
15331.151Skamil	DPRINTF("Before resuming the child process where it left off "
15341.151Skamil	    "and without signal to be sent\n");
15351.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
15361.151Skamil
15371.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
15381.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
15391.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
15401.151Skamil	    child);
15411.151Skamil
15421.151Skamil	validate_status_stopped(status, SIGTRAP);
15431.151Skamil
15441.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
15451.151Skamil	    "child\n");
15461.151Skamil	SYSCALL_REQUIRE(
15471.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
15481.151Skamil
15491.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
15501.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
15511.151Skamil	    "si_errno=%#x\n",
15521.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
15531.151Skamil	    info.psi_siginfo.si_errno);
15541.151Skamil
15551.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
15561.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
15571.151Skamil
15581.151Skamil	SYSCALL_REQUIRE(
15591.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
15601.151Skamil
15611.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
15621.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
15631.151Skamil
15641.151Skamil	lid = state.pe_lwp;
15651.151Skamil	DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
15661.151Skamil
15671.151Skamil	DPRINTF("Before resuming the child process where it left off "
15681.151Skamil	    "and without signal to be sent\n");
15691.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
15701.151Skamil
15711.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
15721.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
15731.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
15741.151Skamil	    child);
15751.151Skamil
15761.151Skamil	validate_status_stopped(status, SIGTRAP);
15771.151Skamil
15781.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
15791.151Skamil	    "child\n");
15801.151Skamil	SYSCALL_REQUIRE(
15811.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
15821.151Skamil
15831.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
15841.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
15851.151Skamil	    "si_errno=%#x\n",
15861.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
15871.151Skamil	    info.psi_siginfo.si_errno);
15881.151Skamil
15891.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
15901.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
15911.151Skamil
15921.151Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
15931.151Skamil
15941.151Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
15951.151Skamil	    TWAIT_FNAME);
15961.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
15971.151Skamil
15981.151Skamil	validate_status_signaled(status, SIGKILL, 0);
15991.151Skamil
16001.151Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
16011.151Skamil	    TWAIT_FNAME);
16021.151Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
16031.151Skamil}
16041.151Skamil
16051.151SkamilATF_TC(threads_and_exec);
16061.151SkamilATF_TC_HEAD(threads_and_exec, tc)
16071.151Skamil{
16081.151Skamil        atf_tc_set_md_var(tc, "descr",
16091.151Skamil            "Verify that multithreaded application on exec() will report "
16101.151Skamil	    "LWP_EXIT events");
16111.151Skamil}
16121.151Skamil
16131.151SkamilATF_TC_BODY(threads_and_exec, tc)
16141.151Skamil{
16151.151Skamil
16161.151Skamil        threads_and_exec();
16171.151Skamil}
16181.151Skamil
16191.151Skamil/// ----------------------------------------------------------------------------
16201.151Skamil
16211.154SkamilATF_TC(suspend_no_deadlock);
16221.154SkamilATF_TC_HEAD(suspend_no_deadlock, tc)
16231.1Skamil{
16241.1Skamil	atf_tc_set_md_var(tc, "descr",
16251.1Skamil	    "Verify that the while the only thread within a process is "
16261.1Skamil	    "suspended, the whole process cannot be unstopped");
16271.1Skamil}
16281.1Skamil
16291.154SkamilATF_TC_BODY(suspend_no_deadlock, tc)
16301.1Skamil{
16311.1Skamil	const int exitval = 5;
16321.1Skamil	const int sigval = SIGSTOP;
16331.1Skamil	pid_t child, wpid;
16341.1Skamil#if defined(TWAIT_HAVE_STATUS)
16351.1Skamil	int status;
16361.1Skamil#endif
16371.1Skamil	struct ptrace_siginfo psi;
16381.1Skamil
16391.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
16401.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
16411.1Skamil	if (child == 0) {
16421.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
16431.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
16441.1Skamil
16451.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
16461.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
16471.1Skamil
16481.13Schristos		DPRINTF("Before exiting of the child process\n");
16491.1Skamil		_exit(exitval);
16501.1Skamil	}
16511.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
16521.1Skamil
16531.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
16541.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
16551.1Skamil
16561.1Skamil	validate_status_stopped(status, sigval);
16571.1Skamil
16581.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
16591.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
16601.1Skamil
16611.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
16621.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
16631.1Skamil
16641.13Schristos	DPRINTF("Before resuming the child process where it left off and "
16651.1Skamil	    "without signal to be sent\n");
16661.1Skamil	ATF_REQUIRE_ERRNO(EDEADLK,
16671.1Skamil	    ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
16681.1Skamil
16691.13Schristos	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
16701.13Schristos	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
16711.1Skamil
16721.13Schristos	DPRINTF("Before resuming the child process where it left off and "
16731.1Skamil	    "without signal to be sent\n");
16741.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
16751.1Skamil
16761.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
16771.1Skamil	    TWAIT_FNAME);
16781.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
16791.1Skamil
16801.1Skamil	validate_status_exited(status, exitval);
16811.1Skamil
16821.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
16831.1Skamil	    TWAIT_FNAME);
16841.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
16851.1Skamil}
16861.1Skamil
16871.154Skamil/// ----------------------------------------------------------------------------
16881.154Skamil
16891.155Skamilstatic pthread_barrier_t barrier1_resume;
16901.155Skamilstatic pthread_barrier_t barrier2_resume;
16911.154Skamil
16921.155Skamilstatic void *
16931.155Skamilresume_thread(void *arg)
16941.154Skamil{
16951.154Skamil
16961.155Skamil	raise(SIGUSR1);
16971.155Skamil
16981.155Skamil	pthread_barrier_wait(&barrier1_resume);
16991.155Skamil
17001.155Skamil	/* Debugger will suspend the process here */
17011.155Skamil
17021.155Skamil	pthread_barrier_wait(&barrier2_resume);
17031.154Skamil
17041.155Skamil	raise(SIGUSR2);
17051.155Skamil
17061.155Skamil	return infinite_thread(arg);
17071.154Skamil}
17081.154Skamil
17091.155SkamilATF_TC(resume);
17101.155SkamilATF_TC_HEAD(resume, tc)
17111.1Skamil{
17121.1Skamil	atf_tc_set_md_var(tc, "descr",
17131.1Skamil	    "Verify that a thread can be suspended by a debugger and later "
17141.1Skamil	    "resumed by the debugger");
17151.1Skamil}
17161.1Skamil
17171.155SkamilATF_TC_BODY(resume, tc)
17181.1Skamil{
17191.1Skamil	const int sigval = SIGSTOP;
17201.1Skamil	pid_t child, wpid;
17211.1Skamil#if defined(TWAIT_HAVE_STATUS)
17221.1Skamil	int status;
17231.1Skamil#endif
17241.1Skamil	lwpid_t lid;
17251.1Skamil	struct ptrace_siginfo psi;
17261.155Skamil	pthread_t t;
17271.1Skamil
17281.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
17291.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
17301.1Skamil	if (child == 0) {
17311.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
17321.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
17331.1Skamil
17341.155Skamil		pthread_barrier_init(&barrier1_resume, NULL, 2);
17351.155Skamil		pthread_barrier_init(&barrier2_resume, NULL, 2);
17361.155Skamil
17371.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
17381.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
17391.1Skamil
17401.155Skamil		DPRINTF("Before creating new thread in child\n");
17411.155Skamil		FORKEE_ASSERT(pthread_create(&t, NULL, resume_thread, NULL) == 0);
17421.1Skamil
17431.155Skamil		pthread_barrier_wait(&barrier1_resume);
17441.1Skamil
17451.155Skamil		pthread_barrier_wait(&barrier2_resume);
17461.1Skamil
17471.155Skamil		infinite_thread(NULL);
17481.1Skamil	}
17491.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
17501.1Skamil
17511.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17521.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17531.1Skamil
17541.1Skamil	validate_status_stopped(status, sigval);
17551.1Skamil
17561.13Schristos	DPRINTF("Before resuming the child process where it left off and "
17571.1Skamil	    "without signal to be sent\n");
17581.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
17591.1Skamil
17601.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
17611.155Skamil	    "SIGUSR1\n", TWAIT_FNAME);
17621.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17631.1Skamil
17641.155Skamil	validate_status_stopped(status, SIGUSR1);
17651.1Skamil
17661.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
17671.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
17681.1Skamil
17691.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
17701.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
17711.1Skamil
17721.155Skamil	lid = psi.psi_lwpid;
17731.1Skamil
17741.13Schristos	DPRINTF("Before resuming the child process where it left off and "
17751.1Skamil	    "without signal to be sent\n");
17761.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
17771.1Skamil
17781.155Skamil	DPRINTF("Before suspending the parent for 1 second, we expect no signals\n");
17791.155Skamil	SYSCALL_REQUIRE(sleep(1) == 0);
17801.155Skamil
17811.155Skamil#if defined(TWAIT_HAVE_OPTIONS)
17821.155Skamil	DPRINTF("Before calling %s() for the child - expected no status\n",
17831.155Skamil	    TWAIT_FNAME);
17841.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, WNOHANG), 0);
17851.155Skamil#endif
17861.155Skamil
17871.155Skamil	DPRINTF("Before resuming the child process where it left off and "
17881.155Skamil	    "without signal to be sent\n");
17891.155Skamil	SYSCALL_REQUIRE(ptrace(PT_STOP, child, NULL, 0) != -1);
17901.155Skamil
17911.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
17921.155Skamil	    "SIGSTOP\n", TWAIT_FNAME);
17931.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17941.1Skamil
17951.155Skamil	validate_status_stopped(status, SIGSTOP);
17961.1Skamil
17971.155Skamil	DPRINTF("Before resuming LWP %d\n", lid);
17981.155Skamil	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, lid) != -1);
17991.155Skamil
18001.155Skamil	DPRINTF("Before resuming the child process where it left off and "
18011.155Skamil	    "without signal to be sent\n");
18021.155Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
18031.1Skamil
18041.155Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
18051.155Skamil	    "SIGUSR2\n", TWAIT_FNAME);
18061.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
18071.1Skamil
18081.155Skamil	validate_status_stopped(status, SIGUSR2);
18091.1Skamil
18101.13Schristos	DPRINTF("Before resuming the child process where it left off and "
18111.1Skamil	    "without signal to be sent\n");
18121.155Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
18131.1Skamil
18141.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
18151.1Skamil	    TWAIT_FNAME);
18161.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
18171.1Skamil
18181.155Skamil	validate_status_signaled(status, SIGKILL, 0);
18191.1Skamil
18201.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
18211.1Skamil	    TWAIT_FNAME);
18221.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
18231.155Skamil}
18241.1Skamil
18251.155Skamil/// ----------------------------------------------------------------------------
18261.1Skamil
18271.106Skamilstatic void
18281.122Skamiluser_va0_disable(int operation)
18291.122Skamil{
18301.122Skamil	pid_t child, wpid;
18311.122Skamil#if defined(TWAIT_HAVE_STATUS)
18321.122Skamil	int status;
18331.122Skamil#endif
18341.122Skamil	const int sigval = SIGSTOP;
18351.122Skamil	int rv;
18361.122Skamil
18371.122Skamil	struct ptrace_siginfo info;
18381.122Skamil
18391.122Skamil	if (get_user_va0_disable() == 0)
18401.122Skamil		atf_tc_skip("vm.user_va0_disable is set to 0");
18411.122Skamil
18421.122Skamil	memset(&info, 0, sizeof(info));
18431.122Skamil
18441.122Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
18451.122Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
18461.122Skamil	if (child == 0) {
18471.122Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
18481.122Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
18491.122Skamil
18501.122Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
18511.122Skamil		FORKEE_ASSERT(raise(sigval) == 0);
18521.122Skamil
18531.122Skamil		/* NOTREACHED */
18541.122Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
18551.122Skamil		__unreachable();
18561.122Skamil	}
18571.122Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
18581.122Skamil
18591.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18601.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
18611.122Skamil
18621.122Skamil	validate_status_stopped(status, sigval);
18631.122Skamil
18641.122Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
18651.122Skamil		"child\n");
18661.122Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
18671.122Skamil		sizeof(info)) != -1);
18681.122Skamil
18691.122Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
18701.122Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
18711.122Skamil		"si_errno=%#x\n",
18721.122Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
18731.122Skamil		info.psi_siginfo.si_errno);
18741.122Skamil
18751.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
18761.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
18771.122Skamil
18781.122Skamil	DPRINTF("Before resuming the child process in PC=0x0 "
18791.122Skamil	    "and without signal to be sent\n");
18801.122Skamil	errno = 0;
18811.122Skamil	rv = ptrace(operation, child, (void *)0, 0);
18821.122Skamil	ATF_REQUIRE_EQ(errno, EINVAL);
18831.122Skamil	ATF_REQUIRE_EQ(rv, -1);
18841.122Skamil
18851.122Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
18861.122Skamil
18871.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18881.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
18891.122Skamil	validate_status_signaled(status, SIGKILL, 0);
18901.122Skamil
18911.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18921.122Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
18931.122Skamil}
18941.122Skamil
18951.122Skamil#define USER_VA0_DISABLE(test, operation)				\
18961.122SkamilATF_TC(test);								\
18971.122SkamilATF_TC_HEAD(test, tc)							\
18981.122Skamil{									\
18991.122Skamil	atf_tc_set_md_var(tc, "descr",					\
19001.122Skamil	    "Verify behavior of " #operation " with PC set to 0x0");	\
19011.122Skamil}									\
19021.122Skamil									\
19031.122SkamilATF_TC_BODY(test, tc)							\
19041.122Skamil{									\
19051.122Skamil									\
19061.122Skamil	user_va0_disable(operation);					\
19071.122Skamil}
19081.122Skamil
19091.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_continue, PT_CONTINUE)
19101.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_syscall, PT_SYSCALL)
19111.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_detach, PT_DETACH)
19121.122Skamil
19131.122Skamil/// ----------------------------------------------------------------------------
19141.122Skamil
19151.130Smgorny/*
19161.130Smgorny * Parse the core file and find the requested note.  If the reading or parsing
19171.130Smgorny * fails, the test is failed.  If the note is found, it is read onto buf, up to
19181.130Smgorny * buf_len.  The actual length of the note is returned (which can be greater
19191.130Smgorny * than buf_len, indicating that it has been truncated).  If the note is not
19201.130Smgorny * found, -1 is returned.
19211.172Sthorpej *
19221.172Sthorpej * If the note_name ends in '*', then we find the first note that matches
19231.172Sthorpej * the note_name prefix up to the '*' character, e.g.:
19241.172Sthorpej *
19251.172Sthorpej *	NetBSD-CORE@*
19261.172Sthorpej *
19271.172Sthorpej * finds the first note whose name prefix matches "NetBSD-CORE@".
19281.130Smgorny */
19291.130Smgornystatic ssize_t core_find_note(const char *core_path,
19301.130Smgorny    const char *note_name, uint64_t note_type, void *buf, size_t buf_len)
19311.130Smgorny{
19321.130Smgorny	int core_fd;
19331.130Smgorny	Elf *core_elf;
19341.130Smgorny	size_t core_numhdr, i;
19351.130Smgorny	ssize_t ret = -1;
19361.172Sthorpej	size_t name_len = strlen(note_name);
19371.172Sthorpej	bool prefix_match = false;
19381.172Sthorpej
19391.172Sthorpej	if (note_name[name_len - 1] == '*') {
19401.172Sthorpej		prefix_match = true;
19411.172Sthorpej		name_len--;
19421.172Sthorpej	} else {
19431.172Sthorpej		/* note: we assume note name will be null-terminated */
19441.172Sthorpej		name_len++;
19451.172Sthorpej	}
19461.130Smgorny
19471.130Smgorny	SYSCALL_REQUIRE((core_fd = open(core_path, O_RDONLY)) != -1);
19481.130Smgorny	SYSCALL_REQUIRE(elf_version(EV_CURRENT) != EV_NONE);
19491.130Smgorny	SYSCALL_REQUIRE((core_elf = elf_begin(core_fd, ELF_C_READ, NULL)));
19501.130Smgorny
19511.130Smgorny	SYSCALL_REQUIRE(elf_getphnum(core_elf, &core_numhdr) != 0);
19521.130Smgorny	for (i = 0; i < core_numhdr && ret == -1; i++) {
19531.130Smgorny		GElf_Phdr core_hdr;
19541.130Smgorny		size_t offset;
19551.130Smgorny		SYSCALL_REQUIRE(gelf_getphdr(core_elf, i, &core_hdr));
19561.130Smgorny		if (core_hdr.p_type != PT_NOTE)
19571.130Smgorny		    continue;
19581.130Smgorny
19591.130Smgorny		for (offset = core_hdr.p_offset;
19601.130Smgorny		    offset < core_hdr.p_offset + core_hdr.p_filesz;) {
19611.130Smgorny			Elf64_Nhdr note_hdr;
19621.130Smgorny			char name_buf[64];
19631.130Smgorny
19641.130Smgorny			switch (gelf_getclass(core_elf)) {
19651.130Smgorny			case ELFCLASS64:
19661.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &note_hdr,
19671.130Smgorny				    sizeof(note_hdr), offset)
19681.130Smgorny				    == sizeof(note_hdr));
19691.130Smgorny				offset += sizeof(note_hdr);
19701.130Smgorny				break;
19711.130Smgorny			case ELFCLASS32:
19721.130Smgorny				{
19731.130Smgorny				Elf32_Nhdr tmp_hdr;
19741.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &tmp_hdr,
19751.130Smgorny				    sizeof(tmp_hdr), offset)
19761.130Smgorny				    == sizeof(tmp_hdr));
19771.130Smgorny				offset += sizeof(tmp_hdr);
19781.130Smgorny				note_hdr.n_namesz = tmp_hdr.n_namesz;
19791.130Smgorny				note_hdr.n_descsz = tmp_hdr.n_descsz;
19801.130Smgorny				note_hdr.n_type = tmp_hdr.n_type;
19811.130Smgorny				}
19821.130Smgorny				break;
19831.130Smgorny			}
19841.130Smgorny
19851.130Smgorny			/* indicates end of notes */
19861.130Smgorny			if (note_hdr.n_namesz == 0 || note_hdr.n_descsz == 0)
19871.130Smgorny				break;
19881.172Sthorpej			if (((prefix_match &&
19891.172Sthorpej			      note_hdr.n_namesz > name_len) ||
19901.172Sthorpej			     (!prefix_match &&
19911.172Sthorpej			      note_hdr.n_namesz == name_len)) &&
19921.130Smgorny			    note_hdr.n_namesz <= sizeof(name_buf)) {
19931.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, name_buf,
19941.130Smgorny				    note_hdr.n_namesz, offset)
19951.131Skamil				    == (ssize_t)(size_t)note_hdr.n_namesz);
19961.130Smgorny
19971.130Smgorny				if (!strncmp(note_name, name_buf, name_len) &&
19981.130Smgorny				    note_hdr.n_type == note_type)
19991.130Smgorny					ret = note_hdr.n_descsz;
20001.130Smgorny			}
20011.130Smgorny
20021.130Smgorny			offset += note_hdr.n_namesz;
20031.130Smgorny			/* fix to alignment */
20041.146Smgorny			offset = roundup(offset, core_hdr.p_align);
20051.130Smgorny
20061.130Smgorny			/* if name & type matched above */
20071.130Smgorny			if (ret != -1) {
20081.130Smgorny				ssize_t read_len = MIN(buf_len,
20091.130Smgorny				    note_hdr.n_descsz);
20101.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, buf,
20111.130Smgorny				    read_len, offset) == read_len);
20121.130Smgorny				break;
20131.130Smgorny			}
20141.130Smgorny
20151.130Smgorny			offset += note_hdr.n_descsz;
20161.146Smgorny			/* fix to alignment */
20171.146Smgorny			offset = roundup(offset, core_hdr.p_align);
20181.130Smgorny		}
20191.130Smgorny	}
20201.130Smgorny
20211.130Smgorny	elf_end(core_elf);
20221.130Smgorny	close(core_fd);
20231.130Smgorny
20241.130Smgorny	return ret;
20251.130Smgorny}
20261.130Smgorny
20271.130SmgornyATF_TC(core_dump_procinfo);
20281.130SmgornyATF_TC_HEAD(core_dump_procinfo, tc)
20291.130Smgorny{
20301.130Smgorny	atf_tc_set_md_var(tc, "descr",
20311.130Smgorny		"Trigger a core dump and verify its contents.");
20321.130Smgorny}
20331.130Smgorny
20341.130SmgornyATF_TC_BODY(core_dump_procinfo, tc)
20351.130Smgorny{
20361.130Smgorny	const int exitval = 5;
20371.130Smgorny	pid_t child, wpid;
20381.130Smgorny#if defined(TWAIT_HAVE_STATUS)
20391.130Smgorny	const int sigval = SIGTRAP;
20401.130Smgorny	int status;
20411.130Smgorny#endif
20421.130Smgorny	char core_path[] = "/tmp/core.XXXXXX";
20431.130Smgorny	int core_fd;
20441.130Smgorny	struct netbsd_elfcore_procinfo procinfo;
20451.130Smgorny
20461.130Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
20471.130Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
20481.130Smgorny	if (child == 0) {
20491.130Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
20501.130Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
20511.130Smgorny
20521.130Smgorny		DPRINTF("Before triggering SIGTRAP\n");
20531.130Smgorny		trigger_trap();
20541.130Smgorny
20551.130Smgorny		DPRINTF("Before exiting of the child process\n");
20561.130Smgorny		_exit(exitval);
20571.130Smgorny	}
20581.130Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
20591.130Smgorny
20601.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
20611.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
20621.130Smgorny
20631.130Smgorny	validate_status_stopped(status, sigval);
20641.130Smgorny
20651.130Smgorny	SYSCALL_REQUIRE((core_fd = mkstemp(core_path)) != -1);
20661.130Smgorny	close(core_fd);
20671.130Smgorny
20681.130Smgorny	DPRINTF("Call DUMPCORE for the child process\n");
20691.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_DUMPCORE, child, core_path, strlen(core_path))
20701.130Smgorny	    != -1);
20711.130Smgorny
20721.130Smgorny	DPRINTF("Read core file\n");
20731.130Smgorny	ATF_REQUIRE_EQ(core_find_note(core_path, "NetBSD-CORE",
20741.130Smgorny	    ELF_NOTE_NETBSD_CORE_PROCINFO, &procinfo, sizeof(procinfo)),
20751.130Smgorny	    sizeof(procinfo));
20761.130Smgorny
20771.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_version, 1);
20781.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_cpisize, sizeof(procinfo));
20791.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_signo, SIGTRAP);
20801.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pid, child);
20811.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ppid, getpid());
20821.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pgrp, getpgid(child));
20831.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_sid, getsid(child));
20841.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ruid, getuid());
20851.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_euid, geteuid());
20861.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_rgid, getgid());
20871.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_egid, getegid());
20881.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_nlwps, 1);
20891.173Skamil	ATF_CHECK(procinfo.cpi_siglwp > 0);
20901.130Smgorny
20911.130Smgorny	unlink(core_path);
20921.130Smgorny
20931.130Smgorny	DPRINTF("Before resuming the child process where it left off and "
20941.130Smgorny	    "without signal to be sent\n");
20951.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
20961.130Smgorny
20971.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
20981.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
20991.130Smgorny
21001.130Smgorny	validate_status_exited(status, exitval);
21011.130Smgorny
21021.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
21031.130Smgorny	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
21041.130Smgorny}
21051.130Smgorny
21061.130Smgorny/// ----------------------------------------------------------------------------
21071.130Smgorny
21081.138Smgorny#if defined(TWAIT_HAVE_STATUS)
21091.138Smgorny
21101.160Smgorny#define THREAD_CONCURRENT_BREAKPOINT_NUM 50
21111.156Smgorny#define THREAD_CONCURRENT_SIGNALS_NUM 50
21121.161Smgorny#define THREAD_CONCURRENT_WATCHPOINT_NUM 50
21131.138Smgorny
21141.138Smgorny/* List of signals to use for the test */
21151.138Smgornyconst int thread_concurrent_signals_list[] = {
21161.138Smgorny	SIGIO,
21171.138Smgorny	SIGXCPU,
21181.138Smgorny	SIGXFSZ,
21191.138Smgorny	SIGVTALRM,
21201.138Smgorny	SIGPROF,
21211.138Smgorny	SIGWINCH,
21221.138Smgorny	SIGINFO,
21231.138Smgorny	SIGUSR1,
21241.138Smgorny	SIGUSR2
21251.138Smgorny};
21261.138Smgorny
21271.157Smgornyenum thread_concurrent_signal_handling {
21281.157Smgorny	/* the signal is discarded by debugger */
21291.157Smgorny	TCSH_DISCARD,
21301.157Smgorny	/* the handler is set to SIG_IGN */
21311.157Smgorny	TCSH_SIG_IGN,
21321.157Smgorny	/* an actual handler is used */
21331.157Smgorny	TCSH_HANDLER
21341.157Smgorny};
21351.157Smgorny
21361.156Smgornystatic pthread_barrier_t thread_concurrent_barrier;
21371.158Smgornystatic pthread_key_t thread_concurrent_key;
21381.161Smgornystatic uint32_t thread_concurrent_watchpoint_var = 0;
21391.138Smgorny
21401.160Smgornystatic void *
21411.160Smgornythread_concurrent_breakpoint_thread(void *arg)
21421.160Smgorny{
21431.160Smgorny	static volatile int watchme = 1;
21441.160Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
21451.160Smgorny	DPRINTF("Before entering breakpoint func from LWP %d\n", _lwp_self());
21461.160Smgorny	check_happy(watchme);
21471.160Smgorny	return NULL;
21481.160Smgorny}
21491.160Smgorny
21501.157Smgornystatic void
21511.157Smgornythread_concurrent_sig_handler(int sig)
21521.157Smgorny{
21531.158Smgorny	void *tls_val = pthread_getspecific(thread_concurrent_key);
21541.158Smgorny	DPRINTF("Before increment, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
21551.158Smgorny	FORKEE_ASSERT(pthread_setspecific(thread_concurrent_key,
21561.158Smgorny	    (void*)((uintptr_t)tls_val + 1)) == 0);
21571.157Smgorny}
21581.157Smgorny
21591.138Smgornystatic void *
21601.138Smgornythread_concurrent_signals_thread(void *arg)
21611.138Smgorny{
21621.138Smgorny	int sigval = thread_concurrent_signals_list[
21631.138Smgorny	    _lwp_self() % __arraycount(thread_concurrent_signals_list)];
21641.158Smgorny	enum thread_concurrent_signal_handling *signal_handle = arg;
21651.158Smgorny	void *tls_val;
21661.158Smgorny
21671.156Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
21681.138Smgorny	DPRINTF("Before raising %s from LWP %d\n", strsignal(sigval),
21691.138Smgorny		_lwp_self());
21701.138Smgorny	pthread_kill(pthread_self(), sigval);
21711.158Smgorny	if (*signal_handle == TCSH_HANDLER) {
21721.158Smgorny	    tls_val = pthread_getspecific(thread_concurrent_key);
21731.158Smgorny	    DPRINTF("After raising, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
21741.158Smgorny	    FORKEE_ASSERT(tls_val == (void*)1);
21751.158Smgorny	}
21761.138Smgorny	return NULL;
21771.138Smgorny}
21781.138Smgorny
21791.161Smgornystatic void *
21801.161Smgornythread_concurrent_watchpoint_thread(void *arg)
21811.161Smgorny{
21821.161Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
21831.161Smgorny	DPRINTF("Before modifying var from LWP %d\n", _lwp_self());
21841.161Smgorny	thread_concurrent_watchpoint_var = 1;
21851.161Smgorny	return NULL;
21861.161Smgorny}
21871.161Smgorny
21881.160Smgorny#if defined(__i386__) || defined(__x86_64__)
21891.160Smgornyenum thread_concurrent_sigtrap_event {
21901.160Smgorny	TCSE_UNKNOWN,
21911.161Smgorny	TCSE_BREAKPOINT,
21921.161Smgorny	TCSE_WATCHPOINT
21931.160Smgorny};
21941.160Smgorny
21951.160Smgornystatic void
21961.160Smgornythread_concurrent_lwp_setup(pid_t child, lwpid_t lwpid);
21971.160Smgornystatic enum thread_concurrent_sigtrap_event
21981.160Smgornythread_concurrent_handle_sigtrap(pid_t child, ptrace_siginfo_t *info);
21991.160Smgorny#endif
22001.160Smgorny
22011.156Smgornystatic void
22021.157Smgornythread_concurrent_test(enum thread_concurrent_signal_handling signal_handle,
22031.161Smgorny    int breakpoint_threads, int signal_threads, int watchpoint_threads)
22041.138Smgorny{
22051.138Smgorny	const int exitval = 5;
22061.138Smgorny	const int sigval = SIGSTOP;
22071.138Smgorny	pid_t child, wpid;
22081.138Smgorny	int status;
22091.141Skamil	struct lwp_event_count signal_counts[THREAD_CONCURRENT_SIGNALS_NUM]
22101.141Skamil	    = {{0, 0}};
22111.160Smgorny	struct lwp_event_count bp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
22121.160Smgorny	    = {{0, 0}};
22131.161Smgorny	struct lwp_event_count wp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
22141.161Smgorny	    = {{0, 0}};
22151.159Smgorny	ptrace_event_t event;
22161.156Smgorny	int i;
22171.156Smgorny
22181.164Skamil#if defined(HAVE_DBREGS)
22191.164Skamil	if (!can_we_set_dbregs()) {
22201.164Skamil		atf_tc_skip("Either run this test as root or set sysctl(3) "
22211.164Skamil		            "security.models.extensions.user_set_dbregs to 1");
22221.164Skamil        }
22231.164Skamil#endif
22241.164Skamil
22251.164Skamil	atf_tc_skip("PR kern/54960");
22261.157Smgorny
22271.156Smgorny	/* Protect against out-of-bounds array access. */
22281.160Smgorny	ATF_REQUIRE(breakpoint_threads <= THREAD_CONCURRENT_BREAKPOINT_NUM);
22291.156Smgorny	ATF_REQUIRE(signal_threads <= THREAD_CONCURRENT_SIGNALS_NUM);
22301.161Smgorny	ATF_REQUIRE(watchpoint_threads <= THREAD_CONCURRENT_WATCHPOINT_NUM);
22311.138Smgorny
22321.138Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
22331.138Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
22341.138Smgorny	if (child == 0) {
22351.160Smgorny		pthread_t bp_threads[THREAD_CONCURRENT_BREAKPOINT_NUM];
22361.156Smgorny		pthread_t sig_threads[THREAD_CONCURRENT_SIGNALS_NUM];
22371.161Smgorny		pthread_t wp_threads[THREAD_CONCURRENT_WATCHPOINT_NUM];
22381.138Smgorny
22391.138Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
22401.138Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
22411.138Smgorny
22421.138Smgorny		DPRINTF("Before raising %s from child\n", strsignal(sigval));
22431.138Smgorny		FORKEE_ASSERT(raise(sigval) == 0);
22441.138Smgorny
22451.157Smgorny		if (signal_handle != TCSH_DISCARD) {
22461.157Smgorny			struct sigaction sa;
22471.157Smgorny			unsigned int j;
22481.157Smgorny
22491.157Smgorny			memset(&sa, 0, sizeof(sa));
22501.157Smgorny			if (signal_handle == TCSH_SIG_IGN)
22511.157Smgorny				sa.sa_handler = SIG_IGN;
22521.157Smgorny			else
22531.157Smgorny				sa.sa_handler = thread_concurrent_sig_handler;
22541.157Smgorny			sigemptyset(&sa.sa_mask);
22551.157Smgorny
22561.157Smgorny			for (j = 0;
22571.157Smgorny			    j < __arraycount(thread_concurrent_signals_list);
22581.157Smgorny			    j++)
22591.157Smgorny				FORKEE_ASSERT(sigaction(
22601.157Smgorny				    thread_concurrent_signals_list[j], &sa, NULL)
22611.157Smgorny				    != -1);
22621.157Smgorny		}
22631.157Smgorny
22641.138Smgorny		DPRINTF("Before starting threads from the child\n");
22651.138Smgorny		FORKEE_ASSERT(pthread_barrier_init(
22661.156Smgorny		    &thread_concurrent_barrier, NULL,
22671.161Smgorny		    breakpoint_threads + signal_threads + watchpoint_threads)
22681.161Smgorny		    == 0);
22691.158Smgorny		FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL)
22701.158Smgorny		    == 0);
22711.138Smgorny
22721.156Smgorny		for (i = 0; i < signal_threads; i++) {
22731.156Smgorny			FORKEE_ASSERT(pthread_create(&sig_threads[i], NULL,
22741.158Smgorny			    thread_concurrent_signals_thread,
22751.158Smgorny			    &signal_handle) == 0);
22761.138Smgorny		}
22771.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
22781.160Smgorny			FORKEE_ASSERT(pthread_create(&bp_threads[i], NULL,
22791.160Smgorny			    thread_concurrent_breakpoint_thread, NULL) == 0);
22801.160Smgorny		}
22811.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
22821.161Smgorny			FORKEE_ASSERT(pthread_create(&wp_threads[i], NULL,
22831.161Smgorny			    thread_concurrent_watchpoint_thread, NULL) == 0);
22841.161Smgorny		}
22851.138Smgorny
22861.138Smgorny		DPRINTF("Before joining threads from the child\n");
22871.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
22881.161Smgorny			FORKEE_ASSERT(pthread_join(wp_threads[i], NULL) == 0);
22891.161Smgorny		}
22901.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
22911.160Smgorny			FORKEE_ASSERT(pthread_join(bp_threads[i], NULL) == 0);
22921.160Smgorny		}
22931.156Smgorny		for (i = 0; i < signal_threads; i++) {
22941.156Smgorny			FORKEE_ASSERT(pthread_join(sig_threads[i], NULL) == 0);
22951.138Smgorny		}
22961.138Smgorny
22971.158Smgorny		FORKEE_ASSERT(pthread_key_delete(thread_concurrent_key) == 0);
22981.138Smgorny		FORKEE_ASSERT(pthread_barrier_destroy(
22991.156Smgorny		    &thread_concurrent_barrier) == 0);
23001.138Smgorny
23011.138Smgorny		DPRINTF("Before exiting of the child process\n");
23021.138Smgorny		_exit(exitval);
23031.138Smgorny	}
23041.138Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
23051.138Smgorny
23061.138Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
23071.138Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
23081.138Smgorny
23091.138Smgorny	validate_status_stopped(status, sigval);
23101.138Smgorny
23111.159Smgorny	DPRINTF("Set LWP event mask for the child process\n");
23121.159Smgorny	memset(&event, 0, sizeof(event));
23131.159Smgorny	event.pe_set_event |= PTRACE_LWP_CREATE;
23141.159Smgorny	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, sizeof(event))
23151.159Smgorny	    != -1);
23161.159Smgorny
23171.138Smgorny	DPRINTF("Before resuming the child process where it left off\n");
23181.138Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
23191.138Smgorny
23201.138Smgorny	DPRINTF("Before entering signal collection loop\n");
23211.138Smgorny	while (1) {
23221.138Smgorny		ptrace_siginfo_t info;
23231.138Smgorny
23241.138Smgorny		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
23251.138Smgorny		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
23261.138Smgorny		    child);
23271.138Smgorny		if (WIFEXITED(status))
23281.138Smgorny			break;
23291.138Smgorny		/* Note: we use validate_status_stopped() to get nice error
23301.138Smgorny		 * message.  Signal is irrelevant since it won't be reached.
23311.138Smgorny		 */
23321.138Smgorny		else if (!WIFSTOPPED(status))
23331.138Smgorny			validate_status_stopped(status, 0);
23341.138Smgorny
23351.138Smgorny		DPRINTF("Before calling PT_GET_SIGINFO\n");
23361.138Smgorny		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
23371.138Smgorny		    sizeof(info)) != -1);
23381.138Smgorny
23391.138Smgorny		DPRINTF("Received signal %d from LWP %d (wait: %d)\n",
23401.138Smgorny		    info.psi_siginfo.si_signo, info.psi_lwpid,
23411.138Smgorny		    WSTOPSIG(status));
23421.138Smgorny
23431.159Smgorny		ATF_CHECK_EQ_MSG(info.psi_siginfo.si_signo, WSTOPSIG(status),
23441.159Smgorny		    "lwp=%d, WSTOPSIG=%d, psi_siginfo=%d", info.psi_lwpid,
23451.159Smgorny		    WSTOPSIG(status), info.psi_siginfo.si_signo);
23461.159Smgorny
23471.159Smgorny		if (WSTOPSIG(status) != SIGTRAP) {
23481.159Smgorny			int expected_sig =
23491.159Smgorny			    thread_concurrent_signals_list[info.psi_lwpid %
23501.159Smgorny			    __arraycount(thread_concurrent_signals_list)];
23511.159Smgorny			ATF_CHECK_EQ_MSG(WSTOPSIG(status), expected_sig,
23521.159Smgorny				"lwp=%d, expected %d, got %d", info.psi_lwpid,
23531.159Smgorny				expected_sig, WSTOPSIG(status));
23541.138Smgorny
23551.159Smgorny			*FIND_EVENT_COUNT(signal_counts, info.psi_lwpid) += 1;
23561.160Smgorny		} else if (info.psi_siginfo.si_code == TRAP_LWP) {
23571.160Smgorny#if defined(__i386__) || defined(__x86_64__)
23581.160Smgorny			thread_concurrent_lwp_setup(child, info.psi_lwpid);
23591.160Smgorny#endif
23601.159Smgorny		} else {
23611.160Smgorny#if defined(__i386__) || defined(__x86_64__)
23621.160Smgorny			switch (thread_concurrent_handle_sigtrap(child, &info)) {
23631.160Smgorny				case TCSE_UNKNOWN:
23641.160Smgorny					/* already reported inside the function */
23651.160Smgorny					break;
23661.160Smgorny				case TCSE_BREAKPOINT:
23671.160Smgorny					*FIND_EVENT_COUNT(bp_counts,
23681.160Smgorny					    info.psi_lwpid) += 1;
23691.160Smgorny					break;
23701.161Smgorny				case TCSE_WATCHPOINT:
23711.161Smgorny					*FIND_EVENT_COUNT(wp_counts,
23721.161Smgorny					    info.psi_lwpid) += 1;
23731.161Smgorny					break;
23741.160Smgorny			}
23751.160Smgorny#else
23761.160Smgorny			ATF_CHECK_MSG(0, "Unexpected SIGTRAP, si_code=%d\n",
23771.160Smgorny			    info.psi_siginfo.si_code);
23781.160Smgorny#endif
23791.159Smgorny		}
23801.138Smgorny
23811.138Smgorny		DPRINTF("Before resuming the child process\n");
23821.157Smgorny		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
23831.159Smgorny		     signal_handle != TCSH_DISCARD && WSTOPSIG(status) != SIGTRAP
23841.159Smgorny		     ? WSTOPSIG(status) : 0) != -1);
23851.138Smgorny	}
23861.138Smgorny
23871.156Smgorny	for (i = 0; i < signal_threads; i++)
23881.141Skamil		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 1,
23891.141Skamil		    "signal_counts[%d].lec_count=%d; lec_lwp=%d",
23901.141Skamil		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
23911.156Smgorny	for (i = signal_threads; i < THREAD_CONCURRENT_SIGNALS_NUM; i++)
23921.156Smgorny		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 0,
23931.156Smgorny		    "extraneous signal_counts[%d].lec_count=%d; lec_lwp=%d",
23941.156Smgorny		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
23951.138Smgorny
23961.160Smgorny	for (i = 0; i < breakpoint_threads; i++)
23971.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 1,
23981.160Smgorny		    "bp_counts[%d].lec_count=%d; lec_lwp=%d",
23991.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
24001.160Smgorny	for (i = breakpoint_threads; i < THREAD_CONCURRENT_BREAKPOINT_NUM; i++)
24011.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 0,
24021.160Smgorny		    "extraneous bp_counts[%d].lec_count=%d; lec_lwp=%d",
24031.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
24041.160Smgorny
24051.161Smgorny	for (i = 0; i < watchpoint_threads; i++)
24061.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 1,
24071.161Smgorny		    "wp_counts[%d].lec_count=%d; lec_lwp=%d",
24081.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
24091.161Smgorny	for (i = watchpoint_threads; i < THREAD_CONCURRENT_WATCHPOINT_NUM; i++)
24101.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 0,
24111.161Smgorny		    "extraneous wp_counts[%d].lec_count=%d; lec_lwp=%d",
24121.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
24131.161Smgorny
24141.138Smgorny	validate_status_exited(status, exitval);
24151.138Smgorny}
24161.138Smgorny
24171.161Smgorny#define THREAD_CONCURRENT_TEST(test, sig_hdl, bps, sigs, wps, descr)	\
24181.156SmgornyATF_TC(test);								\
24191.156SmgornyATF_TC_HEAD(test, tc)							\
24201.156Smgorny{									\
24211.156Smgorny	atf_tc_set_md_var(tc, "descr", descr);				\
24221.156Smgorny}									\
24231.156Smgorny									\
24241.156SmgornyATF_TC_BODY(test, tc)							\
24251.156Smgorny{									\
24261.161Smgorny	thread_concurrent_test(sig_hdl, bps, sigs, wps);		\
24271.156Smgorny}
24281.156Smgorny
24291.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals, TCSH_DISCARD,
24301.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
24311.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
24321.157Smgorny    "correctly");
24331.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_sig_ign, TCSH_SIG_IGN,
24341.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
24351.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
24361.157Smgorny    "correctly and passed back to SIG_IGN handler");
24371.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_handler, TCSH_HANDLER,
24381.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
24391.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
24401.157Smgorny    "correctly and passed back to a handler function");
24411.156Smgorny
24421.163Skamil#if defined(__i386__) || defined(__x86_64__)
24431.160SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_breakpoints, TCSH_DISCARD,
24441.161Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, 0,
24451.161Smgorny    "Verify that concurrent breakpoints are reported correctly");
24461.161SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_watchpoints, TCSH_DISCARD,
24471.161Smgorny    0, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
24481.160Smgorny    "Verify that concurrent breakpoints are reported correctly");
24491.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp, TCSH_DISCARD,
24501.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
24511.162Smgorny    "Verify that concurrent breakpoints and watchpoints are reported "
24521.162Smgorny    "correctly");
24531.162Smgorny
24541.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig, TCSH_DISCARD,
24551.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
24561.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly");
24571.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_sig_ign, TCSH_SIG_IGN,
24581.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
24591.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
24601.162Smgorny    "and passed back to SIG_IGN handler");
24611.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_handler, TCSH_HANDLER,
24621.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
24631.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
24641.162Smgorny    "and passed back to a handler function");
24651.162Smgorny
24661.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig, TCSH_DISCARD,
24671.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
24681.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly");
24691.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_sig_ign, TCSH_SIG_IGN,
24701.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
24711.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
24721.162Smgorny    "and passed back to SIG_IGN handler");
24731.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_handler, TCSH_HANDLER,
24741.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
24751.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
24761.162Smgorny    "and passed back to a handler function");
24771.162Smgorny
24781.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig, TCSH_DISCARD,
24791.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
24801.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
24811.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
24821.162Smgorny    "correctly");
24831.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_sig_ign, TCSH_SIG_IGN,
24841.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
24851.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
24861.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
24871.162Smgorny    "correctly and passed back to SIG_IGN handler");
24881.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_handler, TCSH_HANDLER,
24891.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
24901.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
24911.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
24921.162Smgorny    "correctly and passed back to a handler function");
24931.163Skamil#endif
24941.160Smgorny
24951.138Smgorny#endif /*defined(TWAIT_HAVE_STATUS)*/
24961.138Smgorny
24971.138Smgorny/// ----------------------------------------------------------------------------
24981.138Smgorny
24991.174Skamil#include "t_ptrace_register_wait.h"
25001.175Skamil#include "t_ptrace_syscall_wait.h"
25011.176Skamil#include "t_ptrace_step_wait.h"
25021.177Skamil#include "t_ptrace_kill_wait.h"
25031.178Skamil#include "t_ptrace_bytetransfer_wait.h"
25041.179Skamil#include "t_ptrace_clone_wait.h"
25051.180Skamil#include "t_ptrace_fork_wait.h"
25061.181Skamil#include "t_ptrace_signal_wait.h"
25071.183Skamil#include "t_ptrace_eventmask_wait.h"
25081.185Skamil#include "t_ptrace_lwp_wait.h"
25091.174Skamil
25101.174Skamil/// ----------------------------------------------------------------------------
25111.174Skamil
25121.1Skamil#include "t_ptrace_amd64_wait.h"
25131.1Skamil#include "t_ptrace_i386_wait.h"
25141.1Skamil#include "t_ptrace_x86_wait.h"
25151.1Skamil
25161.165Skamil/// ----------------------------------------------------------------------------
25171.165Skamil
25181.165Skamil#else
25191.165SkamilATF_TC(dummy);
25201.165SkamilATF_TC_HEAD(dummy, tc)
25211.165Skamil{
25221.165Skamil	atf_tc_set_md_var(tc, "descr", "A dummy test");
25231.165Skamil}
25241.165Skamil
25251.165SkamilATF_TC_BODY(dummy, tc)
25261.165Skamil{
25271.165Skamil
25281.165Skamil	// Dummy, skipped
25291.165Skamil	// The ATF framework requires at least a single defined test.
25301.165Skamil}
25311.165Skamil#endif
25321.165Skamil
25331.1SkamilATF_TP_ADD_TCS(tp)
25341.1Skamil{
25351.1Skamil	setvbuf(stdout, NULL, _IONBF, 0);
25361.1Skamil	setvbuf(stderr, NULL, _IONBF, 0);
25371.33Skamil
25381.165Skamil#ifdef ENABLE_TESTS
25391.37Skamil	ATF_TP_ADD_TC(tp, traceme_pid1_parent);
25401.37Skamil
25411.43Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_exec);
25421.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalmasked_exec);
25431.96Skamil	ATF_TP_ADD_TC(tp, traceme_vfork_signalignored_exec);
25441.43Skamil
25451.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sees_terminaton_before_the_parent);
25461.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sysctl_lookup_without_duplicates);
25471.61Skre	ATF_TP_ADD_TC_HAVE_PID(tp,
25481.61Skre		unrelated_tracer_sees_terminaton_before_the_parent);
25491.67Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_attach_to_unrelated_stopped_process);
25501.51Skamil
25511.51Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_child);
25521.66Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_stopped_child);
25531.51Skamil
25541.51Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_parent);
25551.65Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_stopped_parent);
25561.51Skamil
25571.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
25581.51Skamil		tracee_sees_its_original_parent_getppid);
25591.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
25601.51Skamil		tracee_sees_its_original_parent_sysctl_kinfo_proc2);
25611.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
25621.51Skamil		tracee_sees_its_original_parent_procfs_status);
25631.1Skamil
25641.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_unmodified);
25651.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_faked);
25661.79Skamil
25671.82Skamil	ATF_TP_ADD_TC(tp, traceme_exec);
25681.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalmasked_exec);
25691.97Skamil	ATF_TP_ADD_TC(tp, traceme_signalignored_exec);
25701.1Skamil
25711.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_nolwpevents);
25721.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit);
25731.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate);
25741.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit);
25751.1Skamil
25761.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit_masked_sigtrap);
25771.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_masked_sigtrap);
25781.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit_masked_sigtrap);
25791.153Skamil
25801.151Skamil	ATF_TP_ADD_TC(tp, threads_and_exec);
25811.151Skamil
25821.154Skamil	ATF_TP_ADD_TC(tp, suspend_no_deadlock);
25831.1Skamil
25841.155Skamil	ATF_TP_ADD_TC(tp, resume);
25851.1Skamil
25861.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_continue);
25871.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall);
25881.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach);
25891.122Skamil
25901.130Smgorny	ATF_TP_ADD_TC(tp, core_dump_procinfo);
25911.130Smgorny
25921.138Smgorny#if defined(TWAIT_HAVE_STATUS)
25931.138Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals);
25941.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_sig_ign);
25951.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_handler);
25961.160Smgorny#if defined(__i386__) || defined(__x86_64__)
25971.160Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_breakpoints);
25981.161Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_watchpoints);
25991.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp);
26001.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig);
26011.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_sig_ign);
26021.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_handler);
26031.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig);
26041.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_sig_ign);
26051.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_handler);
26061.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig);
26071.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_sig_ign);
26081.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_handler);
26091.160Smgorny#endif
26101.138Smgorny#endif
26111.138Smgorny
26121.174Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_REGISTER();
26131.175Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_SYSCALL();
26141.176Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_STEP();
26151.177Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_KILL();
26161.178Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_BYTETRANSFER();
26171.179Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_CLONE();
26181.180Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_FORK();
26191.181Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_SIGNAL();
26201.183Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_EVENTMASK();
26211.185Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_LWP();
26221.174Skamil
26231.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
26241.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_I386();
26251.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_X86();
26261.1Skamil
26271.165Skamil#else
26281.165Skamil	ATF_TP_ADD_TC(tp, dummy);
26291.165Skamil#endif
26301.165Skamil
26311.1Skamil	return atf_no_error();
26321.1Skamil}
2633