t_ptrace_wait.c revision 1.186
11.186Skamil/*	$NetBSD: t_ptrace_wait.c,v 1.186 2020/05/05 00:23:12 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.186Skamil__RCSID("$NetBSD: t_ptrace_wait.c,v 1.186 2020/05/05 00:23:12 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.59Skamil#if defined(TWAIT_HAVE_PID)
1661.59Skamilstatic void
1671.67Skamiltracer_sees_terminaton_before_the_parent_raw(bool notimeout, bool unrelated,
1681.67Skamil                                             bool stopped)
1691.1Skamil{
1701.51Skamil	/*
1711.51Skamil	 * notimeout - disable timeout in await zombie function
1721.51Skamil	 * unrelated - attach from unrelated tracer reparented to initproc
1731.67Skamil	 * stopped - attach to a stopped process
1741.51Skamil	 */
1751.1Skamil
1761.1Skamil	struct msg_fds parent_tracee, parent_tracer;
1771.1Skamil	const int exitval_tracee = 5;
1781.1Skamil	const int exitval_tracer = 10;
1791.1Skamil	pid_t tracee, tracer, wpid;
1801.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
1811.1Skamil#if defined(TWAIT_HAVE_STATUS)
1821.1Skamil	int status;
1831.1Skamil#endif
1841.1Skamil
1851.67Skamil	/*
1861.67Skamil	 * Only a subset of options are supported.
1871.67Skamil	 */
1881.67Skamil	ATF_REQUIRE((!notimeout && !unrelated && !stopped) ||
1891.67Skamil	            (!notimeout && unrelated && !stopped) ||
1901.67Skamil	            (notimeout && !unrelated && !stopped) ||
1911.67Skamil	            (!notimeout && unrelated && stopped));
1921.67Skamil
1931.13Schristos	DPRINTF("Spawn tracee\n");
1941.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
1951.1Skamil	tracee = atf_utils_fork();
1961.1Skamil	if (tracee == 0) {
1971.67Skamil		if (stopped) {
1981.67Skamil			DPRINTF("Stop self PID %d\n", getpid());
1991.67Skamil			raise(SIGSTOP);
2001.67Skamil		}
2011.67Skamil
2021.1Skamil		// Wait for parent to let us exit
2031.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
2041.1Skamil		_exit(exitval_tracee);
2051.1Skamil	}
2061.1Skamil
2071.13Schristos	DPRINTF("Spawn debugger\n");
2081.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
2091.1Skamil	tracer = atf_utils_fork();
2101.1Skamil	if (tracer == 0) {
2111.51Skamil		if(unrelated) {
2121.51Skamil			/* Fork again and drop parent to reattach to PID 1 */
2131.51Skamil			tracer = atf_utils_fork();
2141.51Skamil			if (tracer != 0)
2151.51Skamil				_exit(exitval_tracer);
2161.51Skamil		}
2171.51Skamil
2181.67Skamil		if (stopped) {
2191.67Skamil			DPRINTF("Await for a stopped parent PID %d\n", tracee);
2201.67Skamil			await_stopped(tracee);
2211.67Skamil		}
2221.67Skamil
2231.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
2241.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
2251.1Skamil
2261.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
2271.1Skamil		FORKEE_REQUIRE_SUCCESS(
2281.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
2291.1Skamil
2301.1Skamil		forkee_status_stopped(status, SIGSTOP);
2311.1Skamil
2321.1Skamil		/* Resume tracee with PT_CONTINUE */
2331.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
2341.1Skamil
2351.1Skamil		/* Inform parent that tracer has attached to tracee */
2361.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
2371.1Skamil
2381.1Skamil		/* Wait for parent to tell use that tracee should have exited */
2391.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
2401.1Skamil
2411.1Skamil		/* Wait for tracee and assert that it exited */
2421.1Skamil		FORKEE_REQUIRE_SUCCESS(
2431.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
2441.1Skamil
2451.1Skamil		forkee_status_exited(status, exitval_tracee);
2461.13Schristos		DPRINTF("Tracee %d exited with %d\n", tracee, exitval_tracee);
2471.1Skamil
2481.13Schristos		DPRINTF("Before exiting of the tracer process\n");
2491.51Skamil		_exit(unrelated ? 0 /* collect by initproc */ : exitval_tracer);
2501.51Skamil	}
2511.51Skamil
2521.51Skamil	if (unrelated) {
2531.51Skamil		DPRINTF("Wait for the tracer process (direct child) to exit "
2541.51Skamil		    "calling %s()\n", TWAIT_FNAME);
2551.51Skamil		TWAIT_REQUIRE_SUCCESS(
2561.51Skamil		    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
2571.51Skamil
2581.51Skamil		validate_status_exited(status, exitval_tracer);
2591.51Skamil
2601.51Skamil		DPRINTF("Wait for the non-exited tracee process with %s()\n",
2611.51Skamil		    TWAIT_FNAME);
2621.51Skamil		TWAIT_REQUIRE_SUCCESS(
2631.51Skamil		    wpid = TWAIT_GENERIC(tracee, NULL, WNOHANG), 0);
2641.1Skamil	}
2651.1Skamil
2661.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
2671.1Skamil	PARENT_FROM_CHILD("tracer ready", parent_tracer, msg);
2681.1Skamil
2691.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
2701.1Skamil	PARENT_TO_CHILD("exit tracee", parent_tracee,  msg);
2711.1Skamil
2721.13Schristos	DPRINTF("Detect that tracee is zombie\n");
2731.51Skamil	if (notimeout)
2741.26Skamil		await_zombie_raw(tracee, 0);
2751.26Skamil	else
2761.26Skamil		await_zombie(tracee);
2771.1Skamil
2781.13Schristos	DPRINTF("Assert that there is no status about tracee %d - "
2791.1Skamil	    "Tracer must detect zombie first - calling %s()\n", tracee,
2801.1Skamil	    TWAIT_FNAME);
2811.1Skamil	TWAIT_REQUIRE_SUCCESS(
2821.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
2831.1Skamil
2841.51Skamil	if (unrelated) {
2851.51Skamil		DPRINTF("Resume the tracer and let it detect exited tracee\n");
2861.51Skamil		PARENT_TO_CHILD("Message 2", parent_tracer, msg);
2871.51Skamil	} else {
2881.51Skamil		DPRINTF("Tell the tracer child should have exited\n");
2891.51Skamil		PARENT_TO_CHILD("wait for tracee exit", parent_tracer,  msg);
2901.51Skamil		DPRINTF("Wait for tracer to finish its job and exit - calling "
2911.59Skamil			"%s()\n", TWAIT_FNAME);
2921.51Skamil
2931.51Skamil		DPRINTF("Wait from tracer child to complete waiting for "
2941.59Skamil			"tracee\n");
2951.51Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
2961.51Skamil		    tracer);
2971.1Skamil
2981.51Skamil		validate_status_exited(status, exitval_tracer);
2991.51Skamil	}
3001.1Skamil
3011.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
3021.1Skamil	    TWAIT_FNAME);
3031.51Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
3041.1Skamil
3051.1Skamil	validate_status_exited(status, exitval_tracee);
3061.1Skamil
3071.1Skamil	msg_close(&parent_tracer);
3081.1Skamil	msg_close(&parent_tracee);
3091.1Skamil}
3101.26Skamil
3111.51SkamilATF_TC(tracer_sees_terminaton_before_the_parent);
3121.51SkamilATF_TC_HEAD(tracer_sees_terminaton_before_the_parent, tc)
3131.51Skamil{
3141.51Skamil	atf_tc_set_md_var(tc, "descr",
3151.51Skamil	    "Assert that tracer sees process termination before the parent");
3161.51Skamil}
3171.51Skamil
3181.51SkamilATF_TC_BODY(tracer_sees_terminaton_before_the_parent, tc)
3191.26Skamil{
3201.26Skamil
3211.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, false, false);
3221.26Skamil}
3231.26Skamil
3241.51SkamilATF_TC(tracer_sysctl_lookup_without_duplicates);
3251.51SkamilATF_TC_HEAD(tracer_sysctl_lookup_without_duplicates, tc)
3261.1Skamil{
3271.164Skamil	atf_tc_set_md_var(tc, "timeout", "15");
3281.1Skamil	atf_tc_set_md_var(tc, "descr",
3291.51Skamil	    "Assert that await_zombie() in attach1 always finds a single "
3301.51Skamil	    "process and no other error is reported");
3311.1Skamil}
3321.1Skamil
3331.51SkamilATF_TC_BODY(tracer_sysctl_lookup_without_duplicates, tc)
3341.1Skamil{
3351.51Skamil	time_t start, end;
3361.51Skamil	double diff;
3371.51Skamil	unsigned long N = 0;
3381.1Skamil
3391.51Skamil	/*
3401.51Skamil	 * Reuse this test with tracer_sees_terminaton_before_the_parent_raw().
3411.51Skamil	 * This test body isn't specific to this race, however it's just good
3421.51Skamil	 * enough for this purposes, no need to invent a dedicated code flow.
3431.51Skamil	 */
3441.1Skamil
3451.51Skamil	start = time(NULL);
3461.51Skamil	while (true) {
3471.51Skamil		DPRINTF("Step: %lu\n", N);
3481.67Skamil		tracer_sees_terminaton_before_the_parent_raw(true, false,
3491.67Skamil		                                             false);
3501.51Skamil		end = time(NULL);
3511.51Skamil		diff = difftime(end, start);
3521.51Skamil		if (diff >= 5.0)
3531.51Skamil			break;
3541.51Skamil		++N;
3551.1Skamil	}
3561.51Skamil	DPRINTF("Iterations: %lu\n", N);
3571.51Skamil}
3581.1Skamil
3591.51SkamilATF_TC(unrelated_tracer_sees_terminaton_before_the_parent);
3601.51SkamilATF_TC_HEAD(unrelated_tracer_sees_terminaton_before_the_parent, tc)
3611.51Skamil{
3621.51Skamil	atf_tc_set_md_var(tc, "descr",
3631.51Skamil	    "Assert that tracer sees process termination before the parent");
3641.51Skamil}
3651.1Skamil
3661.51SkamilATF_TC_BODY(unrelated_tracer_sees_terminaton_before_the_parent, tc)
3671.51Skamil{
3681.1Skamil
3691.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, false);
3701.67Skamil}
3711.67Skamil
3721.67SkamilATF_TC(tracer_attach_to_unrelated_stopped_process);
3731.67SkamilATF_TC_HEAD(tracer_attach_to_unrelated_stopped_process, tc)
3741.67Skamil{
3751.67Skamil	atf_tc_set_md_var(tc, "descr",
3761.67Skamil	    "Assert that tracer can attach to an unrelated stopped process");
3771.67Skamil}
3781.67Skamil
3791.67SkamilATF_TC_BODY(tracer_attach_to_unrelated_stopped_process, tc)
3801.67Skamil{
3811.67Skamil
3821.67Skamil	tracer_sees_terminaton_before_the_parent_raw(false, true, true);
3831.1Skamil}
3841.1Skamil#endif
3851.1Skamil
3861.51Skamil/// ----------------------------------------------------------------------------
3871.51Skamil
3881.66Skamilstatic void
3891.66Skamilparent_attach_to_its_child(bool stopped)
3901.1Skamil{
3911.1Skamil	struct msg_fds parent_tracee;
3921.1Skamil	const int exitval_tracee = 5;
3931.1Skamil	pid_t tracee, wpid;
3941.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
3951.1Skamil#if defined(TWAIT_HAVE_STATUS)
3961.1Skamil	int status;
3971.1Skamil#endif
3981.1Skamil
3991.13Schristos	DPRINTF("Spawn tracee\n");
4001.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
4011.1Skamil	tracee = atf_utils_fork();
4021.1Skamil	if (tracee == 0) {
4031.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
4041.13Schristos		DPRINTF("Parent should now attach to tracee\n");
4051.1Skamil
4061.66Skamil		if (stopped) {
4071.66Skamil			DPRINTF("Stop self PID %d\n", getpid());
4081.66Skamil			SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
4091.66Skamil		}
4101.66Skamil
4111.1Skamil		CHILD_FROM_PARENT("Message 2", parent_tracee, msg);
4121.1Skamil		/* Wait for message from the parent */
4131.1Skamil		_exit(exitval_tracee);
4141.1Skamil	}
4151.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
4161.57Skamil
4171.66Skamil	if (stopped) {
4181.66Skamil		DPRINTF("Await for a stopped tracee PID %d\n", tracee);
4191.66Skamil		await_stopped(tracee);
4201.66Skamil	}
4211.66Skamil
4221.13Schristos	DPRINTF("Before calling PT_ATTACH for tracee %d\n", tracee);
4231.13Schristos	SYSCALL_REQUIRE(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
4241.1Skamil
4251.13Schristos	DPRINTF("Wait for the stopped tracee process with %s()\n",
4261.1Skamil	    TWAIT_FNAME);
4271.1Skamil	TWAIT_REQUIRE_SUCCESS(
4281.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
4291.1Skamil
4301.1Skamil	validate_status_stopped(status, SIGSTOP);
4311.1Skamil
4321.13Schristos	DPRINTF("Resume tracee with PT_CONTINUE\n");
4331.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
4341.1Skamil
4351.13Schristos	DPRINTF("Let the tracee exit now\n");
4361.1Skamil	PARENT_TO_CHILD("Message 2", parent_tracee, msg);
4371.1Skamil
4381.13Schristos	DPRINTF("Wait for tracee to exit with %s()\n", TWAIT_FNAME);
4391.1Skamil	TWAIT_REQUIRE_SUCCESS(
4401.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
4411.1Skamil
4421.1Skamil	validate_status_exited(status, exitval_tracee);
4431.1Skamil
4441.13Schristos	DPRINTF("Before calling %s() for tracee\n", TWAIT_FNAME);
4451.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
4461.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, 0));
4471.1Skamil
4481.1Skamil	msg_close(&parent_tracee);
4491.1Skamil}
4501.1Skamil
4511.66SkamilATF_TC(parent_attach_to_its_child);
4521.66SkamilATF_TC_HEAD(parent_attach_to_its_child, tc)
4531.66Skamil{
4541.66Skamil	atf_tc_set_md_var(tc, "descr",
4551.66Skamil	    "Assert that tracer parent can PT_ATTACH to its child");
4561.66Skamil}
4571.66Skamil
4581.66SkamilATF_TC_BODY(parent_attach_to_its_child, tc)
4591.66Skamil{
4601.66Skamil
4611.66Skamil	parent_attach_to_its_child(false);
4621.66Skamil}
4631.66Skamil
4641.66SkamilATF_TC(parent_attach_to_its_stopped_child);
4651.66SkamilATF_TC_HEAD(parent_attach_to_its_stopped_child, tc)
4661.66Skamil{
4671.66Skamil	atf_tc_set_md_var(tc, "descr",
4681.66Skamil	    "Assert that tracer parent can PT_ATTACH to its stopped child");
4691.66Skamil}
4701.66Skamil
4711.66SkamilATF_TC_BODY(parent_attach_to_its_stopped_child, tc)
4721.66Skamil{
4731.66Skamil
4741.66Skamil	parent_attach_to_its_child(true);
4751.66Skamil}
4761.66Skamil
4771.51Skamil/// ----------------------------------------------------------------------------
4781.51Skamil
4791.65Skamilstatic void
4801.65Skamilchild_attach_to_its_parent(bool stopped)
4811.1Skamil{
4821.1Skamil	struct msg_fds parent_tracee;
4831.1Skamil	const int exitval_tracer = 5;
4841.1Skamil	pid_t tracer, wpid;
4851.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
4861.1Skamil#if defined(TWAIT_HAVE_STATUS)
4871.1Skamil	int status;
4881.1Skamil#endif
4891.1Skamil
4901.13Schristos	DPRINTF("Spawn tracer\n");
4911.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
4921.1Skamil	tracer = atf_utils_fork();
4931.1Skamil	if (tracer == 0) {
4941.1Skamil		/* Wait for message from the parent */
4951.1Skamil		CHILD_FROM_PARENT("Message 1", parent_tracee, msg);
4961.1Skamil
4971.65Skamil		if (stopped) {
4981.65Skamil			DPRINTF("Await for a stopped parent PID %d\n",
4991.65Skamil			        getppid());
5001.65Skamil			await_stopped(getppid());
5011.65Skamil		}
5021.65Skamil
5031.13Schristos		DPRINTF("Attach to parent PID %d with PT_ATTACH from child\n",
5041.1Skamil		    getppid());
5051.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, getppid(), NULL, 0) != -1);
5061.1Skamil
5071.13Schristos		DPRINTF("Wait for the stopped parent process with %s()\n",
5081.1Skamil		    TWAIT_FNAME);
5091.1Skamil		FORKEE_REQUIRE_SUCCESS(
5101.1Skamil		    wpid = TWAIT_GENERIC(getppid(), &status, 0), getppid());
5111.1Skamil
5121.1Skamil		forkee_status_stopped(status, SIGSTOP);
5131.1Skamil
5141.13Schristos		DPRINTF("Resume parent with PT_DETACH\n");
5151.1Skamil		FORKEE_ASSERT(ptrace(PT_DETACH, getppid(), (void *)1, 0)
5161.1Skamil		    != -1);
5171.1Skamil
5181.1Skamil		/* Tell parent we are ready */
5191.1Skamil		CHILD_TO_PARENT("Message 1", parent_tracee, msg);
5201.1Skamil
5211.1Skamil		_exit(exitval_tracer);
5221.1Skamil	}
5231.1Skamil
5241.13Schristos	DPRINTF("Wait for the tracer to become ready\n");
5251.1Skamil	PARENT_TO_CHILD("Message 1", parent_tracee, msg);
5261.65Skamil
5271.65Skamil	if (stopped) {
5281.65Skamil		DPRINTF("Stop self PID %d\n", getpid());
5291.65Skamil		SYSCALL_REQUIRE(raise(SIGSTOP) != -1);
5301.65Skamil	}
5311.65Skamil
5321.13Schristos	DPRINTF("Allow the tracer to exit now\n");
5331.1Skamil	PARENT_FROM_CHILD("Message 1", parent_tracee, msg);
5341.1Skamil
5351.13Schristos	DPRINTF("Wait for tracer to exit with %s()\n", TWAIT_FNAME);
5361.1Skamil	TWAIT_REQUIRE_SUCCESS(
5371.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0), tracer);
5381.1Skamil
5391.1Skamil	validate_status_exited(status, exitval_tracer);
5401.1Skamil
5411.13Schristos	DPRINTF("Before calling %s() for tracer\n", TWAIT_FNAME);
5421.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD,
5431.1Skamil	    wpid = TWAIT_GENERIC(tracer, &status, 0));
5441.1Skamil
5451.1Skamil	msg_close(&parent_tracee);
5461.1Skamil}
5471.1Skamil
5481.65SkamilATF_TC(child_attach_to_its_parent);
5491.65SkamilATF_TC_HEAD(child_attach_to_its_parent, tc)
5501.65Skamil{
5511.65Skamil	atf_tc_set_md_var(tc, "descr",
5521.65Skamil	    "Assert that tracer child can PT_ATTACH to its parent");
5531.65Skamil}
5541.65Skamil
5551.65SkamilATF_TC_BODY(child_attach_to_its_parent, tc)
5561.65Skamil{
5571.65Skamil
5581.65Skamil	child_attach_to_its_parent(false);
5591.65Skamil}
5601.65Skamil
5611.65SkamilATF_TC(child_attach_to_its_stopped_parent);
5621.65SkamilATF_TC_HEAD(child_attach_to_its_stopped_parent, tc)
5631.65Skamil{
5641.65Skamil	atf_tc_set_md_var(tc, "descr",
5651.65Skamil	    "Assert that tracer child can PT_ATTACH to its stopped parent");
5661.65Skamil}
5671.65Skamil
5681.65SkamilATF_TC_BODY(child_attach_to_its_stopped_parent, tc)
5691.65Skamil{
5701.65Skamil	/*
5711.65Skamil	 * The ATF framework (atf-run) does not tolerate raise(SIGSTOP), as
5721.65Skamil	 * this causes a pipe (established from atf-run) to be broken.
5731.65Skamil	 * atf-run uses this mechanism to monitor whether a test is alive.
5741.65Skamil	 *
5751.65Skamil	 * As a workaround spawn this test as a subprocess.
5761.65Skamil	 */
5771.65Skamil
5781.65Skamil	const int exitval = 15;
5791.65Skamil	pid_t child, wpid;
5801.65Skamil#if defined(TWAIT_HAVE_STATUS)
5811.65Skamil	int status;
5821.65Skamil#endif
5831.65Skamil
5841.65Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
5851.65Skamil	if (child == 0) {
5861.65Skamil		child_attach_to_its_parent(true);
5871.65Skamil		_exit(exitval);
5881.65Skamil	} else {
5891.65Skamil		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
5901.65Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
5911.65Skamil
5921.65Skamil		validate_status_exited(status, exitval);
5931.65Skamil
5941.65Skamil		DPRINTF("Before calling %s() for the exited child\n", TWAIT_FNAME);
5951.65Skamil		TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
5961.65Skamil	}
5971.65Skamil}
5981.65Skamil
5991.51Skamil/// ----------------------------------------------------------------------------
6001.51Skamil
6011.1Skamil#if defined(TWAIT_HAVE_PID)
6021.1Skamil
6031.51Skamilenum tracee_sees_its_original_parent_type {
6041.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
6051.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
6061.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS
6071.51Skamil};
6081.51Skamil
6091.51Skamilstatic void
6101.51Skamiltracee_sees_its_original_parent(enum tracee_sees_its_original_parent_type type)
6111.1Skamil{
6121.1Skamil	struct msg_fds parent_tracer, parent_tracee;
6131.1Skamil	const int exitval_tracee = 5;
6141.1Skamil	const int exitval_tracer = 10;
6151.1Skamil	pid_t parent, tracee, tracer, wpid;
6161.1Skamil	uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
6171.1Skamil#if defined(TWAIT_HAVE_STATUS)
6181.1Skamil	int status;
6191.1Skamil#endif
6201.51Skamil	/* sysctl(3) - kinfo_proc2 */
6211.51Skamil	int name[CTL_MAXNAME];
6221.51Skamil	struct kinfo_proc2 kp;
6231.51Skamil	size_t len = sizeof(kp);
6241.51Skamil	unsigned int namelen;
6251.51Skamil
6261.51Skamil	/* procfs - status  */
6271.51Skamil	FILE *fp;
6281.51Skamil	struct stat st;
6291.51Skamil	const char *fname = "/proc/curproc/status";
6301.51Skamil	char s_executable[MAXPATHLEN];
6311.51Skamil	int s_pid, s_ppid;
6321.51Skamil	int rv;
6331.51Skamil
6341.51Skamil	if (type == TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS) {
6351.61Skre		SYSCALL_REQUIRE(
6361.61Skre		    (rv = stat(fname, &st)) == 0 || (errno == ENOENT));
6371.61Skre		if (rv != 0)
6381.51Skamil			atf_tc_skip("/proc/curproc/status not found");
6391.51Skamil	}
6401.1Skamil
6411.13Schristos	DPRINTF("Spawn tracee\n");
6421.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracer) == 0);
6431.13Schristos	SYSCALL_REQUIRE(msg_open(&parent_tracee) == 0);
6441.1Skamil	tracee = atf_utils_fork();
6451.1Skamil	if (tracee == 0) {
6461.1Skamil		parent = getppid();
6471.1Skamil
6481.1Skamil		/* Emit message to the parent */
6491.1Skamil		CHILD_TO_PARENT("tracee ready", parent_tracee, msg);
6501.1Skamil		CHILD_FROM_PARENT("exit tracee", parent_tracee, msg);
6511.1Skamil
6521.51Skamil		switch (type) {
6531.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID:
6541.51Skamil			FORKEE_ASSERT_EQ(parent, getppid());
6551.51Skamil			break;
6561.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2:
6571.51Skamil			namelen = 0;
6581.51Skamil			name[namelen++] = CTL_KERN;
6591.51Skamil			name[namelen++] = KERN_PROC2;
6601.51Skamil			name[namelen++] = KERN_PROC_PID;
6611.51Skamil			name[namelen++] = getpid();
6621.51Skamil			name[namelen++] = len;
6631.51Skamil			name[namelen++] = 1;
6641.51Skamil
6651.61Skre			FORKEE_ASSERT_EQ(
6661.61Skre			    sysctl(name, namelen, &kp, &len, NULL, 0), 0);
6671.51Skamil			FORKEE_ASSERT_EQ(parent, kp.p_ppid);
6681.51Skamil			break;
6691.51Skamil		case TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS:
6701.51Skamil			/*
6711.51Skamil			 * Format:
6721.51Skamil			 *  EXECUTABLE PID PPID ...
6731.51Skamil			 */
6741.51Skamil			FORKEE_ASSERT((fp = fopen(fname, "r")) != NULL);
6751.51Skamil			fscanf(fp, "%s %d %d", s_executable, &s_pid, &s_ppid);
6761.51Skamil			FORKEE_ASSERT_EQ(fclose(fp), 0);
6771.51Skamil			FORKEE_ASSERT_EQ(parent, s_ppid);
6781.51Skamil			break;
6791.51Skamil		}
6801.1Skamil
6811.1Skamil		_exit(exitval_tracee);
6821.1Skamil	}
6831.13Schristos	DPRINTF("Wait for child to record its parent identifier (pid)\n");
6841.1Skamil	PARENT_FROM_CHILD("tracee ready", parent_tracee, msg);
6851.1Skamil
6861.13Schristos	DPRINTF("Spawn debugger\n");
6871.1Skamil	tracer = atf_utils_fork();
6881.1Skamil	if (tracer == 0) {
6891.1Skamil		/* No IPC to communicate with the child */
6901.13Schristos		DPRINTF("Before calling PT_ATTACH from tracee %d\n", getpid());
6911.1Skamil		FORKEE_ASSERT(ptrace(PT_ATTACH, tracee, NULL, 0) != -1);
6921.1Skamil
6931.1Skamil		/* Wait for tracee and assert that it was stopped w/ SIGSTOP */
6941.1Skamil		FORKEE_REQUIRE_SUCCESS(
6951.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
6961.1Skamil
6971.1Skamil		forkee_status_stopped(status, SIGSTOP);
6981.1Skamil
6991.1Skamil		/* Resume tracee with PT_CONTINUE */
7001.1Skamil		FORKEE_ASSERT(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
7011.1Skamil
7021.1Skamil		/* Inform parent that tracer has attached to tracee */
7031.1Skamil		CHILD_TO_PARENT("tracer ready", parent_tracer, msg);
7041.1Skamil
7051.1Skamil		/* Wait for parent to tell use that tracee should have exited */
7061.1Skamil		CHILD_FROM_PARENT("wait for tracee exit", parent_tracer, msg);
7071.1Skamil
7081.1Skamil		/* Wait for tracee and assert that it exited */
7091.1Skamil		FORKEE_REQUIRE_SUCCESS(
7101.1Skamil		    wpid = TWAIT_GENERIC(tracee, &status, 0), tracee);
7111.1Skamil
7121.1Skamil		forkee_status_exited(status, exitval_tracee);
7131.1Skamil
7141.13Schristos		DPRINTF("Before exiting of the tracer process\n");
7151.1Skamil		_exit(exitval_tracer);
7161.1Skamil	}
7171.1Skamil
7181.13Schristos	DPRINTF("Wait for the tracer to attach to the tracee\n");
7191.1Skamil	PARENT_FROM_CHILD("tracer ready",  parent_tracer, msg);
7201.1Skamil
7211.13Schristos	DPRINTF("Resume the tracee and let it exit\n");
7221.1Skamil	PARENT_TO_CHILD("exit tracee",  parent_tracee, msg);
7231.1Skamil
7241.13Schristos	DPRINTF("Detect that tracee is zombie\n");
7251.1Skamil	await_zombie(tracee);
7261.1Skamil
7271.13Schristos	DPRINTF("Assert that there is no status about tracee - "
7281.1Skamil	    "Tracer must detect zombie first - calling %s()\n", TWAIT_FNAME);
7291.1Skamil	TWAIT_REQUIRE_SUCCESS(
7301.1Skamil	    wpid = TWAIT_GENERIC(tracee, &status, WNOHANG), 0);
7311.1Skamil
7321.13Schristos	DPRINTF("Tell the tracer child should have exited\n");
7331.1Skamil	PARENT_TO_CHILD("wait for tracee exit",  parent_tracer, msg);
7341.1Skamil
7351.13Schristos	DPRINTF("Wait from tracer child to complete waiting for tracee\n");
7361.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracer, &status, 0),
7371.1Skamil	    tracer);
7381.1Skamil
7391.1Skamil	validate_status_exited(status, exitval_tracer);
7401.1Skamil
7411.13Schristos	DPRINTF("Wait for tracee to finish its job and exit - calling %s()\n",
7421.1Skamil	    TWAIT_FNAME);
7431.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(tracee, &status, WNOHANG),
7441.1Skamil	    tracee);
7451.1Skamil
7461.1Skamil	validate_status_exited(status, exitval_tracee);
7471.1Skamil
7481.1Skamil	msg_close(&parent_tracer);
7491.1Skamil	msg_close(&parent_tracee);
7501.1Skamil}
7511.1Skamil
7521.61Skre#define TRACEE_SEES_ITS_ORIGINAL_PARENT(test, type, descr)		\
7531.61SkreATF_TC(test);								\
7541.61SkreATF_TC_HEAD(test, tc)							\
7551.61Skre{									\
7561.61Skre	atf_tc_set_md_var(tc, "descr",					\
7571.61Skre	    "Assert that tracee sees its original parent when being traced " \
7581.61Skre	    "(check " descr ")");					\
7591.61Skre}									\
7601.61Skre									\
7611.61SkreATF_TC_BODY(test, tc)							\
7621.61Skre{									\
7631.61Skre									\
7641.61Skre	tracee_sees_its_original_parent(type);				\
7651.1Skamil}
7661.1Skamil
7671.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
7681.51Skamil	tracee_sees_its_original_parent_getppid,
7691.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_GETPPID,
7701.51Skamil	"getppid(2)");
7711.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
7721.51Skamil	tracee_sees_its_original_parent_sysctl_kinfo_proc2,
7731.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_SYSCTL_KINFO_PROC2,
7741.51Skamil	"sysctl(3) and kinfo_proc2");
7751.51SkamilTRACEE_SEES_ITS_ORIGINAL_PARENT(
7761.51Skamil	tracee_sees_its_original_parent_procfs_status,
7771.51Skamil	TRACEE_SEES_ITS_ORIGINAL_PARENT_PROCFS_STATUS,
7781.51Skamil	"the status file in procfs");
7791.1Skamil#endif
7801.1Skamil
7811.51Skamil/// ----------------------------------------------------------------------------
7821.1Skamil
7831.83Skamilstatic void
7841.180Skamilptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c), int *signal_caught)
7851.1Skamil{
7861.180Skamil	const int exitval = 5;
7871.180Skamil	const int sigval = SIGINT;
7881.180Skamil	const int sigfaked = SIGTRAP;
7891.180Skamil	const int sicodefaked = TRAP_BRKPT;
7901.1Skamil	pid_t child, wpid;
7911.180Skamil	struct sigaction sa;
7921.1Skamil#if defined(TWAIT_HAVE_STATUS)
7931.1Skamil	int status;
7941.1Skamil#endif
7951.83Skamil	struct ptrace_siginfo info;
7961.180Skamil	memset(&info, 0, sizeof(info));
7971.83Skamil
7981.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
7991.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
8001.1Skamil	if (child == 0) {
8011.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
8021.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
8031.1Skamil
8041.180Skamil		sa.sa_sigaction = sah;
8051.180Skamil		sa.sa_flags = SA_SIGINFO;
8061.180Skamil		sigemptyset(&sa.sa_mask);
8071.180Skamil
8081.180Skamil		FORKEE_ASSERT(sigaction(faked ? sigfaked : sigval, &sa, NULL)
8091.180Skamil		    != -1);
8101.153Skamil
8111.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
8121.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
8131.1Skamil
8141.180Skamil		FORKEE_ASSERT_EQ(*signal_caught, 1);
8151.1Skamil
8161.180Skamil		DPRINTF("Before exiting of the child process\n");
8171.180Skamil		_exit(exitval);
8181.1Skamil	}
8191.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
8201.1Skamil
8211.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8221.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8231.1Skamil
8241.1Skamil	validate_status_stopped(status, sigval);
8251.1Skamil
8261.83Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
8271.83Skamil	SYSCALL_REQUIRE(
8281.83Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
8291.1Skamil
8301.83Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
8311.83Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
8321.83Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
8331.83Skamil	    info.psi_siginfo.si_errno);
8341.1Skamil
8351.180Skamil	if (faked) {
8361.180Skamil		DPRINTF("Before setting new faked signal to signo=%d "
8371.180Skamil		    "si_code=%d\n", sigfaked, sicodefaked);
8381.180Skamil		info.psi_siginfo.si_signo = sigfaked;
8391.180Skamil		info.psi_siginfo.si_code = sicodefaked;
8401.83Skamil	}
8411.1Skamil
8421.180Skamil	DPRINTF("Before calling ptrace(2) with PT_SET_SIGINFO for child\n");
8431.180Skamil	SYSCALL_REQUIRE(
8441.180Skamil	    ptrace(PT_SET_SIGINFO, child, &info, sizeof(info)) != -1);
8451.1Skamil
8461.180Skamil	if (faked) {
8471.83Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
8481.83Skamil		    "child\n");
8491.180Skamil		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
8501.180Skamil		    sizeof(info)) != -1);
8511.1Skamil
8521.180Skamil		DPRINTF("Before checking siginfo_t\n");
8531.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigfaked);
8541.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, sicodefaked);
8551.83Skamil	}
8561.1Skamil
8571.180Skamil	DPRINTF("Before resuming the child process where it left off and "
8581.180Skamil	    "without signal to be sent\n");
8591.180Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
8601.180Skamil	    faked ? sigfaked : sigval) != -1);
8611.1Skamil
8621.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8631.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
8641.1Skamil
8651.180Skamil	validate_status_exited(status, exitval);
8661.1Skamil
8671.180Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
8681.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
8691.1Skamil}
8701.1Skamil
8711.180Skamil#define PTRACE_SIGINFO(test, faked)					\
8721.83SkamilATF_TC(test);								\
8731.83SkamilATF_TC_HEAD(test, tc)							\
8741.83Skamil{									\
8751.180Skamil	atf_tc_set_md_var(tc, "descr",					\
8761.180Skamil	    "Verify basic PT_GET_SIGINFO and PT_SET_SIGINFO calls"	\
8771.180Skamil	    "with%s setting signal to new value", faked ? "" : "out");	\
8781.180Skamil}									\
8791.180Skamil									\
8801.180Skamilstatic int test##_caught = 0;						\
8811.180Skamil									\
8821.180Skamilstatic void								\
8831.180Skamiltest##_sighandler(int sig, siginfo_t *info, void *ctx)			\
8841.180Skamil{									\
8851.180Skamil	if (faked) {							\
8861.180Skamil		FORKEE_ASSERT_EQ(sig, SIGTRAP);				\
8871.180Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGTRAP);		\
8881.180Skamil		FORKEE_ASSERT_EQ(info->si_code, TRAP_BRKPT);		\
8891.180Skamil	} else {							\
8901.180Skamil		FORKEE_ASSERT_EQ(sig, SIGINT);				\
8911.180Skamil		FORKEE_ASSERT_EQ(info->si_signo, SIGINT);		\
8921.180Skamil		FORKEE_ASSERT_EQ(info->si_code, SI_LWP);		\
8931.180Skamil	}								\
8941.180Skamil									\
8951.180Skamil	++ test##_caught;						\
8961.83Skamil}									\
8971.83Skamil									\
8981.83SkamilATF_TC_BODY(test, tc)							\
8991.83Skamil{									\
9001.83Skamil									\
9011.180Skamil	ptrace_siginfo(faked, test##_sighandler, & test##_caught); 	\
9021.83Skamil}
9031.83Skamil
9041.180SkamilPTRACE_SIGINFO(siginfo_set_unmodified, false)
9051.180SkamilPTRACE_SIGINFO(siginfo_set_faked, true)
9061.83Skamil
9071.83Skamil/// ----------------------------------------------------------------------------
9081.83Skamil
9091.180Skamil#define TRACE_THREADS_NUM 100
9101.180Skamil
9111.180Skamilstatic volatile int done;
9121.180Skamilpthread_mutex_t trace_threads_mtx = PTHREAD_MUTEX_INITIALIZER;
9131.180Skamil
9141.180Skamilstatic void *
9151.180Skamiltrace_threads_cb(void *arg __unused)
9161.180Skamil{
9171.180Skamil
9181.180Skamil	pthread_mutex_lock(&trace_threads_mtx);
9191.180Skamil	done++;
9201.180Skamil	pthread_mutex_unlock(&trace_threads_mtx);
9211.180Skamil
9221.180Skamil	while (done < TRACE_THREADS_NUM)
9231.180Skamil		sched_yield();
9241.180Skamil
9251.180Skamil	return NULL;
9261.180Skamil}
9271.180Skamil
9281.99Skamilstatic void
9291.180Skamiltrace_threads(bool trace_create, bool trace_exit, bool masked)
9301.1Skamil{
9311.1Skamil	const int sigval = SIGSTOP;
9321.180Skamil	pid_t child, wpid;
9331.1Skamil#if defined(TWAIT_HAVE_STATUS)
9341.1Skamil	int status;
9351.1Skamil#endif
9361.1Skamil	ptrace_state_t state;
9371.1Skamil	const int slen = sizeof(state);
9381.1Skamil	ptrace_event_t event;
9391.1Skamil	const int elen = sizeof(event);
9401.99Skamil	struct ptrace_siginfo info;
9411.180Skamil
9421.99Skamil	sigset_t intmask;
9431.99Skamil
9441.180Skamil	pthread_t t[TRACE_THREADS_NUM];
9451.180Skamil	int rv;
9461.180Skamil	size_t n;
9471.180Skamil	lwpid_t lid;
9481.1Skamil
9491.180Skamil	/* Track created and exited threads */
9501.180Skamil	struct lwp_event_count traced_lwps[__arraycount(t)] = {{0, 0}};
9511.14Schristos
9521.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
9531.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
9541.1Skamil	if (child == 0) {
9551.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
9561.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
9571.1Skamil
9581.99Skamil		if (masked) {
9591.99Skamil			sigemptyset(&intmask);
9601.99Skamil			sigaddset(&intmask, SIGTRAP);
9611.99Skamil			sigprocmask(SIG_BLOCK, &intmask, NULL);
9621.99Skamil		}
9631.99Skamil
9641.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
9651.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
9661.1Skamil
9671.180Skamil		for (n = 0; n < __arraycount(t); n++) {
9681.180Skamil			rv = pthread_create(&t[n], NULL, trace_threads_cb,
9691.180Skamil			    NULL);
9701.180Skamil			FORKEE_ASSERT(rv == 0);
9711.126Skamil		}
9721.1Skamil
9731.180Skamil		for (n = 0; n < __arraycount(t); n++) {
9741.180Skamil			rv = pthread_join(t[n], NULL);
9751.180Skamil			FORKEE_ASSERT(rv == 0);
9761.180Skamil		}
9771.1Skamil
9781.180Skamil		/*
9791.180Skamil		 * There is race between _exit() and pthread_join() detaching
9801.180Skamil		 * a thread. For simplicity kill the process after detecting
9811.180Skamil		 * LWP events.
9821.180Skamil		 */
9831.180Skamil		while (true)
9841.180Skamil			continue;
9851.1Skamil
9861.180Skamil		FORKEE_ASSERT(0 && "Not reached");
9871.1Skamil	}
9881.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
9891.1Skamil
9901.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
9911.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
9921.1Skamil
9931.1Skamil	validate_status_stopped(status, sigval);
9941.1Skamil
9951.99Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
9961.99Skamil	SYSCALL_REQUIRE(
9971.99Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
9981.99Skamil
9991.180Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
10001.180Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
10011.180Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
10021.180Skamil	    info.psi_siginfo.si_errno);
10031.180Skamil
10041.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
10051.99Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
10061.1Skamil
10071.180Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
10081.180Skamil	memset(&event, 0, sizeof(event));
10091.180Skamil	if (trace_create)
10101.180Skamil		event.pe_set_event |= PTRACE_LWP_CREATE;
10111.180Skamil	if (trace_exit)
10121.180Skamil		event.pe_set_event |= PTRACE_LWP_EXIT;
10131.99Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
10141.1Skamil
10151.99Skamil	DPRINTF("Before resuming the child process where it left off and "
10161.99Skamil	    "without signal to be sent\n");
10171.99Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
10181.1Skamil
10191.180Skamil	for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
10201.180Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
10211.180Skamil		    "SIGTRAP\n", TWAIT_FNAME);
10221.99Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
10231.99Skamil		    child);
10241.1Skamil
10251.99Skamil		validate_status_stopped(status, SIGTRAP);
10261.1Skamil
10271.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
10281.180Skamil		    "child\n");
10291.180Skamil		SYSCALL_REQUIRE(
10301.180Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
10311.180Skamil
10321.180Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
10331.180Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
10341.180Skamil		    "si_errno=%#x\n",
10351.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
10361.180Skamil		    info.psi_siginfo.si_errno);
10371.1Skamil
10381.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
10391.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
10401.1Skamil
10411.180Skamil		SYSCALL_REQUIRE(
10421.180Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
10431.1Skamil
10441.180Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
10451.180Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
10461.1Skamil
10471.180Skamil		lid = state.pe_lwp;
10481.180Skamil		DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
10491.1Skamil
10501.180Skamil		*FIND_EVENT_COUNT(traced_lwps, lid) += 1;
10511.1Skamil
10521.180Skamil		DPRINTF("Before resuming the child process where it left off "
10531.180Skamil		    "and without signal to be sent\n");
10541.180Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
10551.180Skamil	}
10561.1Skamil
10571.180Skamil	for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
10581.180Skamil		DPRINTF("Before calling %s() for the child - expected stopped "
10591.180Skamil		    "SIGTRAP\n", TWAIT_FNAME);
10601.180Skamil		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
10611.180Skamil		    child);
10621.1Skamil
10631.99Skamil		validate_status_stopped(status, SIGTRAP);
10641.1Skamil
10651.180Skamil		DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
10661.180Skamil		    "child\n");
10671.180Skamil		SYSCALL_REQUIRE(
10681.180Skamil		    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
10691.1Skamil
10701.180Skamil		DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
10711.180Skamil		DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
10721.180Skamil		    "si_errno=%#x\n",
10731.180Skamil		    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
10741.180Skamil		    info.psi_siginfo.si_errno);
10751.1Skamil
10761.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
10771.180Skamil		ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
10781.14Schristos
10791.180Skamil		SYSCALL_REQUIRE(
10801.180Skamil		    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
10811.1Skamil
10821.180Skamil		ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
10831.180Skamil		    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
10841.1Skamil
10851.180Skamil		lid = state.pe_lwp;
10861.180Skamil		DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
10871.1Skamil
10881.180Skamil		if (trace_create) {
10891.180Skamil			int *count = FIND_EVENT_COUNT(traced_lwps, lid);
10901.180Skamil			ATF_REQUIRE_EQ(*count, 1);
10911.180Skamil			*count = 0;
10921.99Skamil		}
10931.1Skamil
10941.99Skamil		DPRINTF("Before resuming the child process where it left off "
10951.99Skamil		    "and without signal to be sent\n");
10961.99Skamil		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
10971.1Skamil	}
10981.1Skamil
10991.180Skamil	kill(child, SIGKILL);
11001.180Skamil
11011.180Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
11021.180Skamil	    TWAIT_FNAME);
11031.180Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11041.180Skamil
11051.180Skamil	validate_status_signaled(status, SIGKILL, 0);
11061.1Skamil
11071.180Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
11081.180Skamil	    TWAIT_FNAME);
11091.180Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
11101.180Skamil}
11111.1Skamil
11121.180Skamil#define TRACE_THREADS(test, trace_create, trace_exit, mask)		\
11131.180SkamilATF_TC(test);								\
11141.180SkamilATF_TC_HEAD(test, tc)							\
11151.180Skamil{									\
11161.180Skamil        atf_tc_set_md_var(tc, "descr",					\
11171.180Skamil            "Verify spawning threads with%s tracing LWP create and"	\
11181.180Skamil	    "with%s tracing LWP exit", trace_create ? "" : "out",	\
11191.180Skamil	    trace_exit ? "" : "out");					\
11201.180Skamil}									\
11211.180Skamil									\
11221.180SkamilATF_TC_BODY(test, tc)							\
11231.180Skamil{									\
11241.180Skamil									\
11251.180Skamil        trace_threads(trace_create, trace_exit, mask);			\
11261.180Skamil}
11271.1Skamil
11281.180SkamilTRACE_THREADS(trace_thread_nolwpevents, false, false, false)
11291.180SkamilTRACE_THREADS(trace_thread_lwpexit, false, true, false)
11301.180SkamilTRACE_THREADS(trace_thread_lwpcreate, true, false, false)
11311.180SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true, false)
11321.102Skamil
11331.180SkamilTRACE_THREADS(trace_thread_lwpexit_masked_sigtrap, false, true, true)
11341.180SkamilTRACE_THREADS(trace_thread_lwpcreate_masked_sigtrap, true, false, true)
11351.180SkamilTRACE_THREADS(trace_thread_lwpcreate_and_exit_masked_sigtrap, true, true, true)
11361.1Skamil
11371.180Skamil/// ----------------------------------------------------------------------------
11381.1Skamil
11391.151Skamilstatic void *
11401.151Skamilthread_and_exec_thread_cb(void *arg __unused)
11411.151Skamil{
11421.151Skamil
11431.151Skamil	execlp("/bin/echo", "/bin/echo", NULL);
11441.151Skamil
11451.151Skamil	abort();
11461.151Skamil}
11471.151Skamil
11481.151Skamilstatic void
11491.151Skamilthreads_and_exec(void)
11501.151Skamil{
11511.151Skamil	const int sigval = SIGSTOP;
11521.151Skamil	pid_t child, wpid;
11531.151Skamil#if defined(TWAIT_HAVE_STATUS)
11541.151Skamil	int status;
11551.151Skamil#endif
11561.151Skamil	ptrace_state_t state;
11571.151Skamil	const int slen = sizeof(state);
11581.151Skamil	ptrace_event_t event;
11591.151Skamil	const int elen = sizeof(event);
11601.151Skamil	struct ptrace_siginfo info;
11611.151Skamil
11621.151Skamil	pthread_t t;
11631.151Skamil	lwpid_t lid;
11641.151Skamil
11651.151Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
11661.151Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
11671.151Skamil	if (child == 0) {
11681.151Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
11691.151Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
11701.151Skamil
11711.151Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
11721.151Skamil		FORKEE_ASSERT(raise(sigval) == 0);
11731.151Skamil
11741.151Skamil		FORKEE_ASSERT(pthread_create(&t, NULL,
11751.151Skamil		    thread_and_exec_thread_cb, NULL) == 0);
11761.151Skamil
11771.151Skamil		for (;;)
11781.151Skamil			continue;
11791.151Skamil
11801.151Skamil		FORKEE_ASSERT(0 && "Not reached");
11811.151Skamil	}
11821.151Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
11831.151Skamil
11841.151Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
11851.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
11861.151Skamil
11871.151Skamil	validate_status_stopped(status, sigval);
11881.151Skamil
11891.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
11901.151Skamil	SYSCALL_REQUIRE(
11911.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
11921.151Skamil
11931.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
11941.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
11951.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
11961.151Skamil	    info.psi_siginfo.si_errno);
11971.151Skamil
11981.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
11991.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
12001.151Skamil
12011.151Skamil	DPRINTF("Set LWP event mask for the child %d\n", child);
12021.151Skamil	memset(&event, 0, sizeof(event));
12031.151Skamil	event.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
12041.151Skamil	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
12051.151Skamil
12061.151Skamil	DPRINTF("Before resuming the child process where it left off and "
12071.151Skamil	    "without signal to be sent\n");
12081.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
12091.151Skamil
12101.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
12111.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
12121.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
12131.151Skamil	    child);
12141.151Skamil
12151.151Skamil	validate_status_stopped(status, SIGTRAP);
12161.151Skamil
12171.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
12181.151Skamil	    "child\n");
12191.151Skamil	SYSCALL_REQUIRE(
12201.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
12211.151Skamil
12221.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12231.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
12241.151Skamil	    "si_errno=%#x\n",
12251.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12261.151Skamil	    info.psi_siginfo.si_errno);
12271.151Skamil
12281.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
12291.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
12301.151Skamil
12311.151Skamil	SYSCALL_REQUIRE(
12321.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
12331.151Skamil
12341.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
12351.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
12361.151Skamil
12371.151Skamil	lid = state.pe_lwp;
12381.151Skamil	DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
12391.151Skamil
12401.151Skamil	DPRINTF("Before resuming the child process where it left off "
12411.151Skamil	    "and without signal to be sent\n");
12421.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
12431.151Skamil
12441.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
12451.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
12461.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
12471.151Skamil	    child);
12481.151Skamil
12491.151Skamil	validate_status_stopped(status, SIGTRAP);
12501.151Skamil
12511.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
12521.151Skamil	    "child\n");
12531.151Skamil	SYSCALL_REQUIRE(
12541.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
12551.151Skamil
12561.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12571.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
12581.151Skamil	    "si_errno=%#x\n",
12591.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12601.151Skamil	    info.psi_siginfo.si_errno);
12611.151Skamil
12621.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
12631.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
12641.151Skamil
12651.151Skamil	SYSCALL_REQUIRE(
12661.151Skamil	    ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
12671.151Skamil
12681.151Skamil	ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
12691.151Skamil	    "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
12701.151Skamil
12711.151Skamil	lid = state.pe_lwp;
12721.151Skamil	DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
12731.151Skamil
12741.151Skamil	DPRINTF("Before resuming the child process where it left off "
12751.151Skamil	    "and without signal to be sent\n");
12761.151Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
12771.151Skamil
12781.151Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
12791.151Skamil	    "SIGTRAP\n", TWAIT_FNAME);
12801.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
12811.151Skamil	    child);
12821.151Skamil
12831.151Skamil	validate_status_stopped(status, SIGTRAP);
12841.151Skamil
12851.151Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
12861.151Skamil	    "child\n");
12871.151Skamil	SYSCALL_REQUIRE(
12881.151Skamil	    ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
12891.151Skamil
12901.151Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
12911.151Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
12921.151Skamil	    "si_errno=%#x\n",
12931.151Skamil	    info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
12941.151Skamil	    info.psi_siginfo.si_errno);
12951.151Skamil
12961.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
12971.151Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
12981.151Skamil
12991.151Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
13001.151Skamil
13011.151Skamil	DPRINTF("Before calling %s() for the child - expected exited\n",
13021.151Skamil	    TWAIT_FNAME);
13031.151Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
13041.151Skamil
13051.151Skamil	validate_status_signaled(status, SIGKILL, 0);
13061.151Skamil
13071.151Skamil	DPRINTF("Before calling %s() for the child - expected no process\n",
13081.151Skamil	    TWAIT_FNAME);
13091.151Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
13101.151Skamil}
13111.151Skamil
13121.151SkamilATF_TC(threads_and_exec);
13131.151SkamilATF_TC_HEAD(threads_and_exec, tc)
13141.151Skamil{
13151.151Skamil        atf_tc_set_md_var(tc, "descr",
13161.151Skamil            "Verify that multithreaded application on exec() will report "
13171.151Skamil	    "LWP_EXIT events");
13181.151Skamil}
13191.151Skamil
13201.151SkamilATF_TC_BODY(threads_and_exec, tc)
13211.151Skamil{
13221.151Skamil
13231.151Skamil        threads_and_exec();
13241.151Skamil}
13251.151Skamil
13261.151Skamil/// ----------------------------------------------------------------------------
13271.151Skamil
13281.154SkamilATF_TC(suspend_no_deadlock);
13291.154SkamilATF_TC_HEAD(suspend_no_deadlock, tc)
13301.1Skamil{
13311.1Skamil	atf_tc_set_md_var(tc, "descr",
13321.1Skamil	    "Verify that the while the only thread within a process is "
13331.1Skamil	    "suspended, the whole process cannot be unstopped");
13341.1Skamil}
13351.1Skamil
13361.154SkamilATF_TC_BODY(suspend_no_deadlock, tc)
13371.1Skamil{
13381.1Skamil	const int exitval = 5;
13391.1Skamil	const int sigval = SIGSTOP;
13401.1Skamil	pid_t child, wpid;
13411.1Skamil#if defined(TWAIT_HAVE_STATUS)
13421.1Skamil	int status;
13431.1Skamil#endif
13441.1Skamil	struct ptrace_siginfo psi;
13451.1Skamil
13461.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
13471.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
13481.1Skamil	if (child == 0) {
13491.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
13501.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
13511.1Skamil
13521.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
13531.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
13541.1Skamil
13551.13Schristos		DPRINTF("Before exiting of the child process\n");
13561.1Skamil		_exit(exitval);
13571.1Skamil	}
13581.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
13591.1Skamil
13601.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
13611.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
13621.1Skamil
13631.1Skamil	validate_status_stopped(status, sigval);
13641.1Skamil
13651.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
13661.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
13671.1Skamil
13681.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
13691.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
13701.1Skamil
13711.13Schristos	DPRINTF("Before resuming the child process where it left off and "
13721.1Skamil	    "without signal to be sent\n");
13731.1Skamil	ATF_REQUIRE_ERRNO(EDEADLK,
13741.1Skamil	    ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
13751.1Skamil
13761.13Schristos	DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
13771.13Schristos	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
13781.1Skamil
13791.13Schristos	DPRINTF("Before resuming the child process where it left off and "
13801.1Skamil	    "without signal to be sent\n");
13811.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
13821.1Skamil
13831.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
13841.1Skamil	    TWAIT_FNAME);
13851.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
13861.1Skamil
13871.1Skamil	validate_status_exited(status, exitval);
13881.1Skamil
13891.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
13901.1Skamil	    TWAIT_FNAME);
13911.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
13921.1Skamil}
13931.1Skamil
13941.154Skamil/// ----------------------------------------------------------------------------
13951.154Skamil
13961.155Skamilstatic pthread_barrier_t barrier1_resume;
13971.155Skamilstatic pthread_barrier_t barrier2_resume;
13981.154Skamil
13991.155Skamilstatic void *
14001.155Skamilresume_thread(void *arg)
14011.154Skamil{
14021.154Skamil
14031.155Skamil	raise(SIGUSR1);
14041.155Skamil
14051.155Skamil	pthread_barrier_wait(&barrier1_resume);
14061.155Skamil
14071.155Skamil	/* Debugger will suspend the process here */
14081.155Skamil
14091.155Skamil	pthread_barrier_wait(&barrier2_resume);
14101.154Skamil
14111.155Skamil	raise(SIGUSR2);
14121.155Skamil
14131.155Skamil	return infinite_thread(arg);
14141.154Skamil}
14151.154Skamil
14161.155SkamilATF_TC(resume);
14171.155SkamilATF_TC_HEAD(resume, tc)
14181.1Skamil{
14191.1Skamil	atf_tc_set_md_var(tc, "descr",
14201.1Skamil	    "Verify that a thread can be suspended by a debugger and later "
14211.1Skamil	    "resumed by the debugger");
14221.1Skamil}
14231.1Skamil
14241.155SkamilATF_TC_BODY(resume, tc)
14251.1Skamil{
14261.1Skamil	const int sigval = SIGSTOP;
14271.1Skamil	pid_t child, wpid;
14281.1Skamil#if defined(TWAIT_HAVE_STATUS)
14291.1Skamil	int status;
14301.1Skamil#endif
14311.1Skamil	lwpid_t lid;
14321.1Skamil	struct ptrace_siginfo psi;
14331.155Skamil	pthread_t t;
14341.1Skamil
14351.13Schristos	DPRINTF("Before forking process PID=%d\n", getpid());
14361.13Schristos	SYSCALL_REQUIRE((child = fork()) != -1);
14371.1Skamil	if (child == 0) {
14381.13Schristos		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
14391.1Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
14401.1Skamil
14411.155Skamil		pthread_barrier_init(&barrier1_resume, NULL, 2);
14421.155Skamil		pthread_barrier_init(&barrier2_resume, NULL, 2);
14431.155Skamil
14441.13Schristos		DPRINTF("Before raising %s from child\n", strsignal(sigval));
14451.1Skamil		FORKEE_ASSERT(raise(sigval) == 0);
14461.1Skamil
14471.155Skamil		DPRINTF("Before creating new thread in child\n");
14481.155Skamil		FORKEE_ASSERT(pthread_create(&t, NULL, resume_thread, NULL) == 0);
14491.1Skamil
14501.155Skamil		pthread_barrier_wait(&barrier1_resume);
14511.1Skamil
14521.155Skamil		pthread_barrier_wait(&barrier2_resume);
14531.1Skamil
14541.155Skamil		infinite_thread(NULL);
14551.1Skamil	}
14561.13Schristos	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
14571.1Skamil
14581.13Schristos	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
14591.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
14601.1Skamil
14611.1Skamil	validate_status_stopped(status, sigval);
14621.1Skamil
14631.13Schristos	DPRINTF("Before resuming the child process where it left off and "
14641.1Skamil	    "without signal to be sent\n");
14651.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
14661.1Skamil
14671.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
14681.155Skamil	    "SIGUSR1\n", TWAIT_FNAME);
14691.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
14701.1Skamil
14711.155Skamil	validate_status_stopped(status, SIGUSR1);
14721.1Skamil
14731.13Schristos	DPRINTF("Before reading siginfo and lwpid_t\n");
14741.13Schristos	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
14751.1Skamil
14761.13Schristos	DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
14771.13Schristos	SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
14781.1Skamil
14791.155Skamil	lid = psi.psi_lwpid;
14801.1Skamil
14811.13Schristos	DPRINTF("Before resuming the child process where it left off and "
14821.1Skamil	    "without signal to be sent\n");
14831.13Schristos	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
14841.1Skamil
14851.155Skamil	DPRINTF("Before suspending the parent for 1 second, we expect no signals\n");
14861.155Skamil	SYSCALL_REQUIRE(sleep(1) == 0);
14871.155Skamil
14881.155Skamil#if defined(TWAIT_HAVE_OPTIONS)
14891.155Skamil	DPRINTF("Before calling %s() for the child - expected no status\n",
14901.155Skamil	    TWAIT_FNAME);
14911.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, WNOHANG), 0);
14921.155Skamil#endif
14931.155Skamil
14941.155Skamil	DPRINTF("Before resuming the child process where it left off and "
14951.155Skamil	    "without signal to be sent\n");
14961.155Skamil	SYSCALL_REQUIRE(ptrace(PT_STOP, child, NULL, 0) != -1);
14971.155Skamil
14981.13Schristos	DPRINTF("Before calling %s() for the child - expected stopped "
14991.155Skamil	    "SIGSTOP\n", TWAIT_FNAME);
15001.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
15011.1Skamil
15021.155Skamil	validate_status_stopped(status, SIGSTOP);
15031.1Skamil
15041.155Skamil	DPRINTF("Before resuming LWP %d\n", lid);
15051.155Skamil	SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, lid) != -1);
15061.155Skamil
15071.155Skamil	DPRINTF("Before resuming the child process where it left off and "
15081.155Skamil	    "without signal to be sent\n");
15091.155Skamil	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
15101.1Skamil
15111.155Skamil	DPRINTF("Before calling %s() for the child - expected stopped "
15121.155Skamil	    "SIGUSR2\n", TWAIT_FNAME);
15131.155Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
15141.1Skamil
15151.155Skamil	validate_status_stopped(status, SIGUSR2);
15161.1Skamil
15171.13Schristos	DPRINTF("Before resuming the child process where it left off and "
15181.1Skamil	    "without signal to be sent\n");
15191.155Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
15201.1Skamil
15211.13Schristos	DPRINTF("Before calling %s() for the child - expected exited\n",
15221.1Skamil	    TWAIT_FNAME);
15231.1Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
15241.1Skamil
15251.155Skamil	validate_status_signaled(status, SIGKILL, 0);
15261.1Skamil
15271.13Schristos	DPRINTF("Before calling %s() for the child - expected no process\n",
15281.1Skamil	    TWAIT_FNAME);
15291.1Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
15301.155Skamil}
15311.1Skamil
15321.155Skamil/// ----------------------------------------------------------------------------
15331.1Skamil
15341.106Skamilstatic void
15351.122Skamiluser_va0_disable(int operation)
15361.122Skamil{
15371.122Skamil	pid_t child, wpid;
15381.122Skamil#if defined(TWAIT_HAVE_STATUS)
15391.122Skamil	int status;
15401.122Skamil#endif
15411.122Skamil	const int sigval = SIGSTOP;
15421.122Skamil	int rv;
15431.122Skamil
15441.122Skamil	struct ptrace_siginfo info;
15451.122Skamil
15461.122Skamil	if (get_user_va0_disable() == 0)
15471.122Skamil		atf_tc_skip("vm.user_va0_disable is set to 0");
15481.122Skamil
15491.122Skamil	memset(&info, 0, sizeof(info));
15501.122Skamil
15511.122Skamil	DPRINTF("Before forking process PID=%d\n", getpid());
15521.122Skamil	SYSCALL_REQUIRE((child = fork()) != -1);
15531.122Skamil	if (child == 0) {
15541.122Skamil		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
15551.122Skamil		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
15561.122Skamil
15571.122Skamil		DPRINTF("Before raising %s from child\n", strsignal(sigval));
15581.122Skamil		FORKEE_ASSERT(raise(sigval) == 0);
15591.122Skamil
15601.122Skamil		/* NOTREACHED */
15611.122Skamil		FORKEE_ASSERTX(0 && "This shall not be reached");
15621.122Skamil		__unreachable();
15631.122Skamil	}
15641.122Skamil	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
15651.122Skamil
15661.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15671.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
15681.122Skamil
15691.122Skamil	validate_status_stopped(status, sigval);
15701.122Skamil
15711.122Skamil	DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
15721.122Skamil		"child\n");
15731.122Skamil	SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
15741.122Skamil		sizeof(info)) != -1);
15751.122Skamil
15761.122Skamil	DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
15771.122Skamil	DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
15781.122Skamil		"si_errno=%#x\n",
15791.122Skamil		info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
15801.122Skamil		info.psi_siginfo.si_errno);
15811.122Skamil
15821.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
15831.122Skamil	ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
15841.122Skamil
15851.122Skamil	DPRINTF("Before resuming the child process in PC=0x0 "
15861.122Skamil	    "and without signal to be sent\n");
15871.122Skamil	errno = 0;
15881.122Skamil	rv = ptrace(operation, child, (void *)0, 0);
15891.122Skamil	ATF_REQUIRE_EQ(errno, EINVAL);
15901.122Skamil	ATF_REQUIRE_EQ(rv, -1);
15911.122Skamil
15921.122Skamil	SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
15931.122Skamil
15941.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15951.122Skamil	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
15961.122Skamil	validate_status_signaled(status, SIGKILL, 0);
15971.122Skamil
15981.122Skamil	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
15991.122Skamil	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
16001.122Skamil}
16011.122Skamil
16021.122Skamil#define USER_VA0_DISABLE(test, operation)				\
16031.122SkamilATF_TC(test);								\
16041.122SkamilATF_TC_HEAD(test, tc)							\
16051.122Skamil{									\
16061.122Skamil	atf_tc_set_md_var(tc, "descr",					\
16071.122Skamil	    "Verify behavior of " #operation " with PC set to 0x0");	\
16081.122Skamil}									\
16091.122Skamil									\
16101.122SkamilATF_TC_BODY(test, tc)							\
16111.122Skamil{									\
16121.122Skamil									\
16131.122Skamil	user_va0_disable(operation);					\
16141.122Skamil}
16151.122Skamil
16161.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_continue, PT_CONTINUE)
16171.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_syscall, PT_SYSCALL)
16181.122SkamilUSER_VA0_DISABLE(user_va0_disable_pt_detach, PT_DETACH)
16191.122Skamil
16201.122Skamil/// ----------------------------------------------------------------------------
16211.122Skamil
16221.130Smgorny/*
16231.130Smgorny * Parse the core file and find the requested note.  If the reading or parsing
16241.130Smgorny * fails, the test is failed.  If the note is found, it is read onto buf, up to
16251.130Smgorny * buf_len.  The actual length of the note is returned (which can be greater
16261.130Smgorny * than buf_len, indicating that it has been truncated).  If the note is not
16271.130Smgorny * found, -1 is returned.
16281.172Sthorpej *
16291.172Sthorpej * If the note_name ends in '*', then we find the first note that matches
16301.172Sthorpej * the note_name prefix up to the '*' character, e.g.:
16311.172Sthorpej *
16321.172Sthorpej *	NetBSD-CORE@*
16331.172Sthorpej *
16341.172Sthorpej * finds the first note whose name prefix matches "NetBSD-CORE@".
16351.130Smgorny */
16361.130Smgornystatic ssize_t core_find_note(const char *core_path,
16371.130Smgorny    const char *note_name, uint64_t note_type, void *buf, size_t buf_len)
16381.130Smgorny{
16391.130Smgorny	int core_fd;
16401.130Smgorny	Elf *core_elf;
16411.130Smgorny	size_t core_numhdr, i;
16421.130Smgorny	ssize_t ret = -1;
16431.172Sthorpej	size_t name_len = strlen(note_name);
16441.172Sthorpej	bool prefix_match = false;
16451.172Sthorpej
16461.172Sthorpej	if (note_name[name_len - 1] == '*') {
16471.172Sthorpej		prefix_match = true;
16481.172Sthorpej		name_len--;
16491.172Sthorpej	} else {
16501.172Sthorpej		/* note: we assume note name will be null-terminated */
16511.172Sthorpej		name_len++;
16521.172Sthorpej	}
16531.130Smgorny
16541.130Smgorny	SYSCALL_REQUIRE((core_fd = open(core_path, O_RDONLY)) != -1);
16551.130Smgorny	SYSCALL_REQUIRE(elf_version(EV_CURRENT) != EV_NONE);
16561.130Smgorny	SYSCALL_REQUIRE((core_elf = elf_begin(core_fd, ELF_C_READ, NULL)));
16571.130Smgorny
16581.130Smgorny	SYSCALL_REQUIRE(elf_getphnum(core_elf, &core_numhdr) != 0);
16591.130Smgorny	for (i = 0; i < core_numhdr && ret == -1; i++) {
16601.130Smgorny		GElf_Phdr core_hdr;
16611.130Smgorny		size_t offset;
16621.130Smgorny		SYSCALL_REQUIRE(gelf_getphdr(core_elf, i, &core_hdr));
16631.130Smgorny		if (core_hdr.p_type != PT_NOTE)
16641.130Smgorny		    continue;
16651.130Smgorny
16661.130Smgorny		for (offset = core_hdr.p_offset;
16671.130Smgorny		    offset < core_hdr.p_offset + core_hdr.p_filesz;) {
16681.130Smgorny			Elf64_Nhdr note_hdr;
16691.130Smgorny			char name_buf[64];
16701.130Smgorny
16711.130Smgorny			switch (gelf_getclass(core_elf)) {
16721.130Smgorny			case ELFCLASS64:
16731.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &note_hdr,
16741.130Smgorny				    sizeof(note_hdr), offset)
16751.130Smgorny				    == sizeof(note_hdr));
16761.130Smgorny				offset += sizeof(note_hdr);
16771.130Smgorny				break;
16781.130Smgorny			case ELFCLASS32:
16791.130Smgorny				{
16801.130Smgorny				Elf32_Nhdr tmp_hdr;
16811.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, &tmp_hdr,
16821.130Smgorny				    sizeof(tmp_hdr), offset)
16831.130Smgorny				    == sizeof(tmp_hdr));
16841.130Smgorny				offset += sizeof(tmp_hdr);
16851.130Smgorny				note_hdr.n_namesz = tmp_hdr.n_namesz;
16861.130Smgorny				note_hdr.n_descsz = tmp_hdr.n_descsz;
16871.130Smgorny				note_hdr.n_type = tmp_hdr.n_type;
16881.130Smgorny				}
16891.130Smgorny				break;
16901.130Smgorny			}
16911.130Smgorny
16921.130Smgorny			/* indicates end of notes */
16931.130Smgorny			if (note_hdr.n_namesz == 0 || note_hdr.n_descsz == 0)
16941.130Smgorny				break;
16951.172Sthorpej			if (((prefix_match &&
16961.172Sthorpej			      note_hdr.n_namesz > name_len) ||
16971.172Sthorpej			     (!prefix_match &&
16981.172Sthorpej			      note_hdr.n_namesz == name_len)) &&
16991.130Smgorny			    note_hdr.n_namesz <= sizeof(name_buf)) {
17001.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, name_buf,
17011.130Smgorny				    note_hdr.n_namesz, offset)
17021.131Skamil				    == (ssize_t)(size_t)note_hdr.n_namesz);
17031.130Smgorny
17041.130Smgorny				if (!strncmp(note_name, name_buf, name_len) &&
17051.130Smgorny				    note_hdr.n_type == note_type)
17061.130Smgorny					ret = note_hdr.n_descsz;
17071.130Smgorny			}
17081.130Smgorny
17091.130Smgorny			offset += note_hdr.n_namesz;
17101.130Smgorny			/* fix to alignment */
17111.146Smgorny			offset = roundup(offset, core_hdr.p_align);
17121.130Smgorny
17131.130Smgorny			/* if name & type matched above */
17141.130Smgorny			if (ret != -1) {
17151.130Smgorny				ssize_t read_len = MIN(buf_len,
17161.130Smgorny				    note_hdr.n_descsz);
17171.130Smgorny				SYSCALL_REQUIRE(pread(core_fd, buf,
17181.130Smgorny				    read_len, offset) == read_len);
17191.130Smgorny				break;
17201.130Smgorny			}
17211.130Smgorny
17221.130Smgorny			offset += note_hdr.n_descsz;
17231.146Smgorny			/* fix to alignment */
17241.146Smgorny			offset = roundup(offset, core_hdr.p_align);
17251.130Smgorny		}
17261.130Smgorny	}
17271.130Smgorny
17281.130Smgorny	elf_end(core_elf);
17291.130Smgorny	close(core_fd);
17301.130Smgorny
17311.130Smgorny	return ret;
17321.130Smgorny}
17331.130Smgorny
17341.130SmgornyATF_TC(core_dump_procinfo);
17351.130SmgornyATF_TC_HEAD(core_dump_procinfo, tc)
17361.130Smgorny{
17371.130Smgorny	atf_tc_set_md_var(tc, "descr",
17381.130Smgorny		"Trigger a core dump and verify its contents.");
17391.130Smgorny}
17401.130Smgorny
17411.130SmgornyATF_TC_BODY(core_dump_procinfo, tc)
17421.130Smgorny{
17431.130Smgorny	const int exitval = 5;
17441.130Smgorny	pid_t child, wpid;
17451.130Smgorny#if defined(TWAIT_HAVE_STATUS)
17461.130Smgorny	const int sigval = SIGTRAP;
17471.130Smgorny	int status;
17481.130Smgorny#endif
17491.130Smgorny	char core_path[] = "/tmp/core.XXXXXX";
17501.130Smgorny	int core_fd;
17511.130Smgorny	struct netbsd_elfcore_procinfo procinfo;
17521.130Smgorny
17531.130Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
17541.130Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
17551.130Smgorny	if (child == 0) {
17561.130Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
17571.130Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
17581.130Smgorny
17591.130Smgorny		DPRINTF("Before triggering SIGTRAP\n");
17601.130Smgorny		trigger_trap();
17611.130Smgorny
17621.130Smgorny		DPRINTF("Before exiting of the child process\n");
17631.130Smgorny		_exit(exitval);
17641.130Smgorny	}
17651.130Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
17661.130Smgorny
17671.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
17681.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
17691.130Smgorny
17701.130Smgorny	validate_status_stopped(status, sigval);
17711.130Smgorny
17721.130Smgorny	SYSCALL_REQUIRE((core_fd = mkstemp(core_path)) != -1);
17731.130Smgorny	close(core_fd);
17741.130Smgorny
17751.130Smgorny	DPRINTF("Call DUMPCORE for the child process\n");
17761.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_DUMPCORE, child, core_path, strlen(core_path))
17771.130Smgorny	    != -1);
17781.130Smgorny
17791.130Smgorny	DPRINTF("Read core file\n");
17801.130Smgorny	ATF_REQUIRE_EQ(core_find_note(core_path, "NetBSD-CORE",
17811.130Smgorny	    ELF_NOTE_NETBSD_CORE_PROCINFO, &procinfo, sizeof(procinfo)),
17821.130Smgorny	    sizeof(procinfo));
17831.130Smgorny
17841.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_version, 1);
17851.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_cpisize, sizeof(procinfo));
17861.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_signo, SIGTRAP);
17871.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pid, child);
17881.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ppid, getpid());
17891.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_pgrp, getpgid(child));
17901.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_sid, getsid(child));
17911.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_ruid, getuid());
17921.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_euid, geteuid());
17931.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_rgid, getgid());
17941.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_egid, getegid());
17951.130Smgorny	ATF_CHECK_EQ(procinfo.cpi_nlwps, 1);
17961.173Skamil	ATF_CHECK(procinfo.cpi_siglwp > 0);
17971.130Smgorny
17981.130Smgorny	unlink(core_path);
17991.130Smgorny
18001.130Smgorny	DPRINTF("Before resuming the child process where it left off and "
18011.130Smgorny	    "without signal to be sent\n");
18021.130Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
18031.130Smgorny
18041.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18051.130Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
18061.130Smgorny
18071.130Smgorny	validate_status_exited(status, exitval);
18081.130Smgorny
18091.130Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
18101.130Smgorny	TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
18111.130Smgorny}
18121.130Smgorny
18131.130Smgorny/// ----------------------------------------------------------------------------
18141.130Smgorny
18151.138Smgorny#if defined(TWAIT_HAVE_STATUS)
18161.138Smgorny
18171.160Smgorny#define THREAD_CONCURRENT_BREAKPOINT_NUM 50
18181.156Smgorny#define THREAD_CONCURRENT_SIGNALS_NUM 50
18191.161Smgorny#define THREAD_CONCURRENT_WATCHPOINT_NUM 50
18201.138Smgorny
18211.138Smgorny/* List of signals to use for the test */
18221.138Smgornyconst int thread_concurrent_signals_list[] = {
18231.138Smgorny	SIGIO,
18241.138Smgorny	SIGXCPU,
18251.138Smgorny	SIGXFSZ,
18261.138Smgorny	SIGVTALRM,
18271.138Smgorny	SIGPROF,
18281.138Smgorny	SIGWINCH,
18291.138Smgorny	SIGINFO,
18301.138Smgorny	SIGUSR1,
18311.138Smgorny	SIGUSR2
18321.138Smgorny};
18331.138Smgorny
18341.157Smgornyenum thread_concurrent_signal_handling {
18351.157Smgorny	/* the signal is discarded by debugger */
18361.157Smgorny	TCSH_DISCARD,
18371.157Smgorny	/* the handler is set to SIG_IGN */
18381.157Smgorny	TCSH_SIG_IGN,
18391.157Smgorny	/* an actual handler is used */
18401.157Smgorny	TCSH_HANDLER
18411.157Smgorny};
18421.157Smgorny
18431.156Smgornystatic pthread_barrier_t thread_concurrent_barrier;
18441.158Smgornystatic pthread_key_t thread_concurrent_key;
18451.161Smgornystatic uint32_t thread_concurrent_watchpoint_var = 0;
18461.138Smgorny
18471.160Smgornystatic void *
18481.160Smgornythread_concurrent_breakpoint_thread(void *arg)
18491.160Smgorny{
18501.160Smgorny	static volatile int watchme = 1;
18511.160Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
18521.160Smgorny	DPRINTF("Before entering breakpoint func from LWP %d\n", _lwp_self());
18531.160Smgorny	check_happy(watchme);
18541.160Smgorny	return NULL;
18551.160Smgorny}
18561.160Smgorny
18571.157Smgornystatic void
18581.157Smgornythread_concurrent_sig_handler(int sig)
18591.157Smgorny{
18601.158Smgorny	void *tls_val = pthread_getspecific(thread_concurrent_key);
18611.158Smgorny	DPRINTF("Before increment, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
18621.158Smgorny	FORKEE_ASSERT(pthread_setspecific(thread_concurrent_key,
18631.158Smgorny	    (void*)((uintptr_t)tls_val + 1)) == 0);
18641.157Smgorny}
18651.157Smgorny
18661.138Smgornystatic void *
18671.138Smgornythread_concurrent_signals_thread(void *arg)
18681.138Smgorny{
18691.138Smgorny	int sigval = thread_concurrent_signals_list[
18701.138Smgorny	    _lwp_self() % __arraycount(thread_concurrent_signals_list)];
18711.158Smgorny	enum thread_concurrent_signal_handling *signal_handle = arg;
18721.158Smgorny	void *tls_val;
18731.158Smgorny
18741.156Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
18751.138Smgorny	DPRINTF("Before raising %s from LWP %d\n", strsignal(sigval),
18761.138Smgorny		_lwp_self());
18771.138Smgorny	pthread_kill(pthread_self(), sigval);
18781.158Smgorny	if (*signal_handle == TCSH_HANDLER) {
18791.158Smgorny	    tls_val = pthread_getspecific(thread_concurrent_key);
18801.158Smgorny	    DPRINTF("After raising, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
18811.158Smgorny	    FORKEE_ASSERT(tls_val == (void*)1);
18821.158Smgorny	}
18831.138Smgorny	return NULL;
18841.138Smgorny}
18851.138Smgorny
18861.161Smgornystatic void *
18871.161Smgornythread_concurrent_watchpoint_thread(void *arg)
18881.161Smgorny{
18891.161Smgorny	pthread_barrier_wait(&thread_concurrent_barrier);
18901.161Smgorny	DPRINTF("Before modifying var from LWP %d\n", _lwp_self());
18911.161Smgorny	thread_concurrent_watchpoint_var = 1;
18921.161Smgorny	return NULL;
18931.161Smgorny}
18941.161Smgorny
18951.160Smgorny#if defined(__i386__) || defined(__x86_64__)
18961.160Smgornyenum thread_concurrent_sigtrap_event {
18971.160Smgorny	TCSE_UNKNOWN,
18981.161Smgorny	TCSE_BREAKPOINT,
18991.161Smgorny	TCSE_WATCHPOINT
19001.160Smgorny};
19011.160Smgorny
19021.160Smgornystatic void
19031.160Smgornythread_concurrent_lwp_setup(pid_t child, lwpid_t lwpid);
19041.160Smgornystatic enum thread_concurrent_sigtrap_event
19051.160Smgornythread_concurrent_handle_sigtrap(pid_t child, ptrace_siginfo_t *info);
19061.160Smgorny#endif
19071.160Smgorny
19081.156Smgornystatic void
19091.157Smgornythread_concurrent_test(enum thread_concurrent_signal_handling signal_handle,
19101.161Smgorny    int breakpoint_threads, int signal_threads, int watchpoint_threads)
19111.138Smgorny{
19121.138Smgorny	const int exitval = 5;
19131.138Smgorny	const int sigval = SIGSTOP;
19141.138Smgorny	pid_t child, wpid;
19151.138Smgorny	int status;
19161.141Skamil	struct lwp_event_count signal_counts[THREAD_CONCURRENT_SIGNALS_NUM]
19171.141Skamil	    = {{0, 0}};
19181.160Smgorny	struct lwp_event_count bp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
19191.160Smgorny	    = {{0, 0}};
19201.161Smgorny	struct lwp_event_count wp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
19211.161Smgorny	    = {{0, 0}};
19221.159Smgorny	ptrace_event_t event;
19231.156Smgorny	int i;
19241.156Smgorny
19251.164Skamil#if defined(HAVE_DBREGS)
19261.164Skamil	if (!can_we_set_dbregs()) {
19271.164Skamil		atf_tc_skip("Either run this test as root or set sysctl(3) "
19281.164Skamil		            "security.models.extensions.user_set_dbregs to 1");
19291.164Skamil        }
19301.164Skamil#endif
19311.164Skamil
19321.164Skamil	atf_tc_skip("PR kern/54960");
19331.157Smgorny
19341.156Smgorny	/* Protect against out-of-bounds array access. */
19351.160Smgorny	ATF_REQUIRE(breakpoint_threads <= THREAD_CONCURRENT_BREAKPOINT_NUM);
19361.156Smgorny	ATF_REQUIRE(signal_threads <= THREAD_CONCURRENT_SIGNALS_NUM);
19371.161Smgorny	ATF_REQUIRE(watchpoint_threads <= THREAD_CONCURRENT_WATCHPOINT_NUM);
19381.138Smgorny
19391.138Smgorny	DPRINTF("Before forking process PID=%d\n", getpid());
19401.138Smgorny	SYSCALL_REQUIRE((child = fork()) != -1);
19411.138Smgorny	if (child == 0) {
19421.160Smgorny		pthread_t bp_threads[THREAD_CONCURRENT_BREAKPOINT_NUM];
19431.156Smgorny		pthread_t sig_threads[THREAD_CONCURRENT_SIGNALS_NUM];
19441.161Smgorny		pthread_t wp_threads[THREAD_CONCURRENT_WATCHPOINT_NUM];
19451.138Smgorny
19461.138Smgorny		DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
19471.138Smgorny		FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
19481.138Smgorny
19491.138Smgorny		DPRINTF("Before raising %s from child\n", strsignal(sigval));
19501.138Smgorny		FORKEE_ASSERT(raise(sigval) == 0);
19511.138Smgorny
19521.157Smgorny		if (signal_handle != TCSH_DISCARD) {
19531.157Smgorny			struct sigaction sa;
19541.157Smgorny			unsigned int j;
19551.157Smgorny
19561.157Smgorny			memset(&sa, 0, sizeof(sa));
19571.157Smgorny			if (signal_handle == TCSH_SIG_IGN)
19581.157Smgorny				sa.sa_handler = SIG_IGN;
19591.157Smgorny			else
19601.157Smgorny				sa.sa_handler = thread_concurrent_sig_handler;
19611.157Smgorny			sigemptyset(&sa.sa_mask);
19621.157Smgorny
19631.157Smgorny			for (j = 0;
19641.157Smgorny			    j < __arraycount(thread_concurrent_signals_list);
19651.157Smgorny			    j++)
19661.157Smgorny				FORKEE_ASSERT(sigaction(
19671.157Smgorny				    thread_concurrent_signals_list[j], &sa, NULL)
19681.157Smgorny				    != -1);
19691.157Smgorny		}
19701.157Smgorny
19711.138Smgorny		DPRINTF("Before starting threads from the child\n");
19721.138Smgorny		FORKEE_ASSERT(pthread_barrier_init(
19731.156Smgorny		    &thread_concurrent_barrier, NULL,
19741.161Smgorny		    breakpoint_threads + signal_threads + watchpoint_threads)
19751.161Smgorny		    == 0);
19761.158Smgorny		FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL)
19771.158Smgorny		    == 0);
19781.138Smgorny
19791.156Smgorny		for (i = 0; i < signal_threads; i++) {
19801.156Smgorny			FORKEE_ASSERT(pthread_create(&sig_threads[i], NULL,
19811.158Smgorny			    thread_concurrent_signals_thread,
19821.158Smgorny			    &signal_handle) == 0);
19831.138Smgorny		}
19841.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
19851.160Smgorny			FORKEE_ASSERT(pthread_create(&bp_threads[i], NULL,
19861.160Smgorny			    thread_concurrent_breakpoint_thread, NULL) == 0);
19871.160Smgorny		}
19881.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
19891.161Smgorny			FORKEE_ASSERT(pthread_create(&wp_threads[i], NULL,
19901.161Smgorny			    thread_concurrent_watchpoint_thread, NULL) == 0);
19911.161Smgorny		}
19921.138Smgorny
19931.138Smgorny		DPRINTF("Before joining threads from the child\n");
19941.161Smgorny		for (i = 0; i < watchpoint_threads; i++) {
19951.161Smgorny			FORKEE_ASSERT(pthread_join(wp_threads[i], NULL) == 0);
19961.161Smgorny		}
19971.160Smgorny		for (i = 0; i < breakpoint_threads; i++) {
19981.160Smgorny			FORKEE_ASSERT(pthread_join(bp_threads[i], NULL) == 0);
19991.160Smgorny		}
20001.156Smgorny		for (i = 0; i < signal_threads; i++) {
20011.156Smgorny			FORKEE_ASSERT(pthread_join(sig_threads[i], NULL) == 0);
20021.138Smgorny		}
20031.138Smgorny
20041.158Smgorny		FORKEE_ASSERT(pthread_key_delete(thread_concurrent_key) == 0);
20051.138Smgorny		FORKEE_ASSERT(pthread_barrier_destroy(
20061.156Smgorny		    &thread_concurrent_barrier) == 0);
20071.138Smgorny
20081.138Smgorny		DPRINTF("Before exiting of the child process\n");
20091.138Smgorny		_exit(exitval);
20101.138Smgorny	}
20111.138Smgorny	DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
20121.138Smgorny
20131.138Smgorny	DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
20141.138Smgorny	TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
20151.138Smgorny
20161.138Smgorny	validate_status_stopped(status, sigval);
20171.138Smgorny
20181.159Smgorny	DPRINTF("Set LWP event mask for the child process\n");
20191.159Smgorny	memset(&event, 0, sizeof(event));
20201.159Smgorny	event.pe_set_event |= PTRACE_LWP_CREATE;
20211.159Smgorny	SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, sizeof(event))
20221.159Smgorny	    != -1);
20231.159Smgorny
20241.138Smgorny	DPRINTF("Before resuming the child process where it left off\n");
20251.138Smgorny	SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
20261.138Smgorny
20271.138Smgorny	DPRINTF("Before entering signal collection loop\n");
20281.138Smgorny	while (1) {
20291.138Smgorny		ptrace_siginfo_t info;
20301.138Smgorny
20311.138Smgorny		DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
20321.138Smgorny		TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
20331.138Smgorny		    child);
20341.138Smgorny		if (WIFEXITED(status))
20351.138Smgorny			break;
20361.138Smgorny		/* Note: we use validate_status_stopped() to get nice error
20371.138Smgorny		 * message.  Signal is irrelevant since it won't be reached.
20381.138Smgorny		 */
20391.138Smgorny		else if (!WIFSTOPPED(status))
20401.138Smgorny			validate_status_stopped(status, 0);
20411.138Smgorny
20421.138Smgorny		DPRINTF("Before calling PT_GET_SIGINFO\n");
20431.138Smgorny		SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
20441.138Smgorny		    sizeof(info)) != -1);
20451.138Smgorny
20461.138Smgorny		DPRINTF("Received signal %d from LWP %d (wait: %d)\n",
20471.138Smgorny		    info.psi_siginfo.si_signo, info.psi_lwpid,
20481.138Smgorny		    WSTOPSIG(status));
20491.138Smgorny
20501.159Smgorny		ATF_CHECK_EQ_MSG(info.psi_siginfo.si_signo, WSTOPSIG(status),
20511.159Smgorny		    "lwp=%d, WSTOPSIG=%d, psi_siginfo=%d", info.psi_lwpid,
20521.159Smgorny		    WSTOPSIG(status), info.psi_siginfo.si_signo);
20531.159Smgorny
20541.159Smgorny		if (WSTOPSIG(status) != SIGTRAP) {
20551.159Smgorny			int expected_sig =
20561.159Smgorny			    thread_concurrent_signals_list[info.psi_lwpid %
20571.159Smgorny			    __arraycount(thread_concurrent_signals_list)];
20581.159Smgorny			ATF_CHECK_EQ_MSG(WSTOPSIG(status), expected_sig,
20591.159Smgorny				"lwp=%d, expected %d, got %d", info.psi_lwpid,
20601.159Smgorny				expected_sig, WSTOPSIG(status));
20611.138Smgorny
20621.159Smgorny			*FIND_EVENT_COUNT(signal_counts, info.psi_lwpid) += 1;
20631.160Smgorny		} else if (info.psi_siginfo.si_code == TRAP_LWP) {
20641.160Smgorny#if defined(__i386__) || defined(__x86_64__)
20651.160Smgorny			thread_concurrent_lwp_setup(child, info.psi_lwpid);
20661.160Smgorny#endif
20671.159Smgorny		} else {
20681.160Smgorny#if defined(__i386__) || defined(__x86_64__)
20691.160Smgorny			switch (thread_concurrent_handle_sigtrap(child, &info)) {
20701.160Smgorny				case TCSE_UNKNOWN:
20711.160Smgorny					/* already reported inside the function */
20721.160Smgorny					break;
20731.160Smgorny				case TCSE_BREAKPOINT:
20741.160Smgorny					*FIND_EVENT_COUNT(bp_counts,
20751.160Smgorny					    info.psi_lwpid) += 1;
20761.160Smgorny					break;
20771.161Smgorny				case TCSE_WATCHPOINT:
20781.161Smgorny					*FIND_EVENT_COUNT(wp_counts,
20791.161Smgorny					    info.psi_lwpid) += 1;
20801.161Smgorny					break;
20811.160Smgorny			}
20821.160Smgorny#else
20831.160Smgorny			ATF_CHECK_MSG(0, "Unexpected SIGTRAP, si_code=%d\n",
20841.160Smgorny			    info.psi_siginfo.si_code);
20851.160Smgorny#endif
20861.159Smgorny		}
20871.138Smgorny
20881.138Smgorny		DPRINTF("Before resuming the child process\n");
20891.157Smgorny		SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
20901.159Smgorny		     signal_handle != TCSH_DISCARD && WSTOPSIG(status) != SIGTRAP
20911.159Smgorny		     ? WSTOPSIG(status) : 0) != -1);
20921.138Smgorny	}
20931.138Smgorny
20941.156Smgorny	for (i = 0; i < signal_threads; i++)
20951.141Skamil		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 1,
20961.141Skamil		    "signal_counts[%d].lec_count=%d; lec_lwp=%d",
20971.141Skamil		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
20981.156Smgorny	for (i = signal_threads; i < THREAD_CONCURRENT_SIGNALS_NUM; i++)
20991.156Smgorny		ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 0,
21001.156Smgorny		    "extraneous signal_counts[%d].lec_count=%d; lec_lwp=%d",
21011.156Smgorny		    i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
21021.138Smgorny
21031.160Smgorny	for (i = 0; i < breakpoint_threads; i++)
21041.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 1,
21051.160Smgorny		    "bp_counts[%d].lec_count=%d; lec_lwp=%d",
21061.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
21071.160Smgorny	for (i = breakpoint_threads; i < THREAD_CONCURRENT_BREAKPOINT_NUM; i++)
21081.160Smgorny		ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 0,
21091.160Smgorny		    "extraneous bp_counts[%d].lec_count=%d; lec_lwp=%d",
21101.160Smgorny		    i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
21111.160Smgorny
21121.161Smgorny	for (i = 0; i < watchpoint_threads; i++)
21131.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 1,
21141.161Smgorny		    "wp_counts[%d].lec_count=%d; lec_lwp=%d",
21151.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
21161.161Smgorny	for (i = watchpoint_threads; i < THREAD_CONCURRENT_WATCHPOINT_NUM; i++)
21171.161Smgorny		ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 0,
21181.161Smgorny		    "extraneous wp_counts[%d].lec_count=%d; lec_lwp=%d",
21191.161Smgorny		    i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
21201.161Smgorny
21211.138Smgorny	validate_status_exited(status, exitval);
21221.138Smgorny}
21231.138Smgorny
21241.161Smgorny#define THREAD_CONCURRENT_TEST(test, sig_hdl, bps, sigs, wps, descr)	\
21251.156SmgornyATF_TC(test);								\
21261.156SmgornyATF_TC_HEAD(test, tc)							\
21271.156Smgorny{									\
21281.156Smgorny	atf_tc_set_md_var(tc, "descr", descr);				\
21291.156Smgorny}									\
21301.156Smgorny									\
21311.156SmgornyATF_TC_BODY(test, tc)							\
21321.156Smgorny{									\
21331.161Smgorny	thread_concurrent_test(sig_hdl, bps, sigs, wps);		\
21341.156Smgorny}
21351.156Smgorny
21361.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals, TCSH_DISCARD,
21371.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
21381.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
21391.157Smgorny    "correctly");
21401.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_sig_ign, TCSH_SIG_IGN,
21411.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
21421.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
21431.157Smgorny    "correctly and passed back to SIG_IGN handler");
21441.157SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_signals_handler, TCSH_HANDLER,
21451.161Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
21461.157Smgorny    "Verify that concurrent signals issued to a single thread are reported "
21471.157Smgorny    "correctly and passed back to a handler function");
21481.156Smgorny
21491.163Skamil#if defined(__i386__) || defined(__x86_64__)
21501.160SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_breakpoints, TCSH_DISCARD,
21511.161Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, 0,
21521.161Smgorny    "Verify that concurrent breakpoints are reported correctly");
21531.161SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_watchpoints, TCSH_DISCARD,
21541.161Smgorny    0, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
21551.160Smgorny    "Verify that concurrent breakpoints are reported correctly");
21561.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp, TCSH_DISCARD,
21571.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
21581.162Smgorny    "Verify that concurrent breakpoints and watchpoints are reported "
21591.162Smgorny    "correctly");
21601.162Smgorny
21611.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig, TCSH_DISCARD,
21621.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
21631.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly");
21641.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_sig_ign, TCSH_SIG_IGN,
21651.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
21661.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
21671.162Smgorny    "and passed back to SIG_IGN handler");
21681.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_handler, TCSH_HANDLER,
21691.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
21701.162Smgorny    "Verify that concurrent breakpoints and signals are reported correctly "
21711.162Smgorny    "and passed back to a handler function");
21721.162Smgorny
21731.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig, TCSH_DISCARD,
21741.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
21751.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly");
21761.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_sig_ign, TCSH_SIG_IGN,
21771.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
21781.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
21791.162Smgorny    "and passed back to SIG_IGN handler");
21801.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_handler, TCSH_HANDLER,
21811.162Smgorny    0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
21821.162Smgorny    "Verify that concurrent watchpoints and signals are reported correctly "
21831.162Smgorny    "and passed back to a handler function");
21841.162Smgorny
21851.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig, TCSH_DISCARD,
21861.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
21871.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
21881.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
21891.162Smgorny    "correctly");
21901.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_sig_ign, TCSH_SIG_IGN,
21911.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
21921.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
21931.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
21941.162Smgorny    "correctly and passed back to SIG_IGN handler");
21951.162SmgornyTHREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_handler, TCSH_HANDLER,
21961.162Smgorny    THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
21971.162Smgorny    THREAD_CONCURRENT_WATCHPOINT_NUM,
21981.162Smgorny    "Verify that concurrent breakpoints, watchpoints and signals are reported "
21991.162Smgorny    "correctly and passed back to a handler function");
22001.163Skamil#endif
22011.160Smgorny
22021.138Smgorny#endif /*defined(TWAIT_HAVE_STATUS)*/
22031.138Smgorny
22041.138Smgorny/// ----------------------------------------------------------------------------
22051.138Smgorny
22061.174Skamil#include "t_ptrace_register_wait.h"
22071.175Skamil#include "t_ptrace_syscall_wait.h"
22081.176Skamil#include "t_ptrace_step_wait.h"
22091.177Skamil#include "t_ptrace_kill_wait.h"
22101.178Skamil#include "t_ptrace_bytetransfer_wait.h"
22111.179Skamil#include "t_ptrace_clone_wait.h"
22121.180Skamil#include "t_ptrace_fork_wait.h"
22131.181Skamil#include "t_ptrace_signal_wait.h"
22141.183Skamil#include "t_ptrace_eventmask_wait.h"
22151.185Skamil#include "t_ptrace_lwp_wait.h"
22161.186Skamil#include "t_ptrace_exec_wait.h"
22171.174Skamil
22181.174Skamil/// ----------------------------------------------------------------------------
22191.174Skamil
22201.1Skamil#include "t_ptrace_amd64_wait.h"
22211.1Skamil#include "t_ptrace_i386_wait.h"
22221.1Skamil#include "t_ptrace_x86_wait.h"
22231.1Skamil
22241.165Skamil/// ----------------------------------------------------------------------------
22251.165Skamil
22261.165Skamil#else
22271.165SkamilATF_TC(dummy);
22281.165SkamilATF_TC_HEAD(dummy, tc)
22291.165Skamil{
22301.165Skamil	atf_tc_set_md_var(tc, "descr", "A dummy test");
22311.165Skamil}
22321.165Skamil
22331.165SkamilATF_TC_BODY(dummy, tc)
22341.165Skamil{
22351.165Skamil
22361.165Skamil	// Dummy, skipped
22371.165Skamil	// The ATF framework requires at least a single defined test.
22381.165Skamil}
22391.165Skamil#endif
22401.165Skamil
22411.1SkamilATF_TP_ADD_TCS(tp)
22421.1Skamil{
22431.1Skamil	setvbuf(stdout, NULL, _IONBF, 0);
22441.1Skamil	setvbuf(stderr, NULL, _IONBF, 0);
22451.33Skamil
22461.165Skamil#ifdef ENABLE_TESTS
22471.37Skamil	ATF_TP_ADD_TC(tp, traceme_pid1_parent);
22481.37Skamil
22491.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sees_terminaton_before_the_parent);
22501.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_sysctl_lookup_without_duplicates);
22511.61Skre	ATF_TP_ADD_TC_HAVE_PID(tp,
22521.61Skre		unrelated_tracer_sees_terminaton_before_the_parent);
22531.67Skamil	ATF_TP_ADD_TC_HAVE_PID(tp, tracer_attach_to_unrelated_stopped_process);
22541.51Skamil
22551.51Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_child);
22561.66Skamil	ATF_TP_ADD_TC(tp, parent_attach_to_its_stopped_child);
22571.51Skamil
22581.51Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_parent);
22591.65Skamil	ATF_TP_ADD_TC(tp, child_attach_to_its_stopped_parent);
22601.51Skamil
22611.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
22621.51Skamil		tracee_sees_its_original_parent_getppid);
22631.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
22641.51Skamil		tracee_sees_its_original_parent_sysctl_kinfo_proc2);
22651.51Skamil	ATF_TP_ADD_TC_HAVE_PID(tp,
22661.51Skamil		tracee_sees_its_original_parent_procfs_status);
22671.1Skamil
22681.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_unmodified);
22691.79Skamil	ATF_TP_ADD_TC(tp, siginfo_set_faked);
22701.79Skamil
22711.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_nolwpevents);
22721.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit);
22731.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate);
22741.119Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit);
22751.1Skamil
22761.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpexit_masked_sigtrap);
22771.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_masked_sigtrap);
22781.153Skamil	ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit_masked_sigtrap);
22791.153Skamil
22801.151Skamil	ATF_TP_ADD_TC(tp, threads_and_exec);
22811.151Skamil
22821.154Skamil	ATF_TP_ADD_TC(tp, suspend_no_deadlock);
22831.1Skamil
22841.155Skamil	ATF_TP_ADD_TC(tp, resume);
22851.1Skamil
22861.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_continue);
22871.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall);
22881.122Skamil	ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach);
22891.122Skamil
22901.130Smgorny	ATF_TP_ADD_TC(tp, core_dump_procinfo);
22911.130Smgorny
22921.138Smgorny#if defined(TWAIT_HAVE_STATUS)
22931.138Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals);
22941.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_sig_ign);
22951.157Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_signals_handler);
22961.160Smgorny#if defined(__i386__) || defined(__x86_64__)
22971.160Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_breakpoints);
22981.161Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_watchpoints);
22991.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp);
23001.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig);
23011.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_sig_ign);
23021.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_handler);
23031.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig);
23041.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_sig_ign);
23051.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_handler);
23061.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig);
23071.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_sig_ign);
23081.162Smgorny	ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_handler);
23091.160Smgorny#endif
23101.138Smgorny#endif
23111.138Smgorny
23121.174Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_REGISTER();
23131.175Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_SYSCALL();
23141.176Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_STEP();
23151.177Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_KILL();
23161.178Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_BYTETRANSFER();
23171.179Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_CLONE();
23181.180Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_FORK();
23191.181Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_SIGNAL();
23201.183Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_EVENTMASK();
23211.185Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_LWP();
23221.186Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_EXEC();
23231.174Skamil
23241.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
23251.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_I386();
23261.1Skamil	ATF_TP_ADD_TCS_PTRACE_WAIT_X86();
23271.1Skamil
23281.165Skamil#else
23291.165Skamil	ATF_TP_ADD_TC(tp, dummy);
23301.165Skamil#endif
23311.165Skamil
23321.1Skamil	return atf_no_error();
23331.1Skamil}
2334