Module Name: src Committed By: kamil Date: Sun Feb 19 23:58:30 UTC 2017
Modified Files: src/tests/kernel/arch/amd64: t_ptrace_wait.c Log Message: Extend dbregs_dr*_trap_variable tests to 1-2-4 byte traps in arch/amd64 Replace the following tests: - dbregs_dr0_trap_variable - dbregs_dr1_trap_variable - dbregs_dr2_trap_variable - dbregs_dr3_trap_variable With new ones: - dbregs_dr0_trap_variable_writeonly_byte - dbregs_dr1_trap_variable_writeonly_byte - dbregs_dr2_trap_variable_writeonly_byte - dbregs_dr3_trap_variable_writeonly_byte - dbregs_dr0_trap_variable_writeonly_2bytes - dbregs_dr1_trap_variable_writeonly_2bytes - dbregs_dr2_trap_variable_writeonly_2bytes - dbregs_dr3_trap_variable_writeonly_2bytes - dbregs_dr0_trap_variable_writeonly_4bytes - dbregs_dr1_trap_variable_writeonly_4bytes - dbregs_dr2_trap_variable_writeonly_4bytes - dbregs_dr3_trap_variable_writeonly_4bytes All tests pass with my local implementation of debug registers. Once the interface will be verified, I will prepare it for commit to HEAD. Sponsored by <The NetBSD Foundation> To generate a diff of this commit: cvs rdiff -u -r1.15 -r1.16 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.15 src/tests/kernel/arch/amd64/t_ptrace_wait.c:1.16 --- src/tests/kernel/arch/amd64/t_ptrace_wait.c:1.15 Sun Feb 19 22:09:29 2017 +++ src/tests/kernel/arch/amd64/t_ptrace_wait.c Sun Feb 19 23:58:30 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: t_ptrace_wait.c,v 1.15 2017/02/19 22:09:29 kamil Exp $ */ +/* $NetBSD: t_ptrace_wait.c,v 1.16 2017/02/19 23:58:30 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.15 2017/02/19 22:09:29 kamil Exp $"); +__RCSID("$NetBSD: t_ptrace_wait.c,v 1.16 2017/02/19 23:58:30 kamil Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -1307,14 +1307,1055 @@ ATF_TC_BODY(dbregs_preserve_dr3_continue #endif #if defined(HAVE_DBREGS) -ATF_TC(dbregs_dr0_trap_variable); -ATF_TC_HEAD(dbregs_dr0_trap_variable, tc) +ATF_TC(dbregs_dr0_trap_variable_writeonly_byte); +ATF_TC_HEAD(dbregs_dr0_trap_variable_writeonly_byte, tc) { atf_tc_set_md_var(tc, "descr", - "Verify that setting trap with DR0 triggers SIGTRAP"); + "Verify that setting trap with DR0 triggers SIGTRAP " + "(break on data writes only and 1 byte mode)"); } -ATF_TC_BODY(dbregs_dr0_trap_variable, tc) +ATF_TC_BODY(dbregs_dr0_trap_variable_writeonly_byte, 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; + volatile int watchme; + union u dr7; + + struct ptrace_siginfo info; + memset(&info, 0, sizeof(info)); + + dr7.raw = 0; + dr7.bits.global_dr0_breakpoint = 1; + dr7.bits.condition_dr0 = 3; /* 0b11 -- break on data write&read */ + dr7.bits.len_dr0 = 0; /* 0b00 -- 1 byte */ + + printf("Assert that known number of Debug Registers (%zu) is valid\n", + len); + ATF_REQUIRE_EQ(__arraycount(r1.dr), len); + ATF_REQUIRE_EQ(__arraycount(r2.dr), len); + + printf("Before forking process PID=%d\n", getpid()); + ATF_REQUIRE((child = fork()) != -1); + 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); + + watchme = 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.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + r1.dr[0] = (long)(intptr_t)&watchme; + printf("Set DR0 (r1.dr[0]) to new value %#lx\n", r1.dr[0]); + + r1.dr[7] = dr7.raw; + printf("Set DR7 (r1.dr[7]) to new value %#lx\n", r1.dr[7]); + + printf("New state of the debug registers (r1):\n"); + for (i = 0; i < __arraycount(r1.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + printf("Call SETDBREGS for the child process (r1)\n"); + ATF_REQUIRE(ptrace(PT_SETDBREGS, child, &r1, 0) != -1); + + printf("Call CONTINUE for the child process\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_stopped(status, SIGTRAP); + + printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n"); + ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1); + + printf("Signal traced to lwpid=%d\n", info.psi_lwpid); + printf("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); + + printf("Before checking siginfo_t\n"); + ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP); + ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_DBREG); + + printf("Call CONTINUE for the child process\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_stopped(status, sigval); + + 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_dr1_trap_variable_writeonly_byte); +ATF_TC_HEAD(dbregs_dr1_trap_variable_writeonly_byte, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that setting trap with DR1 triggers SIGTRAP " + "(break on data writes only and 1 byte mode)"); +} + +ATF_TC_BODY(dbregs_dr1_trap_variable_writeonly_byte, 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; + volatile int watchme; + union u dr7; + + struct ptrace_siginfo info; + memset(&info, 0, sizeof(info)); + + dr7.raw = 0; + dr7.bits.global_dr1_breakpoint = 1; + dr7.bits.condition_dr1 = 3; /* 0b11 -- break on data write&read */ + dr7.bits.len_dr1 = 0; /* 0b00 -- 1 byte */ + + printf("Assert that known number of Debug Registers (%zu) is valid\n", + len); + ATF_REQUIRE_EQ(__arraycount(r1.dr), len); + ATF_REQUIRE_EQ(__arraycount(r2.dr), len); + + printf("Before forking process PID=%d\n", getpid()); + ATF_REQUIRE((child = fork()) != -1); + 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); + + watchme = 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.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + r1.dr[1] = (long)(intptr_t)&watchme; + printf("Set DR1 (r1.dr[1]) to new value %#lx\n", r1.dr[1]); + + r1.dr[7] = dr7.raw; + printf("Set DR7 (r1.dr[7]) to new value %#lx\n", r1.dr[7]); + + printf("New state of the debug registers (r1):\n"); + for (i = 0; i < __arraycount(r1.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + printf("Call SETDBREGS for the child process (r1)\n"); + ATF_REQUIRE(ptrace(PT_SETDBREGS, child, &r1, 0) != -1); + + printf("Call CONTINUE for the child process\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_stopped(status, SIGTRAP); + + printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n"); + ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1); + + printf("Signal traced to lwpid=%d\n", info.psi_lwpid); + printf("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); + + printf("Before checking siginfo_t\n"); + ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP); + ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_DBREG); + + printf("Call CONTINUE for the child process\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_stopped(status, sigval); + + 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_dr2_trap_variable_writeonly_byte); +ATF_TC_HEAD(dbregs_dr2_trap_variable_writeonly_byte, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that setting trap with DR2 triggers SIGTRAP " + "(break on data writes only and 1 byte mode)"); +} + +ATF_TC_BODY(dbregs_dr2_trap_variable_writeonly_byte, 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; + volatile int watchme; + union u dr7; + + struct ptrace_siginfo info; + memset(&info, 0, sizeof(info)); + + dr7.raw = 0; + dr7.bits.global_dr2_breakpoint = 1; + dr7.bits.condition_dr2 = 3; /* 0b11 -- break on data write&read */ + dr7.bits.len_dr2 = 0; /* 0b00 -- 1 byte */ + + printf("Assert that known number of Debug Registers (%zu) is valid\n", + len); + ATF_REQUIRE_EQ(__arraycount(r1.dr), len); + ATF_REQUIRE_EQ(__arraycount(r2.dr), len); + + printf("Before forking process PID=%d\n", getpid()); + ATF_REQUIRE((child = fork()) != -1); + 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); + + watchme = 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.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + r1.dr[2] = (long)(intptr_t)&watchme; + printf("Set DR2 (r1.dr[2]) to new value %#lx\n", r1.dr[2]); + + r1.dr[7] = dr7.raw; + printf("Set DR7 (r1.dr[7]) to new value %#lx\n", r1.dr[7]); + + printf("New state of the debug registers (r1):\n"); + for (i = 0; i < __arraycount(r1.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + printf("Call SETDBREGS for the child process (r1)\n"); + ATF_REQUIRE(ptrace(PT_SETDBREGS, child, &r1, 0) != -1); + + printf("Call CONTINUE for the child process\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_stopped(status, SIGTRAP); + + printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n"); + ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1); + + printf("Signal traced to lwpid=%d\n", info.psi_lwpid); + printf("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); + + printf("Before checking siginfo_t\n"); + ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP); + ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_DBREG); + + printf("Call CONTINUE for the child process\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_stopped(status, sigval); + + 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_dr3_trap_variable_writeonly_byte); +ATF_TC_HEAD(dbregs_dr3_trap_variable_writeonly_byte, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that setting trap with DR3 triggers SIGTRAP " + "(break on data writes only and 1 byte mode)"); +} + +ATF_TC_BODY(dbregs_dr3_trap_variable_writeonly_byte, 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; + volatile int watchme; + union u dr7; + + struct ptrace_siginfo info; + memset(&info, 0, sizeof(info)); + + dr7.raw = 0; + dr7.bits.global_dr3_breakpoint = 1; + dr7.bits.condition_dr3 = 3; /* 0b11 -- break on data write&read */ + dr7.bits.len_dr3 = 0; /* 0b00 -- 1 byte */ + + printf("Assert that known number of Debug Registers (%zu) is valid\n", + len); + ATF_REQUIRE_EQ(__arraycount(r1.dr), len); + ATF_REQUIRE_EQ(__arraycount(r2.dr), len); + + printf("Before forking process PID=%d\n", getpid()); + ATF_REQUIRE((child = fork()) != -1); + 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); + + watchme = 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.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + r1.dr[3] = (long)(intptr_t)&watchme; + printf("Set DR3 (r1.dr[3]) to new value %#lx\n", r1.dr[3]); + + r1.dr[7] = dr7.raw; + printf("Set DR7 (r1.dr[7]) to new value %#lx\n", r1.dr[7]); + + printf("New state of the debug registers (r1):\n"); + for (i = 0; i < __arraycount(r1.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + printf("Call SETDBREGS for the child process (r1)\n"); + ATF_REQUIRE(ptrace(PT_SETDBREGS, child, &r1, 0) != -1); + + printf("Call CONTINUE for the child process\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_stopped(status, SIGTRAP); + + printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n"); + ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1); + + printf("Signal traced to lwpid=%d\n", info.psi_lwpid); + printf("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); + + printf("Before checking siginfo_t\n"); + ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP); + ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_DBREG); + + printf("Call CONTINUE for the child process\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_stopped(status, sigval); + + 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_dr0_trap_variable_writeonly_2bytes); +ATF_TC_HEAD(dbregs_dr0_trap_variable_writeonly_2bytes, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that setting trap with DR0 triggers SIGTRAP " + "(break on data writes only and 2 bytes mode)"); +} + +ATF_TC_BODY(dbregs_dr0_trap_variable_writeonly_2bytes, 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; + volatile int watchme; + union u dr7; + + struct ptrace_siginfo info; + memset(&info, 0, sizeof(info)); + + dr7.raw = 0; + dr7.bits.global_dr0_breakpoint = 1; + dr7.bits.condition_dr0 = 3; /* 0b11 -- break on data write&read */ + dr7.bits.len_dr0 = 1; /* 0b01 -- 2 bytes */ + + printf("Assert that known number of Debug Registers (%zu) is valid\n", + len); + ATF_REQUIRE_EQ(__arraycount(r1.dr), len); + ATF_REQUIRE_EQ(__arraycount(r2.dr), len); + + printf("Before forking process PID=%d\n", getpid()); + ATF_REQUIRE((child = fork()) != -1); + 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); + + watchme = 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.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + r1.dr[0] = (long)(intptr_t)&watchme; + printf("Set DR0 (r1.dr[0]) to new value %#lx\n", r1.dr[0]); + + r1.dr[7] = dr7.raw; + printf("Set DR7 (r1.dr[7]) to new value %#lx\n", r1.dr[7]); + + printf("New state of the debug registers (r1):\n"); + for (i = 0; i < __arraycount(r1.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + printf("Call SETDBREGS for the child process (r1)\n"); + ATF_REQUIRE(ptrace(PT_SETDBREGS, child, &r1, 0) != -1); + + printf("Call CONTINUE for the child process\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_stopped(status, SIGTRAP); + + printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n"); + ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1); + + printf("Signal traced to lwpid=%d\n", info.psi_lwpid); + printf("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); + + printf("Before checking siginfo_t\n"); + ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP); + ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_DBREG); + + printf("Call CONTINUE for the child process\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_stopped(status, sigval); + + 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_dr1_trap_variable_writeonly_2bytes); +ATF_TC_HEAD(dbregs_dr1_trap_variable_writeonly_2bytes, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that setting trap with DR1 triggers SIGTRAP " + "(break on data writes only and 2 bytes mode)"); +} + +ATF_TC_BODY(dbregs_dr1_trap_variable_writeonly_2bytes, 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; + volatile int watchme; + union u dr7; + + struct ptrace_siginfo info; + memset(&info, 0, sizeof(info)); + + dr7.raw = 0; + dr7.bits.global_dr1_breakpoint = 1; + dr7.bits.condition_dr1 = 3; /* 0b11 -- break on data write&read */ + dr7.bits.len_dr1 = 1; /* 0b01 -- 2 bytes */ + + printf("Assert that known number of Debug Registers (%zu) is valid\n", + len); + ATF_REQUIRE_EQ(__arraycount(r1.dr), len); + ATF_REQUIRE_EQ(__arraycount(r2.dr), len); + + printf("Before forking process PID=%d\n", getpid()); + ATF_REQUIRE((child = fork()) != -1); + 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); + + watchme = 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.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + r1.dr[1] = (long)(intptr_t)&watchme; + printf("Set DR1 (r1.dr[1]) to new value %#lx\n", r1.dr[1]); + + r1.dr[7] = dr7.raw; + printf("Set DR7 (r1.dr[7]) to new value %#lx\n", r1.dr[7]); + + printf("New state of the debug registers (r1):\n"); + for (i = 0; i < __arraycount(r1.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + printf("Call SETDBREGS for the child process (r1)\n"); + ATF_REQUIRE(ptrace(PT_SETDBREGS, child, &r1, 0) != -1); + + printf("Call CONTINUE for the child process\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_stopped(status, SIGTRAP); + + printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n"); + ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1); + + printf("Signal traced to lwpid=%d\n", info.psi_lwpid); + printf("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); + + printf("Before checking siginfo_t\n"); + ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP); + ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_DBREG); + + printf("Call CONTINUE for the child process\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_stopped(status, sigval); + + 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_dr2_trap_variable_writeonly_2bytes); +ATF_TC_HEAD(dbregs_dr2_trap_variable_writeonly_2bytes, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that setting trap with DR2 triggers SIGTRAP " + "(break on data writes only and 2 bytes mode)"); +} + +ATF_TC_BODY(dbregs_dr2_trap_variable_writeonly_2bytes, 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; + volatile int watchme; + union u dr7; + + struct ptrace_siginfo info; + memset(&info, 0, sizeof(info)); + + dr7.raw = 0; + dr7.bits.global_dr2_breakpoint = 1; + dr7.bits.condition_dr2 = 3; /* 0b11 -- break on data write&read */ + dr7.bits.len_dr2 = 1; /* 0b01 -- 2 bytes */ + + printf("Assert that known number of Debug Registers (%zu) is valid\n", + len); + ATF_REQUIRE_EQ(__arraycount(r1.dr), len); + ATF_REQUIRE_EQ(__arraycount(r2.dr), len); + + printf("Before forking process PID=%d\n", getpid()); + ATF_REQUIRE((child = fork()) != -1); + 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); + + watchme = 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.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + r1.dr[2] = (long)(intptr_t)&watchme; + printf("Set DR2 (r1.dr[2]) to new value %#lx\n", r1.dr[2]); + + r1.dr[7] = dr7.raw; + printf("Set DR7 (r1.dr[7]) to new value %#lx\n", r1.dr[7]); + + printf("New state of the debug registers (r1):\n"); + for (i = 0; i < __arraycount(r1.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + printf("Call SETDBREGS for the child process (r1)\n"); + ATF_REQUIRE(ptrace(PT_SETDBREGS, child, &r1, 0) != -1); + + printf("Call CONTINUE for the child process\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_stopped(status, SIGTRAP); + + printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n"); + ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1); + + printf("Signal traced to lwpid=%d\n", info.psi_lwpid); + printf("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); + + printf("Before checking siginfo_t\n"); + ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP); + ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_DBREG); + + printf("Call CONTINUE for the child process\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_stopped(status, sigval); + + 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_dr3_trap_variable_writeonly_2bytes); +ATF_TC_HEAD(dbregs_dr3_trap_variable_writeonly_2bytes, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that setting trap with DR3 triggers SIGTRAP " + "(break on data writes only and 2 bytes mode)"); +} + +ATF_TC_BODY(dbregs_dr3_trap_variable_writeonly_2bytes, 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; + volatile int watchme; + union u dr7; + + struct ptrace_siginfo info; + memset(&info, 0, sizeof(info)); + + dr7.raw = 0; + dr7.bits.global_dr3_breakpoint = 1; + dr7.bits.condition_dr3 = 3; /* 0b11 -- break on data write&read */ + dr7.bits.len_dr3 = 1; /* 0b01 -- 2 bytes */ + + printf("Assert that known number of Debug Registers (%zu) is valid\n", + len); + ATF_REQUIRE_EQ(__arraycount(r1.dr), len); + ATF_REQUIRE_EQ(__arraycount(r2.dr), len); + + printf("Before forking process PID=%d\n", getpid()); + ATF_REQUIRE((child = fork()) != -1); + 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); + + watchme = 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.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + r1.dr[3] = (long)(intptr_t)&watchme; + printf("Set DR3 (r1.dr[3]) to new value %#lx\n", r1.dr[3]); + + r1.dr[7] = dr7.raw; + printf("Set DR7 (r1.dr[7]) to new value %#lx\n", r1.dr[7]); + + printf("New state of the debug registers (r1):\n"); + for (i = 0; i < __arraycount(r1.dr); i++) + printf("r1[%zu]=%#lx\n", i, r1.dr[i]); + + printf("Call SETDBREGS for the child process (r1)\n"); + ATF_REQUIRE(ptrace(PT_SETDBREGS, child, &r1, 0) != -1); + + printf("Call CONTINUE for the child process\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_stopped(status, SIGTRAP); + + printf("Before calling ptrace(2) with PT_GET_SIGINFO for child\n"); + ATF_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1); + + printf("Signal traced to lwpid=%d\n", info.psi_lwpid); + printf("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); + + printf("Before checking siginfo_t\n"); + ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP); + ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_DBREG); + + printf("Call CONTINUE for the child process\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_stopped(status, sigval); + + 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_dr0_trap_variable_writeonly_4bytes); +ATF_TC_HEAD(dbregs_dr0_trap_variable_writeonly_4bytes, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Verify that setting trap with DR0 triggers SIGTRAP " + "(break on data writes only and 4 bytes mode)"); +} + +ATF_TC_BODY(dbregs_dr0_trap_variable_writeonly_4bytes, tc) { const int exitval = 5; const int sigval = SIGSTOP; @@ -1436,14 +2477,15 @@ ATF_TC_BODY(dbregs_dr0_trap_variable, tc #endif #if defined(HAVE_DBREGS) -ATF_TC(dbregs_dr1_trap_variable); -ATF_TC_HEAD(dbregs_dr1_trap_variable, tc) +ATF_TC(dbregs_dr1_trap_variable_writeonly_4bytes); +ATF_TC_HEAD(dbregs_dr1_trap_variable_writeonly_4bytes, tc) { atf_tc_set_md_var(tc, "descr", - "Verify that setting trap with DR1 triggers SIGTRAP"); + "Verify that setting trap with DR1 triggers SIGTRAP " + "(break on data writes only and 4 bytes mode)"); } -ATF_TC_BODY(dbregs_dr1_trap_variable, tc) +ATF_TC_BODY(dbregs_dr1_trap_variable_writeonly_4bytes, tc) { const int exitval = 5; const int sigval = SIGSTOP; @@ -1565,14 +2607,15 @@ ATF_TC_BODY(dbregs_dr1_trap_variable, tc #endif #if defined(HAVE_DBREGS) -ATF_TC(dbregs_dr2_trap_variable); -ATF_TC_HEAD(dbregs_dr2_trap_variable, tc) +ATF_TC(dbregs_dr2_trap_variable_writeonly_4bytes); +ATF_TC_HEAD(dbregs_dr2_trap_variable_writeonly_4bytes, tc) { atf_tc_set_md_var(tc, "descr", - "Verify that setting trap with DR2 triggers SIGTRAP"); + "Verify that setting trap with DR2 triggers SIGTRAP " + "(break on data writes only and 4 bytes mode)"); } -ATF_TC_BODY(dbregs_dr2_trap_variable, tc) +ATF_TC_BODY(dbregs_dr2_trap_variable_writeonly_4bytes, tc) { const int exitval = 5; const int sigval = SIGSTOP; @@ -1694,14 +2737,15 @@ ATF_TC_BODY(dbregs_dr2_trap_variable, tc #endif #if defined(HAVE_DBREGS) -ATF_TC(dbregs_dr3_trap_variable); -ATF_TC_HEAD(dbregs_dr3_trap_variable, tc) +ATF_TC(dbregs_dr3_trap_variable_writeonly_4bytes); +ATF_TC_HEAD(dbregs_dr3_trap_variable_writeonly_4bytes, tc) { atf_tc_set_md_var(tc, "descr", - "Verify that setting trap with DR3 triggers SIGTRAP"); + "Verify that setting trap with DR3 triggers SIGTRAP " + "(break on data writes only and 4 bytes mode)"); } -ATF_TC_BODY(dbregs_dr3_trap_variable, tc) +ATF_TC_BODY(dbregs_dr3_trap_variable_writeonly_4bytes, tc) { const int exitval = 5; const int sigval = SIGSTOP; @@ -1846,10 +2890,20 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr2_continued); ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_preserve_dr3_continued); - ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr0_trap_variable); - ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr1_trap_variable); - ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr2_trap_variable); - ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr3_trap_variable); + ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr0_trap_variable_writeonly_byte); + ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr1_trap_variable_writeonly_byte); + ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr2_trap_variable_writeonly_byte); + ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr3_trap_variable_writeonly_byte); + + ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr0_trap_variable_writeonly_2bytes); + ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr1_trap_variable_writeonly_2bytes); + ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr2_trap_variable_writeonly_2bytes); + ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr3_trap_variable_writeonly_2bytes); + + ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr0_trap_variable_writeonly_4bytes); + ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr1_trap_variable_writeonly_4bytes); + ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr2_trap_variable_writeonly_4bytes); + ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr3_trap_variable_writeonly_4bytes); return atf_no_error(); }