Source-Changes-HG archive

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

[src/trunk]: src/tests/kernel/arch/amd64 Define new tests for CPU Debug Regis...



details:   https://anonhg.NetBSD.org/src/rev/4d5bb501f2f9
branches:  trunk
changeset: 349267:4d5bb501f2f9
user:      kamil <kamil%NetBSD.org@localhost>
date:      Sat Dec 03 01:41:15 2016 +0000

description:
Define new tests for CPU Debug Registers in t_ptrace_wait{,3,4,6,id,pid}

Rename dbregs1 to dbregs_print
Rename dbregs[2345] to dbregs_preserve_dr[0123]

Add new tests dbregs_preserve_dr[0123]_yield.

dbregs_preserve_dr0_yield:
     Verify that setting DR0 is preserved across ptrace(2) calls with
     scheduler yield

dbregs_preserve_dr1_yield:
     Verify that setting DR1 is preserved across ptrace(2) calls with
     scheduler yield

dbregs_preserve_dr2_yield:
     Verify that setting DR2 is preserved across ptrace(2) calls with
     scheduler yield

dbregs_preserve_dr3_yield:
     Verify that setting DR3 is preserved across ptrace(2) calls with
     scheduler yield

Add new tests dbregs_preserve_dr[0123]_continued.

dbregs_preserve_dr0_continued:
    Verify that setting DR0 is preserved across ptrace(2) calls and with
    continued child

dbregs_preserve_dr1_continued:
    Verify that setting DR1 is preserved across ptrace(2) calls and with
    continued child

dbregs_preserve_dr2_continued:
    Verify that setting DR2 is preserved across ptrace(2) calls and with
    continued child

dbregs_preserve_dr3_continued:
    Verify that setting DR3 is preserved across ptrace(2) calls and with
    continued child

Use more meaningful names for these tests as they are MD specific and
testing precise functionality. Also there will be a growing number of
tests in this category and prefixing everything with plain dbregs and
trailing with a number cannot be verbose.

Sponsored by <The NetBSD Foundation>

diffstat:

 tests/kernel/arch/amd64/t_ptrace_wait.c |  800 +++++++++++++++++++++++++++++++-
 1 files changed, 778 insertions(+), 22 deletions(-)

diffs (truncated from 893 to 300 lines):

