Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/tests/lib/libc/sys Extend concurrent events test to breakpoints



details:   https://anonhg.NetBSD.org/src/rev/db1745aee869
branches:  trunk
changeset: 744816:db1745aee869
user:      mgorny <mgorny%NetBSD.org@localhost>
date:      Thu Feb 13 15:27:05 2020 +0000

description:
Extend concurrent events test to breakpoints

Add testing for concurrent breakpoint hits.  The code is currently
x86-specific but since it reuses most of the generic concurrent event
test code, it's put in t_ptrace_wait.c with arch-specific hooks.

diffstat:

 tests/lib/libc/sys/t_ptrace_wait.c     |  89 +++++++++++++++++++++++++++++----
 tests/lib/libc/sys/t_ptrace_x86_wait.h |  78 +++++++++++++++++++++++++++++-
 2 files changed, 154 insertions(+), 13 deletions(-)

diffs (297 lines):

diff -r 8fd4b23b3560 -r db1745aee869 tests/lib/libc/sys/t_ptrace_wait.c
--- a/tests/lib/libc/sys/t_ptrace_wait.c        Thu Feb 13 15:26:45 2020 +0000
+++ b/tests/lib/libc/sys/t_ptrace_wait.c        Thu Feb 13 15:27:05 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: t_ptrace_wait.c,v 1.159 2020/02/13 15:26:45 mgorny Exp $       */
+/*     $NetBSD: t_ptrace_wait.c,v 1.160 2020/02/13 15:27:05 mgorny Exp $       */
 
 /*-
  * Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: t_ptrace_wait.c,v 1.159 2020/02/13 15:26:45 mgorny Exp $");
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.160 2020/02/13 15:27:05 mgorny Exp $");
 
 #define __LEGACY_PT_LWPINFO
 
@@ -8620,6 +8620,7 @@
 
 #if defined(TWAIT_HAVE_STATUS)
 
+#define THREAD_CONCURRENT_BREAKPOINT_NUM 50
 #define THREAD_CONCURRENT_SIGNALS_NUM 50
 
 /* List of signals to use for the test */
@@ -8647,6 +8648,16 @@
 static pthread_barrier_t thread_concurrent_barrier;
 static pthread_key_t thread_concurrent_key;
 
+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)
 {
@@ -8676,9 +8687,21 @@
        return NULL;
 }
 
+#if defined(__i386__) || defined(__x86_64__)
+enum thread_concurrent_sigtrap_event {
+       TCSE_UNKNOWN,
+       TCSE_BREAKPOINT
+};
+
+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 signal_threads)
+    int breakpoint_threads, int signal_threads)
 {
        const int exitval = 5;
        const int sigval = SIGSTOP;
@@ -8686,6 +8709,8 @@
        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}};
        ptrace_event_t event;
        int i;
 
@@ -8695,11 +8720,13 @@
                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);
 
        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];
 
                DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
@@ -8730,7 +8757,7 @@
                DPRINTF("Before starting threads from the child\n");
                FORKEE_ASSERT(pthread_barrier_init(
                    &thread_concurrent_barrier, NULL,
-                   signal_threads) == 0);
+                   breakpoint_threads + signal_threads) == 0);
                FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL)
                    == 0);
 
@@ -8739,8 +8766,15 @@
                            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);
+               }
 
                DPRINTF("Before joining threads from the child\n");
+               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);
                }
@@ -8804,10 +8838,25 @@
                                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 {
-                       ATF_CHECK_EQ_MSG(info.psi_siginfo.si_code, TRAP_LWP,
-                           "lwp=%d, expected TRAP_LWP (%d), got %d",
-                           info.psi_lwpid, TRAP_LWP, info.psi_siginfo.si_code);
+#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;
+                       }
+#else
+                       ATF_CHECK_MSG(0, "Unexpected SIGTRAP, si_code=%d\n",
+                           info.psi_siginfo.si_code);
+#endif
                }
 
                DPRINTF("Before resuming the child process\n");
@@ -8825,10 +8874,19 @@
                    "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);
+
        validate_status_exited(status, exitval);
 }
 
-#define THREAD_CONCURRENT_TEST(test, sig_hdl, sigs, descr)             \
+#define THREAD_CONCURRENT_TEST(test, sig_hdl, bps, sigs, descr)                \
 ATF_TC(test);                                                          \
 ATF_TC_HEAD(test, tc)                                                  \
 {                                                                      \
@@ -8837,22 +8895,26 @@
                                                                        \
 ATF_TC_BODY(test, tc)                                                  \
 {                                                                      \
-       thread_concurrent_test(sig_hdl, sigs);                          \
+       thread_concurrent_test(sig_hdl, bps, sigs);                     \
 }
 
 THREAD_CONCURRENT_TEST(thread_concurrent_signals, TCSH_DISCARD,
-    THREAD_CONCURRENT_SIGNALS_NUM,
+    0, THREAD_CONCURRENT_SIGNALS_NUM,
     "Verify that concurrent signals issued to a single thread are reported "
     "correctly");
 THREAD_CONCURRENT_TEST(thread_concurrent_signals_sig_ign, TCSH_SIG_IGN,
-    THREAD_CONCURRENT_SIGNALS_NUM,
+    0, THREAD_CONCURRENT_SIGNALS_NUM,
     "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,
-    THREAD_CONCURRENT_SIGNALS_NUM,
+    0, THREAD_CONCURRENT_SIGNALS_NUM,
     "Verify that concurrent signals issued to a single thread are reported "
     "correctly and passed back to a handler function");
 
+THREAD_CONCURRENT_TEST(thread_concurrent_breakpoints, TCSH_DISCARD,
+    THREAD_CONCURRENT_BREAKPOINT_NUM, 0,
+    "Verify that concurrent breakpoints are reported correctly");
+
 #endif /*defined(TWAIT_HAVE_STATUS)*/
 
 /// ----------------------------------------------------------------------------
@@ -9445,6 +9507,9 @@
        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);
