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