diff -r 98d9e4a08db6 -r 4d5bb501f2f9 tests/kernel/arch/amd64/t_ptrace_wait.c
--- a/tests/kernel/arch/amd64/t_ptrace_wait.c   Sat Dec 03 00:40:47 2016 +0000
+++ b/tests/kernel/arch/amd64/t_ptrace_wait.c   Sat Dec 03 01:41:15 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: t_ptrace_wait.c,v 1.2 2016/12/02 06:49:00 kamil Exp $  */
+/*     $NetBSD: t_ptrace_wait.c,v 1.3 2016/12/03 01:41:15 kamil Exp $  */
 
 /*-
  * Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: t_ptrace_wait.c,v 1.2 2016/12/02 06:49:00 kamil Exp $");
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.3 2016/12/03 01:41:15 kamil Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -39,6 +39,7 @@
 #include <machine/reg.h>
 #include <err.h>
 #include <errno.h>
+#include <sched.h>
 #include <signal.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -53,14 +54,14 @@
 #include "../../t_ptrace_wait.h"
 
 #if defined(HAVE_DBREGS)
-ATF_TC(dbregs1);
-ATF_TC_HEAD(dbregs1, tc)
+ATF_TC(dbregs_print);
+ATF_TC_HEAD(dbregs_print, tc)
 {
        atf_tc_set_md_var(tc, "descr",
            "Verify plain PT_GETDBREGS with printing Debug Registers");
 }
 
-ATF_TC_BODY(dbregs1, tc)
+ATF_TC_BODY(dbregs_print, tc)
 {
        const int exitval = 5;
        const int sigval = SIGSTOP;
@@ -112,14 +113,14 @@
 #endif
 
 #if defined(HAVE_DBREGS)
-ATF_TC(dbregs2);
-ATF_TC_HEAD(dbregs2, tc)
+ATF_TC(dbregs_preserve_dr0);
+ATF_TC_HEAD(dbregs_preserve_dr0, tc)
 {
        atf_tc_set_md_var(tc, "descr",
            "Verify that setting DR0 is preserved across ptrace(2) calls");
 }
 
-ATF_TC_BODY(dbregs2, tc)
+ATF_TC_BODY(dbregs_preserve_dr0, tc)
 {
        const int exitval = 5;
        const int sigval = SIGSTOP;
@@ -196,14 +197,14 @@
 #endif
 
 #if defined(HAVE_DBREGS)
-ATF_TC(dbregs3);
-ATF_TC_HEAD(dbregs3, tc)
+ATF_TC(dbregs_preserve_dr1);
+ATF_TC_HEAD(dbregs_preserve_dr1, tc)
 {
        atf_tc_set_md_var(tc, "descr",
            "Verify that setting DR1 is preserved across ptrace(2) calls");
 }
 
-ATF_TC_BODY(dbregs3, tc)
+ATF_TC_BODY(dbregs_preserve_dr1, tc)
 {
        const int exitval = 5;
        const int sigval = SIGSTOP;
@@ -280,14 +281,14 @@
 #endif
 
 #if defined(HAVE_DBREGS)
-ATF_TC(dbregs4);
-ATF_TC_HEAD(dbregs4, tc)
+ATF_TC(dbregs_preserve_dr2);
+ATF_TC_HEAD(dbregs_preserve_dr2, tc)
 {
        atf_tc_set_md_var(tc, "descr",
            "Verify that setting DR2 is preserved across ptrace(2) calls");
 }
 
-ATF_TC_BODY(dbregs4, tc)
+ATF_TC_BODY(dbregs_preserve_dr2, tc)
 {
        const int exitval = 5;
        const int sigval = SIGSTOP;
@@ -364,14 +365,14 @@
 #endif
 
 #if defined(HAVE_DBREGS)
-ATF_TC(dbregs5);
-ATF_TC_HEAD(dbregs5, tc)
+ATF_TC(dbregs_preserve_dr3);
+ATF_TC_HEAD(dbregs_preserve_dr3, tc)
 {
        atf_tc_set_md_var(tc, "descr",
            "Verify that setting DR3 is preserved across ptrace(2) calls");
 }
 
-ATF_TC_BODY(dbregs5, tc)
+ATF_TC_BODY(dbregs_preserve_dr3, tc)
 {
        const int exitval = 5;
        const int sigval = SIGSTOP;
@@ -447,16 +448,771 @@
 }
 #endif
 
+#if defined(HAVE_DBREGS)
+ATF_TC(dbregs_preserve_dr0_yield);
+ATF_TC_HEAD(dbregs_preserve_dr0_yield, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Verify that setting DR0 is preserved across ptrace(2) calls with "
+           "scheduler yield");
+}
+
+ATF_TC_BODY(dbregs_preserve_dr0_yield, tc)
+{
+       const int exitval = 5;
+       const int sigval = SIGSTOP;
+       pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+       int status;
+#endif
+       struct dbreg r1;
+       struct dbreg r2;
+       /* Number of available CPU Debug Registers on AMD64 */
+       const size_t len = 16;
+       size_t i;
+       int watchme;
+
+       printf("Assert that known number of Debug Registers (%zu) is valid\n",
+           len);
+       ATF_REQUIRE_EQ(__arraycount(r1.dbregs), len);
+       ATF_REQUIRE_EQ(__arraycount(r2.dbregs), len);
+
+       printf("Before forking process PID=%d\n", getpid());
+       child = atf_utils_fork();
+       if (child == 0) {
+               printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+               FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+               printf("Before raising %s from child\n", strsignal(sigval));
+               FORKEE_ASSERT(raise(sigval) == 0);
+
+               printf("Before exiting of the child process\n");
+               _exit(exitval);
+       }
+       printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+       printf("Before calling %s() for the child\n", TWAIT_FNAME);
+       TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+       validate_status_stopped(status, sigval);
+
+       printf("Call GETDBREGS for the child process (r1)\n");
+       ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r1, 0) != -1);
+
+       printf("State of the debug registers (r1):\n");
+       for (i = 0; i < __arraycount(r1.dbregs); i++)
+               printf("r1[%zu]=%#lx\n", i, r1.dbregs[i]);
+
+       r1.dbregs[0] = (long)(intptr_t)&watchme;
+       printf("Set DR0 (r1.dbregs[0]) to new value %#lx\n", r1.dbregs[0]);
+
+       printf("New state of the debug registers (r1):\n");
+       for (i = 0; i < __arraycount(r1.dbregs); i++)
+               printf("r1[%zu]=%#lx\n", i, r1.dbregs[i]);
+
+       printf("Call SETDBREGS for the child process (r1)\n");
+       ATF_REQUIRE(ptrace(PT_SETDBREGS, child, &r1, 0) != -1);
+
+       printf("Yields a processor voluntarily and gives other threads a "
+           "chance to run without waiting for an involuntary preemptive "
+           "switch\n");
+       sched_yield();
+
+       printf("Call GETDBREGS for the child process (r2)\n");
+       ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r2, 0) != -1);
+
+       printf("Assert that (r1) and (r2) are the same\n");
+       ATF_REQUIRE(memcmp(&r1, &r2, len) == 0);
+
+       printf("Before resuming the child process where it left off and "
+           "without signal to be sent\n");
+       ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+       printf("Before calling %s() for the child\n", TWAIT_FNAME);
+       TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+       validate_status_exited(status, exitval);
+
+       printf("Before calling %s() for the child\n", TWAIT_FNAME);
+       TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+
+#if defined(HAVE_DBREGS)
+ATF_TC(dbregs_preserve_dr1_yield);
+ATF_TC_HEAD(dbregs_preserve_dr1_yield, tc)
+{
+       atf_tc_set_md_var(tc, "descr",
+           "Verify that setting DR1 is preserved across ptrace(2) calls with "
+           "scheduler yield");
+}
+
+ATF_TC_BODY(dbregs_preserve_dr1_yield, tc)
+{
+       const int exitval = 5;
+       const int sigval = SIGSTOP;
+       pid_t child, wpid;
+#if defined(TWAIT_HAVE_STATUS)
+       int status;
+#endif
+       struct dbreg r1;
+       struct dbreg r2;
+       /* Number of available CPU Debug Registers on AMD64 */
+       const size_t len = 16;
+       size_t i;
+       int watchme;
+
+       printf("Assert that known number of Debug Registers (%zu) is valid\n",
+           len);
+       ATF_REQUIRE_EQ(__arraycount(r1.dbregs), len);
+       ATF_REQUIRE_EQ(__arraycount(r2.dbregs), len);
+
+       printf("Before forking process PID=%d\n", getpid());
+       child = atf_utils_fork();
+       if (child == 0) {
+               printf("Before calling PT_TRACE_ME from child %d\n", getpid());
+               FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
+
+               printf("Before raising %s from child\n", strsignal(sigval));
+               FORKEE_ASSERT(raise(sigval) == 0);
+
+               printf("Before exiting of the child process\n");
+               _exit(exitval);
+       }
+       printf("Parent process PID=%d, child's PID=%d\n", getpid(), child);
+
+       printf("Before calling %s() for the child\n", TWAIT_FNAME);
+       TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+       validate_status_stopped(status, sigval);
+
+       printf("Call GETDBREGS for the child process (r1)\n");
+       ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r1, 0) != -1);
+
+       printf("State of the debug registers (r1):\n");
+       for (i = 0; i < __arraycount(r1.dbregs); i++)
+               printf("r1[%zu]=%#lx\n", i, r1.dbregs[i]);
+
+       r1.dbregs[1] = (long)(intptr_t)&watchme;
+       printf("Set DR1 (r1.dbregs[1]) to new value %#lx\n", r1.dbregs[1]);
+
+       printf("New state of the debug registers (r1):\n");
+       for (i = 0; i < __arraycount(r1.dbregs); i++)
+               printf("r1[%zu]=%#lx\n", i, r1.dbregs[i]);
+
+       printf("Call SETDBREGS for the child process (r1)\n");
+       ATF_REQUIRE(ptrace(PT_SETDBREGS, child, &r1, 0) != -1);
+
+       printf("Yields a processor voluntarily and gives other threads a "
+           "chance to run without waiting for an involuntary preemptive "
+           "switch\n");
+       sched_yield();
+
+       printf("Call GETDBREGS for the child process (r2)\n");
+       ATF_REQUIRE(ptrace(PT_GETDBREGS, child, &r2, 0) != -1);
+
+       printf("Assert that (r1) and (r2) are the same\n");
+       ATF_REQUIRE(memcmp(&r1, &r2, len) == 0);
+
+       printf("Before resuming the child process where it left off and "
+           "without signal to be sent\n");
+       ATF_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1);
+
+       printf("Before calling %s() for the child\n", TWAIT_FNAME);
+       TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
+
+       validate_status_exited(status, exitval);
+
+       printf("Before calling %s() for the child\n", TWAIT_FNAME);
+       TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
+}
+#endif
+



Home | Main Index | Thread Index | Old Index