+#endif
 #endif
 
        ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64();
diff -r 8fd4b23b3560 -r db1745aee869 tests/lib/libc/sys/t_ptrace_x86_wait.h
--- a/tests/lib/libc/sys/t_ptrace_x86_wait.h    Thu Feb 13 15:26:45 2020 +0000
+++ b/tests/lib/libc/sys/t_ptrace_x86_wait.h    Thu Feb 13 15:27:05 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: t_ptrace_x86_wait.h,v 1.19 2020/02/13 02:53:46 christos Exp $  */
+/*     $NetBSD: t_ptrace_x86_wait.h,v 1.20 2020/02/13 15:27:05 mgorny Exp $    */
 
 /*-
  * Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc.
@@ -3551,6 +3551,82 @@
 
 /// ----------------------------------------------------------------------------
 
+#if defined(TWAIT_HAVE_STATUS)
+
+static void
+thread_concurrent_lwp_setup(pid_t child, lwpid_t lwpid)
+{
+       struct dbreg r;
+       union u dr7;
+
+       /* We need to set debug registers for every child */
+       DPRINTF("Call GETDBREGS for LWP %d\n", lwpid);
+       SYSCALL_REQUIRE(ptrace(PT_GETDBREGS, child, &r, lwpid) != -1);
+
+       dr7.raw = 0;
+       /* should be set to 1 according to Intel manual, 17.2 */
+       dr7.bits.reserved_10 = 1;
+       dr7.bits.local_exact_breakpt = 1;
+       dr7.bits.global_exact_breakpt = 1;
+       /* use DR0 for breakpoints */
+       dr7.bits.global_dr0_breakpoint = 1;
+       dr7.bits.condition_dr0 = 0; /* exec */
+       dr7.bits.len_dr0 = 0;
+       r.dr[7] = dr7.raw;
+       r.dr[0] = (long)(intptr_t)check_happy;
+       DPRINTF("dr0=%" PRIxREGISTER "\n", r.dr[0]);
+       DPRINTF("dr7=%" PRIxREGISTER "\n", r.dr[7]);
+
+       DPRINTF("Call SETDBREGS for LWP %d\n", lwpid);
+       SYSCALL_REQUIRE(ptrace(PT_SETDBREGS, child, &r, lwpid) != -1);
+}
+
+static enum thread_concurrent_sigtrap_event
+thread_concurrent_handle_sigtrap(pid_t child, ptrace_siginfo_t *info)
+{
+       enum thread_concurrent_sigtrap_event ret = TCSE_UNKNOWN;
+       struct dbreg r;
+       union u dr7;
+
+       ATF_CHECK_EQ_MSG(info->psi_siginfo.si_code, TRAP_DBREG,
+           "lwp=%d, expected TRAP_DBREG (%d), got %d", info->psi_lwpid,
+           TRAP_DBREG, info->psi_siginfo.si_code);
+
+       DPRINTF("Call GETDBREGS for LWP %d\n", info->psi_lwpid);
+       SYSCALL_REQUIRE(ptrace(PT_GETDBREGS, child, &r, info->psi_lwpid) != -1);
+       DPRINTF("dr6=%" PRIxREGISTER ", dr7=%" PRIxREGISTER "\n",
+           r.dr[6], r.dr[7]);
+
+       ATF_CHECK_MSG(r.dr[6] & 1, "lwp=%d, got DR6=%" PRIxREGISTER,
+           info->psi_lwpid, r.dr[6]);
+
+       if (r.dr[6] & 1) {
+               r.dr[6] &= ~1;
+
+               /* We need to disable the breakpoint to move
+                * past it.
+                *
+                * TODO: single-step and reenable it?
+                */
+               dr7.raw = r.dr[7];
+               dr7.bits.global_dr0_breakpoint = 0;
+               r.dr[7] = dr7.raw;
+
+               ret = TCSE_BREAKPOINT;
+       }
+
+       DPRINTF("Call SETDBREGS for LWP %d\n", info->psi_lwpid);
+       DPRINTF("dr6=%" PRIxREGISTER ", dr7=%" PRIxREGISTER "\n",
+               r.dr[6], r.dr[7]);
+       SYSCALL_REQUIRE(ptrace(PT_SETDBREGS, child, &r, info->psi_lwpid) != -1);
+
+       return ret;
+}
+
+#endif /*defined(TWAIT_HAVE_STATUS)*/
+
+/// ----------------------------------------------------------------------------
+
 #define ATF_TP_ADD_TCS_PTRACE_WAIT_X86() \
        ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_print); \
        ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr0); \



Home | Main Index | Thread Index | Old Index