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