Module Name: src
Committed By: kamil
Date: Tue May 5 00:50:39 UTC 2020
Modified Files:
src/tests/lib/libc/sys: t_ptrace_wait.c t_ptrace_wait.h
Added Files:
src/tests/lib/libc/sys: t_ptrace_threads_wait.h
Log Message:
Move threads tests out of t_ptrace_wait.c to t_ptrace_threads_wait.h
The same tests are now included with the preprocessor in t_ptrace_wait.c.
No functional change intended.
To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/tests/lib/libc/sys/t_ptrace_threads_wait.h
cvs rdiff -u -r1.187 -r1.188 src/tests/lib/libc/sys/t_ptrace_wait.c
cvs rdiff -u -r1.27 -r1.28 src/tests/lib/libc/sys/t_ptrace_wait.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/tests/lib/libc/sys/t_ptrace_wait.c
diff -u src/tests/lib/libc/sys/t_ptrace_wait.c:1.187 src/tests/lib/libc/sys/t_ptrace_wait.c:1.188
--- src/tests/lib/libc/sys/t_ptrace_wait.c:1.187 Tue May 5 00:33:37 2020
+++ src/tests/lib/libc/sys/t_ptrace_wait.c Tue May 5 00:50:39 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_wait.c,v 1.187 2020/05/05 00:33:37 kamil Exp $ */
+/* $NetBSD: t_ptrace_wait.c,v 1.188 2020/05/05 00:50:39 kamil Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_ptrace_wait.c,v 1.187 2020/05/05 00:33:37 kamil Exp $");
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.188 2020/05/05 00:50:39 kamil Exp $");
#define __LEGACY_PT_LWPINFO
@@ -229,631 +229,6 @@ PTRACE_SIGINFO(siginfo_set_faked, true)
/// ----------------------------------------------------------------------------
-#define TRACE_THREADS_NUM 100
-
-static volatile int done;
-pthread_mutex_t trace_threads_mtx = PTHREAD_MUTEX_INITIALIZER;
-
-static void *
-trace_threads_cb(void *arg __unused)
-{
-
- pthread_mutex_lock(&trace_threads_mtx);
- done++;
- pthread_mutex_unlock(&trace_threads_mtx);
-
- while (done < TRACE_THREADS_NUM)
- sched_yield();
-
- return NULL;
-}
-
-static void
-trace_threads(bool trace_create, bool trace_exit, bool masked)
-{
- const int sigval = SIGSTOP;
- pid_t child, wpid;
-#if defined(TWAIT_HAVE_STATUS)
- int status;
-#endif
- ptrace_state_t state;
- const int slen = sizeof(state);
- ptrace_event_t event;
- const int elen = sizeof(event);
- struct ptrace_siginfo info;
-
- sigset_t intmask;
-
- pthread_t t[TRACE_THREADS_NUM];
- int rv;
- size_t n;
- lwpid_t lid;
-
- /* Track created and exited threads */
- struct lwp_event_count traced_lwps[__arraycount(t)] = {{0, 0}};
-
- DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
- if (child == 0) {
- DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
- FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
-
- if (masked) {
- sigemptyset(&intmask);
- sigaddset(&intmask, SIGTRAP);
- sigprocmask(SIG_BLOCK, &intmask, NULL);
- }
-
- DPRINTF("Before raising %s from child\n", strsignal(sigval));
- FORKEE_ASSERT(raise(sigval) == 0);
-
- for (n = 0; n < __arraycount(t); n++) {
- rv = pthread_create(&t[n], NULL, trace_threads_cb,
- NULL);
- FORKEE_ASSERT(rv == 0);
- }
-
- for (n = 0; n < __arraycount(t); n++) {
- rv = pthread_join(t[n], NULL);
- FORKEE_ASSERT(rv == 0);
- }
-
- /*
- * There is race between _exit() and pthread_join() detaching
- * a thread. For simplicity kill the process after detecting
- * LWP events.
- */
- while (true)
- continue;
-
- FORKEE_ASSERT(0 && "Not reached");
- }
- DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
-
- DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
- validate_status_stopped(status, sigval);
-
- DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
- SYSCALL_REQUIRE(
- ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
-
- DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
- DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
- info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
- info.psi_siginfo.si_errno);
-
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
-
- DPRINTF("Set LWP event mask for the child %d\n", child);
- memset(&event, 0, sizeof(event));
- if (trace_create)
- event.pe_set_event |= PTRACE_LWP_CREATE;
- if (trace_exit)
- event.pe_set_event |= PTRACE_LWP_EXIT;
- SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
-
- DPRINTF("Before resuming the child process where it left off and "
- "without signal to be sent\n");
- SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
- for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
- DPRINTF("Before calling %s() for the child - expected stopped "
- "SIGTRAP\n", TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
- child);
-
- validate_status_stopped(status, SIGTRAP);
-
- DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
- "child\n");
- SYSCALL_REQUIRE(
- ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
-
- DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
- DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
- "si_errno=%#x\n",
- info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
- info.psi_siginfo.si_errno);
-
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
-
- SYSCALL_REQUIRE(
- ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
-
- ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
- "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
-
- lid = state.pe_lwp;
- DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
-
- *FIND_EVENT_COUNT(traced_lwps, lid) += 1;
-
- DPRINTF("Before resuming the child process where it left off "
- "and without signal to be sent\n");
- SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
- }
-
- for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
- DPRINTF("Before calling %s() for the child - expected stopped "
- "SIGTRAP\n", TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
- child);
-
- validate_status_stopped(status, SIGTRAP);
-
- DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
- "child\n");
- SYSCALL_REQUIRE(
- ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
-
- DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
- DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
- "si_errno=%#x\n",
- info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
- info.psi_siginfo.si_errno);
-
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
-
- SYSCALL_REQUIRE(
- ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
-
- ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
- "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
-
- lid = state.pe_lwp;
- DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
-
- if (trace_create) {
- int *count = FIND_EVENT_COUNT(traced_lwps, lid);
- ATF_REQUIRE_EQ(*count, 1);
- *count = 0;
- }
-
- DPRINTF("Before resuming the child process where it left off "
- "and without signal to be sent\n");
- SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
- }
-
- kill(child, SIGKILL);
-
- DPRINTF("Before calling %s() for the child - expected exited\n",
- TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
- validate_status_signaled(status, SIGKILL, 0);
-
- DPRINTF("Before calling %s() for the child - expected no process\n",
- TWAIT_FNAME);
- TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
-}
-
-#define TRACE_THREADS(test, trace_create, trace_exit, mask) \
-ATF_TC(test); \
-ATF_TC_HEAD(test, tc) \
-{ \
- atf_tc_set_md_var(tc, "descr", \
- "Verify spawning threads with%s tracing LWP create and" \
- "with%s tracing LWP exit", trace_create ? "" : "out", \
- trace_exit ? "" : "out"); \
-} \
- \
-ATF_TC_BODY(test, tc) \
-{ \
- \
- trace_threads(trace_create, trace_exit, mask); \
-}
-
-TRACE_THREADS(trace_thread_nolwpevents, false, false, false)
-TRACE_THREADS(trace_thread_lwpexit, false, true, false)
-TRACE_THREADS(trace_thread_lwpcreate, true, false, false)
-TRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true, false)
-
-TRACE_THREADS(trace_thread_lwpexit_masked_sigtrap, false, true, true)
-TRACE_THREADS(trace_thread_lwpcreate_masked_sigtrap, true, false, true)
-TRACE_THREADS(trace_thread_lwpcreate_and_exit_masked_sigtrap, true, true, true)
-
-/// ----------------------------------------------------------------------------
-
-static void *
-thread_and_exec_thread_cb(void *arg __unused)
-{
-
- execlp("/bin/echo", "/bin/echo", NULL);
-
- abort();
-}
-
-static void
-threads_and_exec(void)
-{
- const int sigval = SIGSTOP;
- pid_t child, wpid;
-#if defined(TWAIT_HAVE_STATUS)
- int status;
-#endif
- ptrace_state_t state;
- const int slen = sizeof(state);
- ptrace_event_t event;
- const int elen = sizeof(event);
- struct ptrace_siginfo info;
-
- pthread_t t;
- lwpid_t lid;
-
- DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
- if (child == 0) {
- DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
- FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
-
- DPRINTF("Before raising %s from child\n", strsignal(sigval));
- FORKEE_ASSERT(raise(sigval) == 0);
-
- FORKEE_ASSERT(pthread_create(&t, NULL,
- thread_and_exec_thread_cb, NULL) == 0);
-
- for (;;)
- continue;
-
- FORKEE_ASSERT(0 && "Not reached");
- }
- DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
-
- DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
- validate_status_stopped(status, sigval);
-
- DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
- SYSCALL_REQUIRE(
- ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
-
- DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
- DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
- info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
- info.psi_siginfo.si_errno);
-
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
-
- DPRINTF("Set LWP event mask for the child %d\n", child);
- memset(&event, 0, sizeof(event));
- event.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
- SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
-
- DPRINTF("Before resuming the child process where it left off and "
- "without signal to be sent\n");
- SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
- DPRINTF("Before calling %s() for the child - expected stopped "
- "SIGTRAP\n", TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
- child);
-
- validate_status_stopped(status, SIGTRAP);
-
- DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
- "child\n");
- SYSCALL_REQUIRE(
- ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
-
- DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
- DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
- "si_errno=%#x\n",
- info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
- info.psi_siginfo.si_errno);
-
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
-
- SYSCALL_REQUIRE(
- ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
-
- ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
- "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
-
- lid = state.pe_lwp;
- DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
-
- DPRINTF("Before resuming the child process where it left off "
- "and without signal to be sent\n");
- SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
- DPRINTF("Before calling %s() for the child - expected stopped "
- "SIGTRAP\n", TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
- child);
-
- validate_status_stopped(status, SIGTRAP);
-
- DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
- "child\n");
- SYSCALL_REQUIRE(
- ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
-
- DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
- DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
- "si_errno=%#x\n",
- info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
- info.psi_siginfo.si_errno);
-
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
-
- SYSCALL_REQUIRE(
- ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
-
- ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
- "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
-
- lid = state.pe_lwp;
- DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
-
- DPRINTF("Before resuming the child process where it left off "
- "and without signal to be sent\n");
- SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
- DPRINTF("Before calling %s() for the child - expected stopped "
- "SIGTRAP\n", TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
- child);
-
- validate_status_stopped(status, SIGTRAP);
-
- DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
- "child\n");
- SYSCALL_REQUIRE(
- ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
-
- DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
- DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
- "si_errno=%#x\n",
- info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
- info.psi_siginfo.si_errno);
-
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
-
- SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
-
- DPRINTF("Before calling %s() for the child - expected exited\n",
- TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
- validate_status_signaled(status, SIGKILL, 0);
-
- DPRINTF("Before calling %s() for the child - expected no process\n",
- TWAIT_FNAME);
- TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
-}
-
-ATF_TC(threads_and_exec);
-ATF_TC_HEAD(threads_and_exec, tc)
-{
- atf_tc_set_md_var(tc, "descr",
- "Verify that multithreaded application on exec() will report "
- "LWP_EXIT events");
-}
-
-ATF_TC_BODY(threads_and_exec, tc)
-{
-
- threads_and_exec();
-}
-
-/// ----------------------------------------------------------------------------
-
-ATF_TC(suspend_no_deadlock);
-ATF_TC_HEAD(suspend_no_deadlock, tc)
-{
- atf_tc_set_md_var(tc, "descr",
- "Verify that the while the only thread within a process is "
- "suspended, the whole process cannot be unstopped");
-}
-
-ATF_TC_BODY(suspend_no_deadlock, tc)
-{
- const int exitval = 5;
- const int sigval = SIGSTOP;
- pid_t child, wpid;
-#if defined(TWAIT_HAVE_STATUS)
- int status;
-#endif
- struct ptrace_siginfo psi;
-
- DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
- if (child == 0) {
- DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
- FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
-
- DPRINTF("Before raising %s from child\n", strsignal(sigval));
- FORKEE_ASSERT(raise(sigval) == 0);
-
- DPRINTF("Before exiting of the child process\n");
- _exit(exitval);
- }
- DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
-
- DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
- validate_status_stopped(status, sigval);
-
- DPRINTF("Before reading siginfo and lwpid_t\n");
- SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
-
- DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
- SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
-
- DPRINTF("Before resuming the child process where it left off and "
- "without signal to be sent\n");
- ATF_REQUIRE_ERRNO(EDEADLK,
- ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
-
- DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
- SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
-
- DPRINTF("Before resuming the child process where it left off and "
- "without signal to be sent\n");
- SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
- DPRINTF("Before calling %s() for the child - expected exited\n",
- TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
- validate_status_exited(status, exitval);
-
- DPRINTF("Before calling %s() for the child - expected no process\n",
- TWAIT_FNAME);
- TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
-}
-
-/// ----------------------------------------------------------------------------
-
-static pthread_barrier_t barrier1_resume;
-static pthread_barrier_t barrier2_resume;
-
-static void *
-resume_thread(void *arg)
-{
-
- raise(SIGUSR1);
-
- pthread_barrier_wait(&barrier1_resume);
-
- /* Debugger will suspend the process here */
-
- pthread_barrier_wait(&barrier2_resume);
-
- raise(SIGUSR2);
-
- return infinite_thread(arg);
-}
-
-ATF_TC(resume);
-ATF_TC_HEAD(resume, tc)
-{
- atf_tc_set_md_var(tc, "descr",
- "Verify that a thread can be suspended by a debugger and later "
- "resumed by the debugger");
-}
-
-ATF_TC_BODY(resume, tc)
-{
- const int sigval = SIGSTOP;
- pid_t child, wpid;
-#if defined(TWAIT_HAVE_STATUS)
- int status;
-#endif
- lwpid_t lid;
- struct ptrace_siginfo psi;
- pthread_t t;
-
- DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
- if (child == 0) {
- DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
- FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
-
- pthread_barrier_init(&barrier1_resume, NULL, 2);
- pthread_barrier_init(&barrier2_resume, NULL, 2);
-
- DPRINTF("Before raising %s from child\n", strsignal(sigval));
- FORKEE_ASSERT(raise(sigval) == 0);
-
- DPRINTF("Before creating new thread in child\n");
- FORKEE_ASSERT(pthread_create(&t, NULL, resume_thread, NULL) == 0);
-
- pthread_barrier_wait(&barrier1_resume);
-
- pthread_barrier_wait(&barrier2_resume);
-
- infinite_thread(NULL);
- }
- DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
-
- DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
- validate_status_stopped(status, sigval);
-
- DPRINTF("Before resuming the child process where it left off and "
- "without signal to be sent\n");
- SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
- DPRINTF("Before calling %s() for the child - expected stopped "
- "SIGUSR1\n", TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
- validate_status_stopped(status, SIGUSR1);
-
- DPRINTF("Before reading siginfo and lwpid_t\n");
- SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
-
- DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
- SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
-
- lid = psi.psi_lwpid;
-
- DPRINTF("Before resuming the child process where it left off and "
- "without signal to be sent\n");
- SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
- DPRINTF("Before suspending the parent for 1 second, we expect no signals\n");
- SYSCALL_REQUIRE(sleep(1) == 0);
-
-#if defined(TWAIT_HAVE_OPTIONS)
- DPRINTF("Before calling %s() for the child - expected no status\n",
- TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, WNOHANG), 0);
-#endif
-
- DPRINTF("Before resuming the child process where it left off and "
- "without signal to be sent\n");
- SYSCALL_REQUIRE(ptrace(PT_STOP, child, NULL, 0) != -1);
-
- DPRINTF("Before calling %s() for the child - expected stopped "
- "SIGSTOP\n", TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
- validate_status_stopped(status, SIGSTOP);
-
- DPRINTF("Before resuming LWP %d\n", lid);
- SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, lid) != -1);
-
- DPRINTF("Before resuming the child process where it left off and "
- "without signal to be sent\n");
- SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
- DPRINTF("Before calling %s() for the child - expected stopped "
- "SIGUSR2\n", TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
- validate_status_stopped(status, SIGUSR2);
-
- DPRINTF("Before resuming the child process where it left off and "
- "without signal to be sent\n");
- SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
-
- DPRINTF("Before calling %s() for the child - expected exited\n",
- TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
- validate_status_signaled(status, SIGKILL, 0);
-
- DPRINTF("Before calling %s() for the child - expected no process\n",
- TWAIT_FNAME);
- TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
-}
-
-/// ----------------------------------------------------------------------------
-
static void
user_va0_disable(int operation)
{
@@ -1135,397 +510,6 @@ ATF_TC_BODY(core_dump_procinfo, tc)
/// ----------------------------------------------------------------------------
-#if defined(TWAIT_HAVE_STATUS)
-
-#define THREAD_CONCURRENT_BREAKPOINT_NUM 50
-#define THREAD_CONCURRENT_SIGNALS_NUM 50
-#define THREAD_CONCURRENT_WATCHPOINT_NUM 50
-
-/* List of signals to use for the test */
-const int thread_concurrent_signals_list[] = {
- SIGIO,
- SIGXCPU,
- SIGXFSZ,
- SIGVTALRM,
- SIGPROF,
- SIGWINCH,
- SIGINFO,
- SIGUSR1,
- SIGUSR2
-};
-
-enum thread_concurrent_signal_handling {
- /* the signal is discarded by debugger */
- TCSH_DISCARD,
- /* the handler is set to SIG_IGN */
- TCSH_SIG_IGN,
- /* an actual handler is used */
- TCSH_HANDLER
-};
-
-static pthread_barrier_t thread_concurrent_barrier;
-static pthread_key_t thread_concurrent_key;
-static uint32_t thread_concurrent_watchpoint_var = 0;
-
-static void *
-thread_concurrent_breakpoint_thread(void *arg)
-{
- static volatile int watchme = 1;
- pthread_barrier_wait(&thread_concurrent_barrier);
- DPRINTF("Before entering breakpoint func from LWP %d\n", _lwp_self());
- check_happy(watchme);
- return NULL;
-}
-
-static void
-thread_concurrent_sig_handler(int sig)
-{
- void *tls_val = pthread_getspecific(thread_concurrent_key);
- DPRINTF("Before increment, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
- FORKEE_ASSERT(pthread_setspecific(thread_concurrent_key,
- (void*)((uintptr_t)tls_val + 1)) == 0);
-}
-
-static void *
-thread_concurrent_signals_thread(void *arg)
-{
- int sigval = thread_concurrent_signals_list[
- _lwp_self() % __arraycount(thread_concurrent_signals_list)];
- enum thread_concurrent_signal_handling *signal_handle = arg;
- void *tls_val;
-
- pthread_barrier_wait(&thread_concurrent_barrier);
- DPRINTF("Before raising %s from LWP %d\n", strsignal(sigval),
- _lwp_self());
- pthread_kill(pthread_self(), sigval);
- if (*signal_handle == TCSH_HANDLER) {
- tls_val = pthread_getspecific(thread_concurrent_key);
- DPRINTF("After raising, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
- FORKEE_ASSERT(tls_val == (void*)1);
- }
- return NULL;
-}
-
-static void *
-thread_concurrent_watchpoint_thread(void *arg)
-{
- pthread_barrier_wait(&thread_concurrent_barrier);
- DPRINTF("Before modifying var from LWP %d\n", _lwp_self());
- thread_concurrent_watchpoint_var = 1;
- return NULL;
-}
-
-#if defined(__i386__) || defined(__x86_64__)
-enum thread_concurrent_sigtrap_event {
- TCSE_UNKNOWN,
- TCSE_BREAKPOINT,
- TCSE_WATCHPOINT
-};
-
-static void
-thread_concurrent_lwp_setup(pid_t child, lwpid_t lwpid);
-static enum thread_concurrent_sigtrap_event
-thread_concurrent_handle_sigtrap(pid_t child, ptrace_siginfo_t *info);
-#endif
-
-static void
-thread_concurrent_test(enum thread_concurrent_signal_handling signal_handle,
- int breakpoint_threads, int signal_threads, int watchpoint_threads)
-{
- const int exitval = 5;
- const int sigval = SIGSTOP;
- pid_t child, wpid;
- int status;
- struct lwp_event_count signal_counts[THREAD_CONCURRENT_SIGNALS_NUM]
- = {{0, 0}};
- struct lwp_event_count bp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
- = {{0, 0}};
- struct lwp_event_count wp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
- = {{0, 0}};
- ptrace_event_t event;
- int i;
-
-#if defined(HAVE_DBREGS)
- if (!can_we_set_dbregs()) {
- atf_tc_skip("Either run this test as root or set sysctl(3) "
- "security.models.extensions.user_set_dbregs to 1");
- }
-#endif
-
- atf_tc_skip("PR kern/54960");
-
- /* Protect against out-of-bounds array access. */
- ATF_REQUIRE(breakpoint_threads <= THREAD_CONCURRENT_BREAKPOINT_NUM);
- ATF_REQUIRE(signal_threads <= THREAD_CONCURRENT_SIGNALS_NUM);
- ATF_REQUIRE(watchpoint_threads <= THREAD_CONCURRENT_WATCHPOINT_NUM);
-
- DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
- if (child == 0) {
- pthread_t bp_threads[THREAD_CONCURRENT_BREAKPOINT_NUM];
- pthread_t sig_threads[THREAD_CONCURRENT_SIGNALS_NUM];
- pthread_t wp_threads[THREAD_CONCURRENT_WATCHPOINT_NUM];
-
- DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
- FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
-
- DPRINTF("Before raising %s from child\n", strsignal(sigval));
- FORKEE_ASSERT(raise(sigval) == 0);
-
- if (signal_handle != TCSH_DISCARD) {
- struct sigaction sa;
- unsigned int j;
-
- memset(&sa, 0, sizeof(sa));
- if (signal_handle == TCSH_SIG_IGN)
- sa.sa_handler = SIG_IGN;
- else
- sa.sa_handler = thread_concurrent_sig_handler;
- sigemptyset(&sa.sa_mask);
-
- for (j = 0;
- j < __arraycount(thread_concurrent_signals_list);
- j++)
- FORKEE_ASSERT(sigaction(
- thread_concurrent_signals_list[j], &sa, NULL)
- != -1);
- }
-
- DPRINTF("Before starting threads from the child\n");
- FORKEE_ASSERT(pthread_barrier_init(
- &thread_concurrent_barrier, NULL,
- breakpoint_threads + signal_threads + watchpoint_threads)
- == 0);
- FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL)
- == 0);
-
- for (i = 0; i < signal_threads; i++) {
- FORKEE_ASSERT(pthread_create(&sig_threads[i], NULL,
- thread_concurrent_signals_thread,
- &signal_handle) == 0);
- }
- for (i = 0; i < breakpoint_threads; i++) {
- FORKEE_ASSERT(pthread_create(&bp_threads[i], NULL,
- thread_concurrent_breakpoint_thread, NULL) == 0);
- }
- for (i = 0; i < watchpoint_threads; i++) {
- FORKEE_ASSERT(pthread_create(&wp_threads[i], NULL,
- thread_concurrent_watchpoint_thread, NULL) == 0);
- }
-
- DPRINTF("Before joining threads from the child\n");
- for (i = 0; i < watchpoint_threads; i++) {
- FORKEE_ASSERT(pthread_join(wp_threads[i], NULL) == 0);
- }
- for (i = 0; i < breakpoint_threads; i++) {
- FORKEE_ASSERT(pthread_join(bp_threads[i], NULL) == 0);
- }
- for (i = 0; i < signal_threads; i++) {
- FORKEE_ASSERT(pthread_join(sig_threads[i], NULL) == 0);
- }
-
- FORKEE_ASSERT(pthread_key_delete(thread_concurrent_key) == 0);
- FORKEE_ASSERT(pthread_barrier_destroy(
- &thread_concurrent_barrier) == 0);
-
- DPRINTF("Before exiting of the child process\n");
- _exit(exitval);
- }
- DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
-
- DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
-
- validate_status_stopped(status, sigval);
-
- DPRINTF("Set LWP event mask for the child process\n");
- memset(&event, 0, sizeof(event));
- event.pe_set_event |= PTRACE_LWP_CREATE;
- SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, sizeof(event))
- != -1);
-
- DPRINTF("Before resuming the child process where it left off\n");
- SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
-
- DPRINTF("Before entering signal collection loop\n");
- while (1) {
- ptrace_siginfo_t info;
-
- DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
- TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
- child);
- if (WIFEXITED(status))
- break;
- /* Note: we use validate_status_stopped() to get nice error
- * message. Signal is irrelevant since it won't be reached.
- */
- else if (!WIFSTOPPED(status))
- validate_status_stopped(status, 0);
-
- DPRINTF("Before calling PT_GET_SIGINFO\n");
- SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
- sizeof(info)) != -1);
-
- DPRINTF("Received signal %d from LWP %d (wait: %d)\n",
- info.psi_siginfo.si_signo, info.psi_lwpid,
- WSTOPSIG(status));
-
- ATF_CHECK_EQ_MSG(info.psi_siginfo.si_signo, WSTOPSIG(status),
- "lwp=%d, WSTOPSIG=%d, psi_siginfo=%d", info.psi_lwpid,
- WSTOPSIG(status), info.psi_siginfo.si_signo);
-
- if (WSTOPSIG(status) != SIGTRAP) {
- int expected_sig =
- thread_concurrent_signals_list[info.psi_lwpid %
- __arraycount(thread_concurrent_signals_list)];
- ATF_CHECK_EQ_MSG(WSTOPSIG(status), expected_sig,
- "lwp=%d, expected %d, got %d", info.psi_lwpid,
- expected_sig, WSTOPSIG(status));
-
- *FIND_EVENT_COUNT(signal_counts, info.psi_lwpid) += 1;
- } else if (info.psi_siginfo.si_code == TRAP_LWP) {
-#if defined(__i386__) || defined(__x86_64__)
- thread_concurrent_lwp_setup(child, info.psi_lwpid);
-#endif
- } else {
-#if defined(__i386__) || defined(__x86_64__)
- switch (thread_concurrent_handle_sigtrap(child, &info)) {
- case TCSE_UNKNOWN:
- /* already reported inside the function */
- break;
- case TCSE_BREAKPOINT:
- *FIND_EVENT_COUNT(bp_counts,
- info.psi_lwpid) += 1;
- break;
- case TCSE_WATCHPOINT:
- *FIND_EVENT_COUNT(wp_counts,
- info.psi_lwpid) += 1;
- break;
- }
-#else
- ATF_CHECK_MSG(0, "Unexpected SIGTRAP, si_code=%d\n",
- info.psi_siginfo.si_code);
-#endif
- }
-
- DPRINTF("Before resuming the child process\n");
- SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
- signal_handle != TCSH_DISCARD && WSTOPSIG(status) != SIGTRAP
- ? WSTOPSIG(status) : 0) != -1);
- }
-
- for (i = 0; i < signal_threads; i++)
- ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 1,
- "signal_counts[%d].lec_count=%d; lec_lwp=%d",
- i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
- for (i = signal_threads; i < THREAD_CONCURRENT_SIGNALS_NUM; i++)
- ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 0,
- "extraneous signal_counts[%d].lec_count=%d; lec_lwp=%d",
- i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
-
- for (i = 0; i < breakpoint_threads; i++)
- ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 1,
- "bp_counts[%d].lec_count=%d; lec_lwp=%d",
- i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
- for (i = breakpoint_threads; i < THREAD_CONCURRENT_BREAKPOINT_NUM; i++)
- ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 0,
- "extraneous bp_counts[%d].lec_count=%d; lec_lwp=%d",
- i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
-
- for (i = 0; i < watchpoint_threads; i++)
- ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 1,
- "wp_counts[%d].lec_count=%d; lec_lwp=%d",
- i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
- for (i = watchpoint_threads; i < THREAD_CONCURRENT_WATCHPOINT_NUM; i++)
- ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 0,
- "extraneous wp_counts[%d].lec_count=%d; lec_lwp=%d",
- i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
-
- validate_status_exited(status, exitval);
-}
-
-#define THREAD_CONCURRENT_TEST(test, sig_hdl, bps, sigs, wps, descr) \
-ATF_TC(test); \
-ATF_TC_HEAD(test, tc) \
-{ \
- atf_tc_set_md_var(tc, "descr", descr); \
-} \
- \
-ATF_TC_BODY(test, tc) \
-{ \
- thread_concurrent_test(sig_hdl, bps, sigs, wps); \
-}
-
-THREAD_CONCURRENT_TEST(thread_concurrent_signals, TCSH_DISCARD,
- 0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
- "Verify that concurrent signals issued to a single thread are reported "
- "correctly");
-THREAD_CONCURRENT_TEST(thread_concurrent_signals_sig_ign, TCSH_SIG_IGN,
- 0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
- "Verify that concurrent signals issued to a single thread are reported "
- "correctly and passed back to SIG_IGN handler");
-THREAD_CONCURRENT_TEST(thread_concurrent_signals_handler, TCSH_HANDLER,
- 0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
- "Verify that concurrent signals issued to a single thread are reported "
- "correctly and passed back to a handler function");
-
-#if defined(__i386__) || defined(__x86_64__)
-THREAD_CONCURRENT_TEST(thread_concurrent_breakpoints, TCSH_DISCARD,
- THREAD_CONCURRENT_BREAKPOINT_NUM, 0, 0,
- "Verify that concurrent breakpoints are reported correctly");
-THREAD_CONCURRENT_TEST(thread_concurrent_watchpoints, TCSH_DISCARD,
- 0, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
- "Verify that concurrent breakpoints are reported correctly");
-THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp, TCSH_DISCARD,
- THREAD_CONCURRENT_BREAKPOINT_NUM, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
- "Verify that concurrent breakpoints and watchpoints are reported "
- "correctly");
-
-THREAD_CONCURRENT_TEST(thread_concurrent_bp_sig, TCSH_DISCARD,
- THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
- "Verify that concurrent breakpoints and signals are reported correctly");
-THREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_sig_ign, TCSH_SIG_IGN,
- THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
- "Verify that concurrent breakpoints and signals are reported correctly "
- "and passed back to SIG_IGN handler");
-THREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_handler, TCSH_HANDLER,
- THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
- "Verify that concurrent breakpoints and signals are reported correctly "
- "and passed back to a handler function");
-
-THREAD_CONCURRENT_TEST(thread_concurrent_wp_sig, TCSH_DISCARD,
- 0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
- "Verify that concurrent watchpoints and signals are reported correctly");
-THREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_sig_ign, TCSH_SIG_IGN,
- 0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
- "Verify that concurrent watchpoints and signals are reported correctly "
- "and passed back to SIG_IGN handler");
-THREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_handler, TCSH_HANDLER,
- 0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
- "Verify that concurrent watchpoints and signals are reported correctly "
- "and passed back to a handler function");
-
-THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig, TCSH_DISCARD,
- THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
- THREAD_CONCURRENT_WATCHPOINT_NUM,
- "Verify that concurrent breakpoints, watchpoints and signals are reported "
- "correctly");
-THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_sig_ign, TCSH_SIG_IGN,
- THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
- THREAD_CONCURRENT_WATCHPOINT_NUM,
- "Verify that concurrent breakpoints, watchpoints and signals are reported "
- "correctly and passed back to SIG_IGN handler");
-THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_handler, TCSH_HANDLER,
- THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
- THREAD_CONCURRENT_WATCHPOINT_NUM,
- "Verify that concurrent breakpoints, watchpoints and signals are reported "
- "correctly and passed back to a handler function");
-#endif
-
-#endif /*defined(TWAIT_HAVE_STATUS)*/
-
-/// ----------------------------------------------------------------------------
-
#include "t_ptrace_register_wait.h"
#include "t_ptrace_syscall_wait.h"
#include "t_ptrace_step_wait.h"
@@ -1538,6 +522,7 @@ THREAD_CONCURRENT_TEST(thread_concurrent
#include "t_ptrace_lwp_wait.h"
#include "t_ptrace_exec_wait.h"
#include "t_ptrace_topology_wait.h"
+#include "t_ptrace_threads_wait.h"
/// ----------------------------------------------------------------------------
@@ -1571,47 +556,12 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, siginfo_set_unmodified);
ATF_TP_ADD_TC(tp, siginfo_set_faked);
- ATF_TP_ADD_TC(tp, trace_thread_nolwpevents);
- ATF_TP_ADD_TC(tp, trace_thread_lwpexit);
- ATF_TP_ADD_TC(tp, trace_thread_lwpcreate);
- ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit);
-
- ATF_TP_ADD_TC(tp, trace_thread_lwpexit_masked_sigtrap);
- ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_masked_sigtrap);
- ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit_masked_sigtrap);
-
- ATF_TP_ADD_TC(tp, threads_and_exec);
-
- ATF_TP_ADD_TC(tp, suspend_no_deadlock);
-
- ATF_TP_ADD_TC(tp, resume);
-
ATF_TP_ADD_TC(tp, user_va0_disable_pt_continue);
ATF_TP_ADD_TC(tp, user_va0_disable_pt_syscall);
ATF_TP_ADD_TC(tp, user_va0_disable_pt_detach);
ATF_TP_ADD_TC(tp, core_dump_procinfo);
-#if defined(TWAIT_HAVE_STATUS)
- ATF_TP_ADD_TC(tp, thread_concurrent_signals);
- ATF_TP_ADD_TC(tp, thread_concurrent_signals_sig_ign);
- ATF_TP_ADD_TC(tp, thread_concurrent_signals_handler);
-#if defined(__i386__) || defined(__x86_64__)
- ATF_TP_ADD_TC(tp, thread_concurrent_breakpoints);
- ATF_TP_ADD_TC(tp, thread_concurrent_watchpoints);
- ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp);
- ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig);
- ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_sig_ign);
- ATF_TP_ADD_TC(tp, thread_concurrent_bp_sig_handler);
- ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig);
- ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_sig_ign);
- ATF_TP_ADD_TC(tp, thread_concurrent_wp_sig_handler);
- ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig);
- ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_sig_ign);
- ATF_TP_ADD_TC(tp, thread_concurrent_bp_wp_sig_handler);
-#endif
-#endif
-
ATF_TP_ADD_TCS_PTRACE_WAIT_REGISTER();
ATF_TP_ADD_TCS_PTRACE_WAIT_SYSCALL();
ATF_TP_ADD_TCS_PTRACE_WAIT_STEP();
@@ -1624,6 +574,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TCS_PTRACE_WAIT_LWP();
ATF_TP_ADD_TCS_PTRACE_WAIT_EXEC();
ATF_TP_ADD_TCS_PTRACE_WAIT_TOPOLOGY();
+ ATF_TP_ADD_TCS_PTRACE_WAIT_THREADS();
ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
ATF_TP_ADD_TCS_PTRACE_WAIT_I386();
Index: src/tests/lib/libc/sys/t_ptrace_wait.h
diff -u src/tests/lib/libc/sys/t_ptrace_wait.h:1.27 src/tests/lib/libc/sys/t_ptrace_wait.h:1.28
--- src/tests/lib/libc/sys/t_ptrace_wait.h:1.27 Sun Mar 8 15:07:44 2020
+++ src/tests/lib/libc/sys/t_ptrace_wait.h Tue May 5 00:50:39 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_wait.h,v 1.27 2020/03/08 15:07:44 martin Exp $ */
+/* $NetBSD: t_ptrace_wait.h,v 1.28 2020/05/05 00:50:39 kamil Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc.
@@ -744,6 +744,18 @@ find_event_count(struct lwp_event_count
#define ATF_TP_ADD_TC_HAVE_PID(a,b)
#endif
+#if defined(TWAIT_HAVE_STATUS)
+#define ATF_TP_ADD_TC_HAVE_STATUS(a,b) ATF_TP_ADD_TC(a,b)
+#else
+#define ATF_TP_ADD_TC_HAVE_STATUS(a,b)
+#endif
+
+#if defined(TWAIT_HAVE_STATUS) && (defined(__i386__) || defined(__x86_64__))
+#define ATF_TP_ADD_TC_HAVE_STATUS_X86(a,b) ATF_TP_ADD_TC(a,b)
+#else
+#define ATF_TP_ADD_TC_HAVE_STATUS_X86(a,b)
+#endif
+
#if defined(HAVE_GPREGS)
#define ATF_TP_ADD_TC_HAVE_GPREGS(a,b) ATF_TP_ADD_TC(a,b)
#else
Added files:
Index: src/tests/lib/libc/sys/t_ptrace_threads_wait.h
diff -u /dev/null src/tests/lib/libc/sys/t_ptrace_threads_wait.h:1.1
--- /dev/null Tue May 5 00:50:39 2020
+++ src/tests/lib/libc/sys/t_ptrace_threads_wait.h Tue May 5 00:50:39 2020
@@ -0,0 +1,1069 @@
+/* $NetBSD: t_ptrace_threads_wait.h,v 1.1 2020/05/05 00:50:39 kamil Exp $ */
+
+/*-
+ * Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#define TRACE_THREADS_NUM 100
+
+static volatile int done;
+pthread_mutex_t trace_threads_mtx = PTHREAD_MUTEX_INITIALIZER;
+
+static void *
+trace_threads_cb(void *arg __unused)
+{
+
+ pthread_mutex_lock(&trace_threads_mtx);
+ done++;
+ pthread_mutex_unlock(&trace_threads_mtx);
+
+ while (done < TRACE_THREADS_NUM)
+ sched_yield();
+
+ return NULL;
+}
+
+static void
+trace_threads(bool trace_create, bool trace_exit, bool masked)
+{
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ ptrace_state_t state;
+ const int slen = sizeof(state);
+ ptrace_event_t event;
+ const int elen = sizeof(event);
+ struct ptrace_siginfo info;
+
+ sigset_t intmask;
+
+ pthread_t t[TRACE_THREADS_NUM];
+ int rv;
+ size_t n;
+ lwpid_t lid;
+
+ /* Track created and exited threads */
+ struct lwp_event_count traced_lwps[__arraycount(t)] = {{0, 0}};
+
+ DPRINTF("Before forking process PID=%d\n", getpid());
+ SYSCALL_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ if (masked) {
+ sigemptyset(&intmask);
+ sigaddset(&intmask, SIGTRAP);
+ sigprocmask(SIG_BLOCK, &intmask, NULL);
+ }
+
+ DPRINTF("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ for (n = 0; n < __arraycount(t); n++) {
+ rv = pthread_create(&t[n], NULL, trace_threads_cb,
+ NULL);
+ FORKEE_ASSERT(rv == 0);
+ }
+
+ for (n = 0; n < __arraycount(t); n++) {
+ rv = pthread_join(t[n], NULL);
+ FORKEE_ASSERT(rv == 0);
+ }
+
+ /*
+ * There is race between _exit() and pthread_join() detaching
+ * a thread. For simplicity kill the process after detecting
+ * LWP events.
+ */
+ while (true)
+ continue;
+
+ FORKEE_ASSERT(0 && "Not reached");
+ }
+ DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+ SYSCALL_REQUIRE(
+ ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
+ DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
+ info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+ info.psi_siginfo.si_errno);
+
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+
+ DPRINTF("Set LWP event mask for the child %d\n", child);
+ memset(&event, 0, sizeof(event));
+ if (trace_create)
+ event.pe_set_event |= PTRACE_LWP_CREATE;
+ if (trace_exit)
+ event.pe_set_event |= PTRACE_LWP_EXIT;
+ SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
+
+ DPRINTF("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ for (n = 0; n < (trace_create ? __arraycount(t) : 0); n++) {
+ DPRINTF("Before calling %s() for the child - expected stopped "
+ "SIGTRAP\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+ child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
+ "child\n");
+ SYSCALL_REQUIRE(
+ ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
+ DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
+ "si_errno=%#x\n",
+ info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+ info.psi_siginfo.si_errno);
+
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
+
+ SYSCALL_REQUIRE(
+ ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
+
+ ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
+ "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
+
+ lid = state.pe_lwp;
+ DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
+
+ *FIND_EVENT_COUNT(traced_lwps, lid) += 1;
+
+ DPRINTF("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+ }
+
+ for (n = 0; n < (trace_exit ? __arraycount(t) : 0); n++) {
+ DPRINTF("Before calling %s() for the child - expected stopped "
+ "SIGTRAP\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+ child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
+ "child\n");
+ SYSCALL_REQUIRE(
+ ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
+ DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
+ "si_errno=%#x\n",
+ info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+ info.psi_siginfo.si_errno);
+
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
+
+ SYSCALL_REQUIRE(
+ ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
+
+ ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
+ "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
+
+ lid = state.pe_lwp;
+ DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
+
+ if (trace_create) {
+ int *count = FIND_EVENT_COUNT(traced_lwps, lid);
+ ATF_REQUIRE_EQ(*count, 1);
+ *count = 0;
+ }
+
+ DPRINTF("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+ }
+
+ kill(child, SIGKILL);
+
+ DPRINTF("Before calling %s() for the child - expected exited\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_signaled(status, SIGKILL, 0);
+
+ DPRINTF("Before calling %s() for the child - expected no process\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+#define TRACE_THREADS(test, trace_create, trace_exit, mask) \
+ATF_TC(test); \
+ATF_TC_HEAD(test, tc) \
+{ \
+ atf_tc_set_md_var(tc, "descr", \
+ "Verify spawning threads with%s tracing LWP create and" \
+ "with%s tracing LWP exit", trace_create ? "" : "out", \
+ trace_exit ? "" : "out"); \
+} \
+ \
+ATF_TC_BODY(test, tc) \
+{ \
+ \
+ trace_threads(trace_create, trace_exit, mask); \
+}
+
+TRACE_THREADS(trace_thread_nolwpevents, false, false, false)
+TRACE_THREADS(trace_thread_lwpexit, false, true, false)
+TRACE_THREADS(trace_thread_lwpcreate, true, false, false)
+TRACE_THREADS(trace_thread_lwpcreate_and_exit, true, true, false)
+
+TRACE_THREADS(trace_thread_lwpexit_masked_sigtrap, false, true, true)
+TRACE_THREADS(trace_thread_lwpcreate_masked_sigtrap, true, false, true)
+TRACE_THREADS(trace_thread_lwpcreate_and_exit_masked_sigtrap, true, true, true)
+
+/// ----------------------------------------------------------------------------
+
+static void *
+thread_and_exec_thread_cb(void *arg __unused)
+{
+
+ execlp("/bin/echo", "/bin/echo", NULL);
+
+ abort();
+}
+
+static void
+threads_and_exec(void)
+{
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ ptrace_state_t state;
+ const int slen = sizeof(state);
+ ptrace_event_t event;
+ const int elen = sizeof(event);
+ struct ptrace_siginfo info;
+
+ pthread_t t;
+ lwpid_t lid;
+
+ DPRINTF("Before forking process PID=%d\n", getpid());
+ SYSCALL_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ DPRINTF("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ FORKEE_ASSERT(pthread_create(&t, NULL,
+ thread_and_exec_thread_cb, NULL) == 0);
+
+ for (;;)
+ continue;
+
+ FORKEE_ASSERT(0 && "Not reached");
+ }
+ DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n");
+ SYSCALL_REQUIRE(
+ ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
+ DPRINTF("Signal properties: si_signo=%#x si_code=%#x si_errno=%#x\n",
+ info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+ info.psi_siginfo.si_errno);
+
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+
+ DPRINTF("Set LWP event mask for the child %d\n", child);
+ memset(&event, 0, sizeof(event));
+ event.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT;
+ SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, elen) != -1);
+
+ DPRINTF("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ DPRINTF("Before calling %s() for the child - expected stopped "
+ "SIGTRAP\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+ child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
+ "child\n");
+ SYSCALL_REQUIRE(
+ ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
+ DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
+ "si_errno=%#x\n",
+ info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+ info.psi_siginfo.si_errno);
+
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
+
+ SYSCALL_REQUIRE(
+ ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
+
+ ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_CREATE,
+ "%d != %d", state.pe_report_event, PTRACE_LWP_CREATE);
+
+ lid = state.pe_lwp;
+ DPRINTF("Reported PTRACE_LWP_CREATE event with lid %d\n", lid);
+
+ DPRINTF("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ DPRINTF("Before calling %s() for the child - expected stopped "
+ "SIGTRAP\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+ child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
+ "child\n");
+ SYSCALL_REQUIRE(
+ ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
+ DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
+ "si_errno=%#x\n",
+ info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+ info.psi_siginfo.si_errno);
+
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_LWP);
+
+ SYSCALL_REQUIRE(
+ ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
+
+ ATF_REQUIRE_EQ_MSG(state.pe_report_event, PTRACE_LWP_EXIT,
+ "%d != %d", state.pe_report_event, PTRACE_LWP_EXIT);
+
+ lid = state.pe_lwp;
+ DPRINTF("Reported PTRACE_LWP_EXIT event with lid %d\n", lid);
+
+ DPRINTF("Before resuming the child process where it left off "
+ "and without signal to be sent\n");
+ SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ DPRINTF("Before calling %s() for the child - expected stopped "
+ "SIGTRAP\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+ child);
+
+ validate_status_stopped(status, SIGTRAP);
+
+ DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for "
+ "child\n");
+ SYSCALL_REQUIRE(
+ ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1);
+
+ DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid);
+ DPRINTF("Signal properties: si_signo=%#x si_code=%#x "
+ "si_errno=%#x\n",
+ info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
+ info.psi_siginfo.si_errno);
+
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP);
+ ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_EXEC);
+
+ SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1);
+
+ DPRINTF("Before calling %s() for the child - expected exited\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_signaled(status, SIGKILL, 0);
+
+ DPRINTF("Before calling %s() for the child - expected no process\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+ATF_TC(threads_and_exec);
+ATF_TC_HEAD(threads_and_exec, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that multithreaded application on exec() will report "
+ "LWP_EXIT events");
+}
+
+ATF_TC_BODY(threads_and_exec, tc)
+{
+
+ threads_and_exec();
+}
+
+/// ----------------------------------------------------------------------------
+
+ATF_TC(suspend_no_deadlock);
+ATF_TC_HEAD(suspend_no_deadlock, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that the while the only thread within a process is "
+ "suspended, the whole process cannot be unstopped");
+}
+
+ATF_TC_BODY(suspend_no_deadlock, tc)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ struct ptrace_siginfo psi;
+
+ DPRINTF("Before forking process PID=%d\n", getpid());
+ SYSCALL_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ DPRINTF("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ DPRINTF("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ DPRINTF("Before reading siginfo and lwpid_t\n");
+ SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
+
+ DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
+ SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
+
+ DPRINTF("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ ATF_REQUIRE_ERRNO(EDEADLK,
+ ptrace(PT_CONTINUE, child, (void *)1, 0) == -1);
+
+ DPRINTF("Before resuming LWP %d\n", psi.psi_lwpid);
+ SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, psi.psi_lwpid) != -1);
+
+ DPRINTF("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ DPRINTF("Before calling %s() for the child - expected exited\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_exited(status, exitval);
+
+ DPRINTF("Before calling %s() for the child - expected no process\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+/// ----------------------------------------------------------------------------
+
+static pthread_barrier_t barrier1_resume;
+static pthread_barrier_t barrier2_resume;
+
+static void *
+resume_thread(void *arg)
+{
+
+ raise(SIGUSR1);
+
+ pthread_barrier_wait(&barrier1_resume);
+
+ /* Debugger will suspend the process here */
+
+ pthread_barrier_wait(&barrier2_resume);
+
+ raise(SIGUSR2);
+
+ return infinite_thread(arg);
+}
+
+ATF_TC(resume);
+ATF_TC_HEAD(resume, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify that a thread can be suspended by a debugger and later "
+ "resumed by the debugger");
+}
+
+ATF_TC_BODY(resume, tc)
+{
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+ int status;
+#endif
+ lwpid_t lid;
+ struct ptrace_siginfo psi;
+ pthread_t t;
+
+ DPRINTF("Before forking process PID=%d\n", getpid());
+ SYSCALL_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ pthread_barrier_init(&barrier1_resume, NULL, 2);
+ pthread_barrier_init(&barrier2_resume, NULL, 2);
+
+ DPRINTF("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ DPRINTF("Before creating new thread in child\n");
+ FORKEE_ASSERT(pthread_create(&t, NULL, resume_thread, NULL) == 0);
+
+ pthread_barrier_wait(&barrier1_resume);
+
+ pthread_barrier_wait(&barrier2_resume);
+
+ infinite_thread(NULL);
+ }
+ DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ DPRINTF("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ DPRINTF("Before calling %s() for the child - expected stopped "
+ "SIGUSR1\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGUSR1);
+
+ DPRINTF("Before reading siginfo and lwpid_t\n");
+ SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &psi, sizeof(psi)) != -1);
+
+ DPRINTF("Before suspending LWP %d\n", psi.psi_lwpid);
+ SYSCALL_REQUIRE(ptrace(PT_SUSPEND, child, NULL, psi.psi_lwpid) != -1);
+
+ lid = psi.psi_lwpid;
+
+ DPRINTF("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ DPRINTF("Before suspending the parent for 1 second, we expect no signals\n");
+ SYSCALL_REQUIRE(sleep(1) == 0);
+
+#if defined(TWAIT_HAVE_OPTIONS)
+ DPRINTF("Before calling %s() for the child - expected no status\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, WNOHANG), 0);
+#endif
+
+ DPRINTF("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ SYSCALL_REQUIRE(ptrace(PT_STOP, child, NULL, 0) != -1);
+
+ DPRINTF("Before calling %s() for the child - expected stopped "
+ "SIGSTOP\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGSTOP);
+
+ DPRINTF("Before resuming LWP %d\n", lid);
+ SYSCALL_REQUIRE(ptrace(PT_RESUME, child, NULL, lid) != -1);
+
+ DPRINTF("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ DPRINTF("Before calling %s() for the child - expected stopped "
+ "SIGUSR2\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, SIGUSR2);
+
+ DPRINTF("Before resuming the child process where it left off and "
+ "without signal to be sent\n");
+ SYSCALL_REQUIRE(ptrace(PT_KILL, child, (void *)1, 0) != -1);
+
+ DPRINTF("Before calling %s() for the child - expected exited\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_signaled(status, SIGKILL, 0);
+
+ DPRINTF("Before calling %s() for the child - expected no process\n",
+ TWAIT_FNAME);
+ TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+
+/// ----------------------------------------------------------------------------
+
+#if defined(TWAIT_HAVE_STATUS)
+
+#define THREAD_CONCURRENT_BREAKPOINT_NUM 50
+#define THREAD_CONCURRENT_SIGNALS_NUM 50
+#define THREAD_CONCURRENT_WATCHPOINT_NUM 50
+
+/* List of signals to use for the test */
+const int thread_concurrent_signals_list[] = {
+ SIGIO,
+ SIGXCPU,
+ SIGXFSZ,
+ SIGVTALRM,
+ SIGPROF,
+ SIGWINCH,
+ SIGINFO,
+ SIGUSR1,
+ SIGUSR2
+};
+
+enum thread_concurrent_signal_handling {
+ /* the signal is discarded by debugger */
+ TCSH_DISCARD,
+ /* the handler is set to SIG_IGN */
+ TCSH_SIG_IGN,
+ /* an actual handler is used */
+ TCSH_HANDLER
+};
+
+static pthread_barrier_t thread_concurrent_barrier;
+static pthread_key_t thread_concurrent_key;
+static uint32_t thread_concurrent_watchpoint_var = 0;
+
+static void *
+thread_concurrent_breakpoint_thread(void *arg)
+{
+ static volatile int watchme = 1;
+ pthread_barrier_wait(&thread_concurrent_barrier);
+ DPRINTF("Before entering breakpoint func from LWP %d\n", _lwp_self());
+ check_happy(watchme);
+ return NULL;
+}
+
+static void
+thread_concurrent_sig_handler(int sig)
+{
+ void *tls_val = pthread_getspecific(thread_concurrent_key);
+ DPRINTF("Before increment, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
+ FORKEE_ASSERT(pthread_setspecific(thread_concurrent_key,
+ (void*)((uintptr_t)tls_val + 1)) == 0);
+}
+
+static void *
+thread_concurrent_signals_thread(void *arg)
+{
+ int sigval = thread_concurrent_signals_list[
+ _lwp_self() % __arraycount(thread_concurrent_signals_list)];
+ enum thread_concurrent_signal_handling *signal_handle = arg;
+ void *tls_val;
+
+ pthread_barrier_wait(&thread_concurrent_barrier);
+ DPRINTF("Before raising %s from LWP %d\n", strsignal(sigval),
+ _lwp_self());
+ pthread_kill(pthread_self(), sigval);
+ if (*signal_handle == TCSH_HANDLER) {
+ tls_val = pthread_getspecific(thread_concurrent_key);
+ DPRINTF("After raising, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
+ FORKEE_ASSERT(tls_val == (void*)1);
+ }
+ return NULL;
+}
+
+static void *
+thread_concurrent_watchpoint_thread(void *arg)
+{
+ pthread_barrier_wait(&thread_concurrent_barrier);
+ DPRINTF("Before modifying var from LWP %d\n", _lwp_self());
+ thread_concurrent_watchpoint_var = 1;
+ return NULL;
+}
+
+#if defined(__i386__) || defined(__x86_64__)
+enum thread_concurrent_sigtrap_event {
+ TCSE_UNKNOWN,
+ TCSE_BREAKPOINT,
+ TCSE_WATCHPOINT
+};
+
+static void
+thread_concurrent_lwp_setup(pid_t child, lwpid_t lwpid);
+static enum thread_concurrent_sigtrap_event
+thread_concurrent_handle_sigtrap(pid_t child, ptrace_siginfo_t *info);
+#endif
+
+static void
+thread_concurrent_test(enum thread_concurrent_signal_handling signal_handle,
+ int breakpoint_threads, int signal_threads, int watchpoint_threads)
+{
+ const int exitval = 5;
+ const int sigval = SIGSTOP;
+ pid_t child, wpid;
+ int status;
+ struct lwp_event_count signal_counts[THREAD_CONCURRENT_SIGNALS_NUM]
+ = {{0, 0}};
+ struct lwp_event_count bp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
+ = {{0, 0}};
+ struct lwp_event_count wp_counts[THREAD_CONCURRENT_BREAKPOINT_NUM]
+ = {{0, 0}};
+ ptrace_event_t event;
+ int i;
+
+#if defined(HAVE_DBREGS)
+ if (!can_we_set_dbregs()) {
+ atf_tc_skip("Either run this test as root or set sysctl(3) "
+ "security.models.extensions.user_set_dbregs to 1");
+ }
+#endif
+
+ atf_tc_skip("PR kern/54960");
+
+ /* Protect against out-of-bounds array access. */
+ ATF_REQUIRE(breakpoint_threads <= THREAD_CONCURRENT_BREAKPOINT_NUM);
+ ATF_REQUIRE(signal_threads <= THREAD_CONCURRENT_SIGNALS_NUM);
+ ATF_REQUIRE(watchpoint_threads <= THREAD_CONCURRENT_WATCHPOINT_NUM);
+
+ DPRINTF("Before forking process PID=%d\n", getpid());
+ SYSCALL_REQUIRE((child = fork()) != -1);
+ if (child == 0) {
+ pthread_t bp_threads[THREAD_CONCURRENT_BREAKPOINT_NUM];
+ pthread_t sig_threads[THREAD_CONCURRENT_SIGNALS_NUM];
+ pthread_t wp_threads[THREAD_CONCURRENT_WATCHPOINT_NUM];
+
+ DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
+ FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+ DPRINTF("Before raising %s from child\n", strsignal(sigval));
+ FORKEE_ASSERT(raise(sigval) == 0);
+
+ if (signal_handle != TCSH_DISCARD) {
+ struct sigaction sa;
+ unsigned int j;
+
+ memset(&sa, 0, sizeof(sa));
+ if (signal_handle == TCSH_SIG_IGN)
+ sa.sa_handler = SIG_IGN;
+ else
+ sa.sa_handler = thread_concurrent_sig_handler;
+ sigemptyset(&sa.sa_mask);
+
+ for (j = 0;
+ j < __arraycount(thread_concurrent_signals_list);
+ j++)
+ FORKEE_ASSERT(sigaction(
+ thread_concurrent_signals_list[j], &sa, NULL)
+ != -1);
+ }
+
+ DPRINTF("Before starting threads from the child\n");
+ FORKEE_ASSERT(pthread_barrier_init(
+ &thread_concurrent_barrier, NULL,
+ breakpoint_threads + signal_threads + watchpoint_threads)
+ == 0);
+ FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL)
+ == 0);
+
+ for (i = 0; i < signal_threads; i++) {
+ FORKEE_ASSERT(pthread_create(&sig_threads[i], NULL,
+ thread_concurrent_signals_thread,
+ &signal_handle) == 0);
+ }
+ for (i = 0; i < breakpoint_threads; i++) {
+ FORKEE_ASSERT(pthread_create(&bp_threads[i], NULL,
+ thread_concurrent_breakpoint_thread, NULL) == 0);
+ }
+ for (i = 0; i < watchpoint_threads; i++) {
+ FORKEE_ASSERT(pthread_create(&wp_threads[i], NULL,
+ thread_concurrent_watchpoint_thread, NULL) == 0);
+ }
+
+ DPRINTF("Before joining threads from the child\n");
+ for (i = 0; i < watchpoint_threads; i++) {
+ FORKEE_ASSERT(pthread_join(wp_threads[i], NULL) == 0);
+ }
+ for (i = 0; i < breakpoint_threads; i++) {
+ FORKEE_ASSERT(pthread_join(bp_threads[i], NULL) == 0);
+ }
+ for (i = 0; i < signal_threads; i++) {
+ FORKEE_ASSERT(pthread_join(sig_threads[i], NULL) == 0);
+ }
+
+ FORKEE_ASSERT(pthread_key_delete(thread_concurrent_key) == 0);
+ FORKEE_ASSERT(pthread_barrier_destroy(
+ &thread_concurrent_barrier) == 0);
+
+ DPRINTF("Before exiting of the child process\n");
+ _exit(exitval);
+ }
+ DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+ DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+ validate_status_stopped(status, sigval);
+
+ DPRINTF("Set LWP event mask for the child process\n");
+ memset(&event, 0, sizeof(event));
+ event.pe_set_event |= PTRACE_LWP_CREATE;
+ SYSCALL_REQUIRE(ptrace(PT_SET_EVENT_MASK, child, &event, sizeof(event))
+ != -1);
+
+ DPRINTF("Before resuming the child process where it left off\n");
+ SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+ DPRINTF("Before entering signal collection loop\n");
+ while (1) {
+ ptrace_siginfo_t info;
+
+ DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
+ TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0),
+ child);
+ if (WIFEXITED(status))
+ break;
+ /* Note: we use validate_status_stopped() to get nice error
+ * message. Signal is irrelevant since it won't be reached.
+ */
+ else if (!WIFSTOPPED(status))
+ validate_status_stopped(status, 0);
+
+ DPRINTF("Before calling PT_GET_SIGINFO\n");
+ SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info,
+ sizeof(info)) != -1);
+
+ DPRINTF("Received signal %d from LWP %d (wait: %d)\n",
+ info.psi_siginfo.si_signo, info.psi_lwpid,
+ WSTOPSIG(status));
+
+ ATF_CHECK_EQ_MSG(info.psi_siginfo.si_signo, WSTOPSIG(status),
+ "lwp=%d, WSTOPSIG=%d, psi_siginfo=%d", info.psi_lwpid,
+ WSTOPSIG(status), info.psi_siginfo.si_signo);
+
+ if (WSTOPSIG(status) != SIGTRAP) {
+ int expected_sig =
+ thread_concurrent_signals_list[info.psi_lwpid %
+ __arraycount(thread_concurrent_signals_list)];
+ ATF_CHECK_EQ_MSG(WSTOPSIG(status), expected_sig,
+ "lwp=%d, expected %d, got %d", info.psi_lwpid,
+ expected_sig, WSTOPSIG(status));
+
+ *FIND_EVENT_COUNT(signal_counts, info.psi_lwpid) += 1;
+ } else if (info.psi_siginfo.si_code == TRAP_LWP) {
+#if defined(__i386__) || defined(__x86_64__)
+ thread_concurrent_lwp_setup(child, info.psi_lwpid);
+#endif
+ } else {
+#if defined(__i386__) || defined(__x86_64__)
+ switch (thread_concurrent_handle_sigtrap(child, &info)) {
+ case TCSE_UNKNOWN:
+ /* already reported inside the function */
+ break;
+ case TCSE_BREAKPOINT:
+ *FIND_EVENT_COUNT(bp_counts,
+ info.psi_lwpid) += 1;
+ break;
+ case TCSE_WATCHPOINT:
+ *FIND_EVENT_COUNT(wp_counts,
+ info.psi_lwpid) += 1;
+ break;
+ }
+#else
+ ATF_CHECK_MSG(0, "Unexpected SIGTRAP, si_code=%d\n",
+ info.psi_siginfo.si_code);
+#endif
+ }
+
+ DPRINTF("Before resuming the child process\n");
+ SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1,
+ signal_handle != TCSH_DISCARD && WSTOPSIG(status) != SIGTRAP
+ ? WSTOPSIG(status) : 0) != -1);
+ }
+
+ for (i = 0; i < signal_threads; i++)
+ ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 1,
+ "signal_counts[%d].lec_count=%d; lec_lwp=%d",
+ i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
+ for (i = signal_threads; i < THREAD_CONCURRENT_SIGNALS_NUM; i++)
+ ATF_CHECK_EQ_MSG(signal_counts[i].lec_count, 0,
+ "extraneous signal_counts[%d].lec_count=%d; lec_lwp=%d",
+ i, signal_counts[i].lec_count, signal_counts[i].lec_lwp);
+
+ for (i = 0; i < breakpoint_threads; i++)
+ ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 1,
+ "bp_counts[%d].lec_count=%d; lec_lwp=%d",
+ i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
+ for (i = breakpoint_threads; i < THREAD_CONCURRENT_BREAKPOINT_NUM; i++)
+ ATF_CHECK_EQ_MSG(bp_counts[i].lec_count, 0,
+ "extraneous bp_counts[%d].lec_count=%d; lec_lwp=%d",
+ i, bp_counts[i].lec_count, bp_counts[i].lec_lwp);
+
+ for (i = 0; i < watchpoint_threads; i++)
+ ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 1,
+ "wp_counts[%d].lec_count=%d; lec_lwp=%d",
+ i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
+ for (i = watchpoint_threads; i < THREAD_CONCURRENT_WATCHPOINT_NUM; i++)
+ ATF_CHECK_EQ_MSG(wp_counts[i].lec_count, 0,
+ "extraneous wp_counts[%d].lec_count=%d; lec_lwp=%d",
+ i, wp_counts[i].lec_count, wp_counts[i].lec_lwp);
+
+ validate_status_exited(status, exitval);
+}
+
+#define THREAD_CONCURRENT_TEST(test, sig_hdl, bps, sigs, wps, descr) \
+ATF_TC(test); \
+ATF_TC_HEAD(test, tc) \
+{ \
+ atf_tc_set_md_var(tc, "descr", descr); \
+} \
+ \
+ATF_TC_BODY(test, tc) \
+{ \
+ thread_concurrent_test(sig_hdl, bps, sigs, wps); \
+}
+
+THREAD_CONCURRENT_TEST(thread_concurrent_signals, TCSH_DISCARD,
+ 0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
+ "Verify that concurrent signals issued to a single thread are reported "
+ "correctly");
+THREAD_CONCURRENT_TEST(thread_concurrent_signals_sig_ign, TCSH_SIG_IGN,
+ 0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
+ "Verify that concurrent signals issued to a single thread are reported "
+ "correctly and passed back to SIG_IGN handler");
+THREAD_CONCURRENT_TEST(thread_concurrent_signals_handler, TCSH_HANDLER,
+ 0, THREAD_CONCURRENT_SIGNALS_NUM, 0,
+ "Verify that concurrent signals issued to a single thread are reported "
+ "correctly and passed back to a handler function");
+
+#if defined(__i386__) || defined(__x86_64__)
+THREAD_CONCURRENT_TEST(thread_concurrent_breakpoints, TCSH_DISCARD,
+ THREAD_CONCURRENT_BREAKPOINT_NUM, 0, 0,
+ "Verify that concurrent breakpoints are reported correctly");
+THREAD_CONCURRENT_TEST(thread_concurrent_watchpoints, TCSH_DISCARD,
+ 0, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
+ "Verify that concurrent breakpoints are reported correctly");
+THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp, TCSH_DISCARD,
+ THREAD_CONCURRENT_BREAKPOINT_NUM, 0, THREAD_CONCURRENT_WATCHPOINT_NUM,
+ "Verify that concurrent breakpoints and watchpoints are reported "
+ "correctly");
+
+THREAD_CONCURRENT_TEST(thread_concurrent_bp_sig, TCSH_DISCARD,
+ THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
+ "Verify that concurrent breakpoints and signals are reported correctly");
+THREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_sig_ign, TCSH_SIG_IGN,
+ THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
+ "Verify that concurrent breakpoints and signals are reported correctly "
+ "and passed back to SIG_IGN handler");
+THREAD_CONCURRENT_TEST(thread_concurrent_bp_sig_handler, TCSH_HANDLER,
+ THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM, 0,
+ "Verify that concurrent breakpoints and signals are reported correctly "
+ "and passed back to a handler function");
+
+THREAD_CONCURRENT_TEST(thread_concurrent_wp_sig, TCSH_DISCARD,
+ 0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
+ "Verify that concurrent watchpoints and signals are reported correctly");
+THREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_sig_ign, TCSH_SIG_IGN,
+ 0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
+ "Verify that concurrent watchpoints and signals are reported correctly "
+ "and passed back to SIG_IGN handler");
+THREAD_CONCURRENT_TEST(thread_concurrent_wp_sig_handler, TCSH_HANDLER,
+ 0, THREAD_CONCURRENT_SIGNALS_NUM, THREAD_CONCURRENT_WATCHPOINT_NUM,
+ "Verify that concurrent watchpoints and signals are reported correctly "
+ "and passed back to a handler function");
+
+THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig, TCSH_DISCARD,
+ THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
+ THREAD_CONCURRENT_WATCHPOINT_NUM,
+ "Verify that concurrent breakpoints, watchpoints and signals are reported "
+ "correctly");
+THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_sig_ign, TCSH_SIG_IGN,
+ THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
+ THREAD_CONCURRENT_WATCHPOINT_NUM,
+ "Verify that concurrent breakpoints, watchpoints and signals are reported "
+ "correctly and passed back to SIG_IGN handler");
+THREAD_CONCURRENT_TEST(thread_concurrent_bp_wp_sig_handler, TCSH_HANDLER,
+ THREAD_CONCURRENT_BREAKPOINT_NUM, THREAD_CONCURRENT_SIGNALS_NUM,
+ THREAD_CONCURRENT_WATCHPOINT_NUM,
+ "Verify that concurrent breakpoints, watchpoints and signals are reported "
+ "correctly and passed back to a handler function");
+#endif
+
+#endif /*defined(TWAIT_HAVE_STATUS)*/
+
+#define ATF_TP_ADD_TCS_PTRACE_WAIT_THREADS() \
+ ATF_TP_ADD_TC(tp, trace_thread_nolwpevents); \
+ ATF_TP_ADD_TC(tp, trace_thread_lwpexit); \
+ ATF_TP_ADD_TC(tp, trace_thread_lwpcreate); \
+ ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit); \
+ ATF_TP_ADD_TC(tp, trace_thread_lwpexit_masked_sigtrap); \
+ ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_masked_sigtrap); \
+ ATF_TP_ADD_TC(tp, trace_thread_lwpcreate_and_exit_masked_sigtrap); \
+ ATF_TP_ADD_TC(tp, threads_and_exec); \
+ ATF_TP_ADD_TC(tp, suspend_no_deadlock); \
+ ATF_TP_ADD_TC(tp, resume); \
+ ATF_TP_ADD_TC_HAVE_STATUS(tp, thread_concurrent_signals); \
+ ATF_TP_ADD_TC_HAVE_STATUS(tp, thread_concurrent_signals_sig_ign); \
+ ATF_TP_ADD_TC_HAVE_STATUS(tp, thread_concurrent_signals_handler); \
+ ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_breakpoints); \
+ ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_watchpoints); \
+ ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_bp_wp); \
+ ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_bp_sig); \
+ ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_bp_sig_sig_ign); \
+ ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_bp_sig_handler); \
+ ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_wp_sig); \
+ ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_wp_sig_sig_ign); \
+ ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_wp_sig_handler); \
+ ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_bp_wp_sig); \
+ ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_bp_wp_sig_sig_ign); \
+ ATF_TP_ADD_TC_HAVE_STATUS_X86(tp, thread_concurrent_bp_wp_sig_handler);