Module Name:    src
Committed By:   kamil
Date:           Fri Dec  2 06:49:00 UTC 2016

Modified Files:
        src/tests/kernel/arch/amd64: t_ptrace_wait.c

Log Message:
Add new tests dbregs[2345] in MD arch/amd64/ t_ptrace_wait{,3,4,6,id,pid}

dbregs2:
    Verify that setting DR0 is preserved across ptrace(2) calls

dbregs3:
    Verify that setting DR1 is preserved across ptrace(2) calls

dbregs4:
    Verify that setting DR2 is preserved across ptrace(2) calls

dbregs5:
    Verify that setting DR3 is preserved across ptrace(2) calls

These tests are deliberately fine-grained as they are expected to penetrate
precisely each functional aspect of CPU Debug Registers on amd64 one after
another.

These tests (and MI ones) might be generated or merged with helper
functions, however in order to copy-and-paste them out of a test-suite and
quickly port to other platform (in order to compare results) it's useful to
keep them as stand-alone as they are.

Code from these tests might be shared with other ports in future, for the
same reason keep them currently as they are.

Sponsored by <The NetBSD Foundation>


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/tests/kernel/arch/amd64/t_ptrace_wait.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/tests/kernel/arch/amd64/t_ptrace_wait.c
diff -u src/tests/kernel/arch/amd64/t_ptrace_wait.c:1.1 src/tests/kernel/arch/amd64/t_ptrace_wait.c:1.2
--- src/tests/kernel/arch/amd64/t_ptrace_wait.c:1.1	Fri Dec  2 05:54:15 2016
+++ src/tests/kernel/arch/amd64/t_ptrace_wait.c	Fri Dec  2 06:49:00 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: t_ptrace_wait.c,v 1.1 2016/12/02 05:54:15 kamil Exp $	*/
+/*	$NetBSD: t_ptrace_wait.c,v 1.2 2016/12/02 06:49:00 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.1 2016/12/02 05:54:15 kamil Exp $");
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.2 2016/12/02 06:49:00 kamil Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -111,12 +111,352 @@ ATF_TC_BODY(dbregs1, tc)
 }
 #endif
 
+#if defined(HAVE_DBREGS)
+ATF_TC(dbregs2);
+ATF_TC_HEAD(dbregs2, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify that setting DR0 is preserved across ptrace(2) calls");
+}
+
+ATF_TC_BODY(dbregs2, 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("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(dbregs3);
+ATF_TC_HEAD(dbregs3, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify that setting DR1 is preserved across ptrace(2) calls");
+}
+
+ATF_TC_BODY(dbregs3, 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("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(dbregs4);
+ATF_TC_HEAD(dbregs4, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify that setting DR2 is preserved across ptrace(2) calls");
+}
+
+ATF_TC_BODY(dbregs4, 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[2] = (long)(intptr_t)&watchme;
+	printf("Set DR2 (r1.dbregs[2]) to new value %#lx\n", r1.dbregs[2]);
+
+	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("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(dbregs5);
+ATF_TC_HEAD(dbregs5, tc)
+{
+	atf_tc_set_md_var(tc, "descr",
+	    "Verify that setting DR3 is preserved across ptrace(2) calls");
+}
+
+ATF_TC_BODY(dbregs5, 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[3] = (long)(intptr_t)&watchme;
+	printf("Set DR3 (r1.dbregs[3]) to new value %#lx\n", r1.dbregs[3]);
+
+	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("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
+
 ATF_TP_ADD_TCS(tp)
 {
 	setvbuf(stdout, NULL, _IONBF, 0);
 	setvbuf(stderr, NULL, _IONBF, 0);
 
 	ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs1);
+	ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs2);
+	ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs3);
+	ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs4);
+	ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs5);
 
 	return atf_no_error();
 }

Reply via email to