Reduce the code duplication and improve maintainability of x86 register tests by combining all of them to a single base function. --- tests/lib/libc/sys/t_ptrace_amd64_wait.h | 406 +--- tests/lib/libc/sys/t_ptrace_i386_wait.h | 335 +-- tests/lib/libc/sys/t_ptrace_x86_wait.h | 2417 ++++++++++------------ 3 files changed, 1103 insertions(+), 2055 deletions(-)
diff --git a/tests/lib/libc/sys/t_ptrace_amd64_wait.h b/tests/lib/libc/sys/t_ptrace_amd64_wait.h index 1ea17ea1ec1a..0f410f3600d0 100644 --- a/tests/lib/libc/sys/t_ptrace_amd64_wait.h +++ b/tests/lib/libc/sys/t_ptrace_amd64_wait.h @@ -111,415 +111,11 @@ ATF_TC_BODY(x86_64_regs1, tc) TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); } -ATF_TC(x86_64_regs_gp_read); -ATF_TC_HEAD(x86_64_regs_gp_read, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set general-purpose reg values from debugged program and read " - "them via PT_GETREGS, comparing values against expected."); -} - -ATF_TC_BODY(x86_64_regs_gp_read, tc) -{ - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct reg gpr; - - const uint64_t rax = 0x0001020304050607; - const uint64_t rbx = 0x1011121314151617; - const uint64_t rcx = 0x2021222324252627; - const uint64_t rdx = 0x3031323334353637; - const uint64_t rsi = 0x4041424344454647; - const uint64_t rdi = 0x5051525354555657; - const uint64_t rsp = 0x6061626364656667; - const uint64_t rbp = 0x7071727374757677; - - 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 running assembly from child\n"); - - __asm__ __volatile__( - /* rbp & rbp are a bit tricky, we must not clobber them */ - "movq %%rsp, %%r8\n\t" - "movq %%rbp, %%r9\n\t" - "movq %6, %%rsp\n\t" - "movq %7, %%rbp\n\t" - "\n\t" - "int3\n\t" - "\n\t" - "movq %%r8, %%rsp\n\t" - "movq %%r9, %%rbp\n\t" - : - : "a"(rax), "b"(rbx), "c"(rcx), "d"(rdx), "S"(rsi), "D"(rdi), - "i"(rsp), "i"(rbp) - : "%r8", "%r9" - ); - - 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("Call GETREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1); - - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RAX], rax); - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RBX], rbx); - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RCX], rcx); - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RDX], rdx); - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RSI], rsi); - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RDI], rdi); - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RSP], rsp); - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RBP], rbp); - - 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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); -} - -ATF_TC(x86_64_regs_gp_write); -ATF_TC_HEAD(x86_64_regs_gp_write, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set general-purpose reg values into a debugged program via " - "PT_SETREGS and compare the result against expected."); -} - -ATF_TC_BODY(x86_64_regs_gp_write, tc) -{ - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct reg gpr; - - const uint64_t rax = 0x0001020304050607; - const uint64_t rbx = 0x1011121314151617; - const uint64_t rcx = 0x2021222324252627; - const uint64_t rdx = 0x3031323334353637; - const uint64_t rsi = 0x4041424344454647; - const uint64_t rdi = 0x5051525354555657; - const uint64_t rsp = 0x6061626364656667; - const uint64_t rbp = 0x7071727374757677; - - DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); - if (child == 0) { - const uint64_t fill = 0x0F0F0F0F0F0F0F0F; - uint64_t v_rax, v_rbx, v_rcx, v_rdx, v_rsi, v_rdi, v_rsp, v_rbp; - - DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); - FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); - - DPRINTF("Before running assembly from child\n"); - - __asm__ __volatile__( - /* save rsp & rbp */ - "movq %%rsp, %4\n\t" - "movq %%rbp, %5\n\t" - "\n\t" - /* fill registers with clobber pattern */ - "movq %8, %%rax\n\t" - "movq %8, %%rbx\n\t" - "movq %8, %%rcx\n\t" - "movq %8, %%rdx\n\t" - "movq %8, %%rsp\n\t" - "movq %8, %%rbp\n\t" - "movq %8, %%rsi\n\t" - "movq %8, %%rdi\n\t" - "\n\t" - "int3\n\t" - "\n\t" - /* swap saved & current rsp & rbp */ - "xchgq %%rsp, %4\n\t" - "xchgq %%rbp, %5\n\t" - : "=a"(v_rax), "=b"(v_rbx), "=c"(v_rcx), "=d"(v_rdx), "=r"(v_rsp), - "=r"(v_rbp), "=S"(v_rsi), "=D"(v_rdi) - : "g"(fill) - : - ); - - DPRINTF("Before comparing results\n"); - FORKEE_ASSERT_EQ(v_rax, rax); - FORKEE_ASSERT_EQ(v_rbx, rbx); - FORKEE_ASSERT_EQ(v_rcx, rcx); - FORKEE_ASSERT_EQ(v_rdx, rdx); - FORKEE_ASSERT_EQ(v_rsi, rsi); - FORKEE_ASSERT_EQ(v_rdi, rdi); - FORKEE_ASSERT_EQ(v_rsp, rsp); - FORKEE_ASSERT_EQ(v_rbp, rbp); - - 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("Call GETREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1); - - gpr.regs[_REG_RAX] = rax; - gpr.regs[_REG_RBX] = rbx; - gpr.regs[_REG_RCX] = rcx; - gpr.regs[_REG_RDX] = rdx; - gpr.regs[_REG_RSI] = rsi; - gpr.regs[_REG_RDI] = rdi; - gpr.regs[_REG_RSP] = rsp; - gpr.regs[_REG_RBP] = rbp; - - DPRINTF("Call SETREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_SETREGS, child, &gpr, 0) != -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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); -} - -ATF_TC(x86_64_regs_r8_read); -ATF_TC_HEAD(x86_64_regs_r8_read, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set r8..r15 reg values from debugged program and read " - "them via PT_GETREGS, comparing values against expected."); -} - -ATF_TC_BODY(x86_64_regs_r8_read, tc) -{ - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct reg gpr; - - const uint64_t r8[] = { - 0x0001020304050607, - 0x1011121314151617, - 0x2021222324252627, - 0x3031323334353637, - 0x4041424344454647, - 0x5051525354555657, - 0x6061626364656667, - 0x7071727374757677, - }; - - 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 running assembly from child\n"); - - __asm__ __volatile__( - "movq 0x00(%%rbx), %%r8\n\t" - "movq 0x08(%%rbx), %%r9\n\t" - "movq 0x10(%%rbx), %%r10\n\t" - "movq 0x18(%%rbx), %%r11\n\t" - "movq 0x20(%%rbx), %%r12\n\t" - "movq 0x28(%%rbx), %%r13\n\t" - "movq 0x30(%%rbx), %%r14\n\t" - "movq 0x38(%%rbx), %%r15\n\t" - "int3\n\t" - : - : "b"(r8) - : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" - ); - - 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("Call GETREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1); - - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R8], r8[0]); - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R9], r8[1]); - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R10], r8[2]); - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R11], r8[3]); - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R12], r8[4]); - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R13], r8[5]); - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R14], r8[6]); - ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R15], r8[7]); - - 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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); -} - -ATF_TC(x86_64_regs_r8_write); -ATF_TC_HEAD(x86_64_regs_r8_write, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set r8..r15 reg values into a debugged program via " - "PT_SETREGS and compare the result against expected."); -} - -ATF_TC_BODY(x86_64_regs_r8_write, tc) -{ - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct reg gpr; - - const uint64_t r8[] = { - 0x0001020304050607, - 0x1011121314151617, - 0x2021222324252627, - 0x3031323334353637, - 0x4041424344454647, - 0x5051525354555657, - 0x6061626364656667, - 0x7071727374757677, - }; - - DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); - if (child == 0) { - const uint64_t fill = 0x0F0F0F0F0F0F0F0F; - uint64_t v_r8[8]; - - DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); - FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); - - DPRINTF("Before running assembly from child\n"); - - __asm__ __volatile__( - /* fill registers with clobber pattern */ - "movq %1, %%r8\n\t" - "movq %1, %%r9\n\t" - "movq %1, %%r10\n\t" - "movq %1, %%r11\n\t" - "movq %1, %%r12\n\t" - "movq %1, %%r13\n\t" - "movq %1, %%r14\n\t" - "movq %1, %%r15\n\t" - "\n\t" - "int3\n\t" - "\n\t" - "movq %%r8, 0x00(%0)\n\t" - "movq %%r9, 0x08(%0)\n\t" - "movq %%r10, 0x10(%0)\n\t" - "movq %%r11, 0x18(%0)\n\t" - "movq %%r12, 0x20(%0)\n\t" - "movq %%r13, 0x28(%0)\n\t" - "movq %%r14, 0x30(%0)\n\t" - "movq %%r15, 0x38(%0)\n\t" - : - : "a"(v_r8), "m"(fill) - : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" - ); - - DPRINTF("Before comparing results\n"); - FORKEE_ASSERT_EQ(v_r8[0], r8[0]); - FORKEE_ASSERT_EQ(v_r8[1], r8[1]); - FORKEE_ASSERT_EQ(v_r8[2], r8[2]); - FORKEE_ASSERT_EQ(v_r8[3], r8[3]); - FORKEE_ASSERT_EQ(v_r8[4], r8[4]); - FORKEE_ASSERT_EQ(v_r8[5], r8[5]); - FORKEE_ASSERT_EQ(v_r8[6], r8[6]); - FORKEE_ASSERT_EQ(v_r8[7], r8[7]); - - 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("Call GETREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1); - - gpr.regs[_REG_R8] = r8[0]; - gpr.regs[_REG_R9] = r8[1]; - gpr.regs[_REG_R10] = r8[2]; - gpr.regs[_REG_R11] = r8[3]; - gpr.regs[_REG_R12] = r8[4]; - gpr.regs[_REG_R13] = r8[5]; - gpr.regs[_REG_R14] = r8[6]; - gpr.regs[_REG_R15] = r8[7]; - - DPRINTF("Call SETREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_SETREGS, child, &gpr, 0) != -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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); -} - /// ---------------------------------------------------------------------------- #define ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64() \ - ATF_TP_ADD_TC_HAVE_GPREGS(tp, x86_64_regs1); \ - ATF_TP_ADD_TC_HAVE_GPREGS(tp, x86_64_regs_gp_read); \ - ATF_TP_ADD_TC_HAVE_GPREGS(tp, x86_64_regs_gp_write); \ - ATF_TP_ADD_TC_HAVE_GPREGS(tp, x86_64_regs_r8_read); \ - ATF_TP_ADD_TC_HAVE_GPREGS(tp, x86_64_regs_r8_write); + ATF_TP_ADD_TC_HAVE_GPREGS(tp, x86_64_regs1); #else #define ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64() #endif diff --git a/tests/lib/libc/sys/t_ptrace_i386_wait.h b/tests/lib/libc/sys/t_ptrace_i386_wait.h index 7250f4eb66db..8db74261bb35 100644 --- a/tests/lib/libc/sys/t_ptrace_i386_wait.h +++ b/tests/lib/libc/sys/t_ptrace_i386_wait.h @@ -101,341 +101,8 @@ ATF_TC_BODY(i386_regs1, tc) TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); } -ATF_TC(i386_regs_gp_read); -ATF_TC_HEAD(i386_regs_gp_read, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set general-purpose reg values from debugged program and read " - "them via PT_GETREGS, comparing values against expected."); -} - -ATF_TC_BODY(i386_regs_gp_read, tc) -{ - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct reg gpr; - - const uint32_t eax = 0x00010203; - const uint32_t ebx = 0x10111213; - const uint32_t ecx = 0x20212223; - const uint32_t edx = 0x30313233; - const uint32_t esi = 0x40414243; - const uint32_t edi = 0x50515253; - - 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 running assembly from child\n"); - - __asm__ __volatile__( - "int3\n\t" - : - : "a"(eax), "b"(ebx), "c"(ecx), "d"(edx), "S"(esi), "D"(edi) - : - ); - - 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("Call GETREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1); - - ATF_CHECK_EQ((uint32_t)gpr.r_eax, eax); - ATF_CHECK_EQ((uint32_t)gpr.r_ebx, ebx); - ATF_CHECK_EQ((uint32_t)gpr.r_ecx, ecx); - ATF_CHECK_EQ((uint32_t)gpr.r_edx, edx); - ATF_CHECK_EQ((uint32_t)gpr.r_esi, esi); - ATF_CHECK_EQ((uint32_t)gpr.r_edi, edi); - - 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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); -} - -ATF_TC(i386_regs_gp_write); -ATF_TC_HEAD(i386_regs_gp_write, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set general-purpose reg values into a debugged program via " - "PT_SETREGS and compare the result against expected."); -} - -ATF_TC_BODY(i386_regs_gp_write, tc) -{ - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct reg gpr; - - const uint32_t eax = 0x00010203; - const uint32_t ebx = 0x10111213; - const uint32_t ecx = 0x20212223; - const uint32_t edx = 0x30313233; - const uint32_t esi = 0x40414243; - const uint32_t edi = 0x50515253; - - DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); - if (child == 0) { - const uint64_t fill = 0x0F0F0F0F; - uint32_t v_eax, v_ebx, v_ecx, v_edx, v_esi, v_edi; - - DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); - FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); - - DPRINTF("Before running assembly from child\n"); - - __asm__ __volatile__( - /* fill registers with clobber pattern */ - "movl %6, %%eax\n\t" - "movl %6, %%ebx\n\t" - "movl %6, %%ecx\n\t" - "movl %6, %%edx\n\t" - "movl %6, %%esi\n\t" - "movl %6, %%edi\n\t" - "\n\t" - "int3\n\t" - : "=a"(v_eax), "=b"(v_ebx), "=c"(v_ecx), "=d"(v_edx), "=S"(v_esi), - "=D"(v_edi) - : "g"(fill) - : - ); - - DPRINTF("Before comparing results\n"); - FORKEE_ASSERT_EQ(v_eax, eax); - FORKEE_ASSERT_EQ(v_ebx, ebx); - FORKEE_ASSERT_EQ(v_ecx, ecx); - FORKEE_ASSERT_EQ(v_edx, edx); - FORKEE_ASSERT_EQ(v_esi, esi); - FORKEE_ASSERT_EQ(v_edi, edi); - - 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("Call GETREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1); - - gpr.r_eax = eax; - gpr.r_ebx = ebx; - gpr.r_ecx = ecx; - gpr.r_edx = edx; - gpr.r_esi = esi; - gpr.r_edi = edi; - - DPRINTF("Call SETREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_SETREGS, child, &gpr, 0) != -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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); -} - -ATF_TC(i386_regs_ebp_esp_read); -ATF_TC_HEAD(i386_regs_ebp_esp_read, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set EBP & ESP reg values from debugged program and read " - "them via PT_GETREGS, comparing values against expected."); -} - -ATF_TC_BODY(i386_regs_ebp_esp_read, tc) -{ - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct reg gpr; - - const uint32_t esp = 0x60616263; - const uint32_t ebp = 0x70717273; - - 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 running assembly from child\n"); - - __asm__ __volatile__( - /* ebp & ebp are a bit tricky, we must not clobber them */ - "movl %%esp, %%eax\n\t" - "movl %%ebp, %%ebx\n\t" - "movl %0, %%esp\n\t" - "movl %1, %%ebp\n\t" - "\n\t" - "int3\n\t" - "\n\t" - "movl %%eax, %%esp\n\t" - "movl %%ebx, %%ebp\n\t" - : - : "ri"(esp), "ri"(ebp) - : "%eax", "%ebx" - ); - - 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("Call GETREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1); - - ATF_CHECK_EQ((uint32_t)gpr.r_esp, esp); - ATF_CHECK_EQ((uint32_t)gpr.r_ebp, ebp); - - 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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); -} - -ATF_TC(i386_regs_ebp_esp_write); -ATF_TC_HEAD(i386_regs_ebp_esp_write, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set EBP & ESP reg values into a debugged program via " - "PT_SETREGS and compare the result against expected."); -} - -ATF_TC_BODY(i386_regs_ebp_esp_write, tc) -{ - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct reg gpr; - - const uint32_t esp = 0x60616263; - const uint32_t ebp = 0x70717273; - - DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); - if (child == 0) { - const uint64_t fill = 0x0F0F0F0F; - uint32_t v_esp, v_ebp; - - DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); - FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); - - DPRINTF("Before running assembly from child\n"); - - __asm__ __volatile__( - /* save original ebp & esp using our output registers */ - "movl %%esp, %0\n\t" - "movl %%ebp, %1\n\t" - /* fill them with clobber pattern */ - "movl %2, %%esp\n\t" - "movl %2, %%ebp\n\t" - "\n\t" - "int3\n\t" - "\n\t" - /* restore ebp & esp, and save the result */ - "xchgl %%esp, %0\n\t" - "xchgl %%ebp, %1\n\t" - : "=r"(v_esp), "=r"(v_ebp) - : "g"(fill) - : - ); - - DPRINTF("Before comparing results\n"); - FORKEE_ASSERT_EQ(v_esp, esp); - FORKEE_ASSERT_EQ(v_ebp, ebp); - - 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("Call GETREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1); - - gpr.r_esp = esp; - gpr.r_ebp = ebp; - - DPRINTF("Call SETREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_SETREGS, child, &gpr, 0) != -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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); -} - #define ATF_TP_ADD_TCS_PTRACE_WAIT_I386() \ - ATF_TP_ADD_TC_HAVE_GPREGS(tp, i386_regs1); \ - ATF_TP_ADD_TC_HAVE_GPREGS(tp, i386_regs_gp_read); \ - ATF_TP_ADD_TC_HAVE_GPREGS(tp, i386_regs_gp_write); \ - ATF_TP_ADD_TC_HAVE_GPREGS(tp, i386_regs_ebp_esp_read); \ - ATF_TP_ADD_TC_HAVE_GPREGS(tp, i386_regs_ebp_esp_write); + ATF_TP_ADD_TC_HAVE_GPREGS(tp, i386_regs1); #else #define ATF_TP_ADD_TCS_PTRACE_WAIT_I386() #endif diff --git a/tests/lib/libc/sys/t_ptrace_x86_wait.h b/tests/lib/libc/sys/t_ptrace_x86_wait.h index 6d177d4624e9..4572e3eb8b23 100644 --- a/tests/lib/libc/sys/t_ptrace_x86_wait.h +++ b/tests/lib/libc/sys/t_ptrace_x86_wait.h @@ -2189,1273 +2189,400 @@ ATF_TC_BODY(x86_cve_2018_8897, tc) TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); } -ATF_TC(x86_regs_mm_read); -ATF_TC_HEAD(x86_regs_mm_read, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set MMX (mm0..mm7) reg values from debugged program and read " - "them via PT_GETFPREGS, comparing values against expected."); -} +/// ---------------------------------------------------------------------------- -__attribute__((target("mmx"))) -static __inline void set_mm_regs(const uint64_t mm[]) +union x86_test_register { + struct { + uint64_t a, b, c, d; + } ymm; + struct { + uint64_t a, b; + } xmm; + uint64_t u64; + uint32_t u32; +}; + +enum x86_test_regset { + TEST_GPREGS, + TEST_FPREGS, + TEST_XMMREGS, + TEST_XSTATE +}; + +/* Please keep them grouped by acceptable x86_test_regset. */ +enum x86_test_registers { + /* TEST_GPREGS */ + GPREGS_32, + GPREGS_32_EBP_ESP, + GPREGS_64, + GPREGS_64_R8, + /* TEST_FPREGS/TEST_XMMREGS */ + FPREGS_MM, + FPREGS_XMM, + /* TEST_XSTATE */ + FPREGS_YMM +}; + +enum x86_test_regmode { + TEST_GETREGS, + TEST_SETREGS +}; + +static __inline void get_gp32_regs(union x86_test_register out[]) { +#if defined(__i386__) + const uint32_t fill = 0x0F0F0F0F; + __asm__ __volatile__( - "movq 0x00(%0), %%mm0\n\t" - "movq 0x08(%0), %%mm1\n\t" - "movq 0x10(%0), %%mm2\n\t" - "movq 0x18(%0), %%mm3\n\t" - "movq 0x20(%0), %%mm4\n\t" - "movq 0x28(%0), %%mm5\n\t" - "movq 0x30(%0), %%mm6\n\t" - "movq 0x38(%0), %%mm7\n\t" + /* fill registers with clobber pattern */ + "movl %6, %%eax\n\t" + "movl %6, %%ebx\n\t" + "movl %6, %%ecx\n\t" + "movl %6, %%edx\n\t" + "movl %6, %%esi\n\t" + "movl %6, %%edi\n\t" + "\n\t" "int3\n\t" - : - : "b"(mm) - : "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" + : "=a"(out[0].u32), "=b"(out[1].u32), "=c"(out[2].u32), + "=d"(out[3].u32), "=S"(out[4].u32), "=D"(out[5].u32) + : "g"(fill) ); +#else + __unreachable(); +#endif } -ATF_TC_BODY(x86_regs_mm_read, tc) +static __inline void set_gp32_regs(const union x86_test_register data[]) { - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct fpreg fpr; - - const uint64_t mm[] = { - 0x0001020304050607, - 0x1011121314151617, - 0x2021222324252627, - 0x3031323334353637, - 0x4041424344454647, - 0x5051525354555657, - 0x6061626364656667, - 0x7071727374757677, - }; - - /* verify whether MMX is supported here */ - DPRINTF("Before invoking cpuid\n"); - { - unsigned int eax, ebx, ecx, edx; - if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) - atf_tc_skip("CPUID is not supported by the CPU"); - - DPRINTF("cpuid: EDX = %08x\n", edx); - - if (!(edx & bit_MMX)) - atf_tc_skip("MMX is not supported by the CPU"); - } - - 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 running assembly from child\n"); - set_mm_regs(mm); - - 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("Call GETFPREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETFPREGS, child, &fpr, 0) != -1); - -#if defined(__x86_64__) -#define MM_REG(n) fpr.fxstate.fx_87_ac[n].r.f87_mantissa +#if defined(__i386__) + __asm__ __volatile__( + "int3\n\t" + : + : "a"(data[0].u32), "b"(data[1].u32), "c"(data[2].u32), + "d"(data[3].u32), "S"(data[4].u32), "D"(data[5].u32) + : + ); #else -#define MM_REG(n) fpr.fstate.s87_ac[n].f87_mantissa + __unreachable(); #endif - - ATF_CHECK_EQ(MM_REG(0), mm[0]); - ATF_CHECK_EQ(MM_REG(1), mm[1]); - ATF_CHECK_EQ(MM_REG(2), mm[2]); - ATF_CHECK_EQ(MM_REG(3), mm[3]); - ATF_CHECK_EQ(MM_REG(4), mm[4]); - ATF_CHECK_EQ(MM_REG(5), mm[5]); - ATF_CHECK_EQ(MM_REG(6), mm[6]); - ATF_CHECK_EQ(MM_REG(7), mm[7]); - -#undef MM_REG - - 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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); } -__attribute__((target("mmx"))) -static __inline void get_mm_regs(uint64_t v_mm[]) +static __inline void get_gp32_ebp_esp_regs(union x86_test_register out[]) { - const uint64_t fill = 0x0F0F0F0F0F0F0F0F; +#if defined(__i386__) + const uint32_t fill = 0x0F0F0F0F; __asm__ __volatile__( - /* fill registers with clobber pattern */ - "movq %1, %%mm0\n\t" - "movq %1, %%mm1\n\t" - "movq %1, %%mm2\n\t" - "movq %1, %%mm3\n\t" - "movq %1, %%mm4\n\t" - "movq %1, %%mm5\n\t" - "movq %1, %%mm6\n\t" - "movq %1, %%mm7\n\t" + /* save original ebp & esp using our output registers */ + "movl %%esp, %0\n\t" + "movl %%ebp, %1\n\t" + /* fill them with clobber pattern */ + "movl %2, %%esp\n\t" + "movl %2, %%ebp\n\t" "\n\t" "int3\n\t" "\n\t" - "movq %%mm0, 0x00(%0)\n\t" - "movq %%mm1, 0x08(%0)\n\t" - "movq %%mm2, 0x10(%0)\n\t" - "movq %%mm3, 0x18(%0)\n\t" - "movq %%mm4, 0x20(%0)\n\t" - "movq %%mm5, 0x28(%0)\n\t" - "movq %%mm6, 0x30(%0)\n\t" - "movq %%mm7, 0x38(%0)\n\t" + /* restore ebp & esp, and save the result */ + "xchgl %%esp, %0\n\t" + "xchgl %%ebp, %1\n\t" + : "=r"(out[0].u32), "=r"(out[1].u32) + : "g"(fill) : - : "a"(v_mm), "m"(fill) - : "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" ); -} - -ATF_TC(x86_regs_mm_write); -ATF_TC_HEAD(x86_regs_mm_write, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set mm0..mm7 reg values into a debugged program via " - "PT_SETFPREGS and compare the result against expected."); -} - -ATF_TC_BODY(x86_regs_mm_write, tc) -{ - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct fpreg fpr; - - const uint64_t mm[] = { - 0x0001020304050607, - 0x1011121314151617, - 0x2021222324252627, - 0x3031323334353637, - 0x4041424344454647, - 0x5051525354555657, - 0x6061626364656667, - 0x7071727374757677, - }; - - /* verify whether MMX is supported here */ - DPRINTF("Before invoking cpuid\n"); - { - unsigned int eax, ebx, ecx, edx; - if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) - atf_tc_skip("CPUID is not supported by the CPU"); - - DPRINTF("cpuid: EDX = %08x\n", edx); - - if (!(edx & bit_MMX)) - atf_tc_skip("MMX is not supported by the CPU"); - } - - DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); - if (child == 0) { - uint64_t v_mm[8]; - - DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); - FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); - - DPRINTF("Before running assembly from child\n"); - get_mm_regs(v_mm); - - DPRINTF("Before comparing results\n"); - FORKEE_ASSERT_EQ(v_mm[0], mm[0]); - FORKEE_ASSERT_EQ(v_mm[1], mm[1]); - FORKEE_ASSERT_EQ(v_mm[2], mm[2]); - FORKEE_ASSERT_EQ(v_mm[3], mm[3]); - FORKEE_ASSERT_EQ(v_mm[4], mm[4]); - FORKEE_ASSERT_EQ(v_mm[5], mm[5]); - FORKEE_ASSERT_EQ(v_mm[6], mm[6]); - FORKEE_ASSERT_EQ(v_mm[7], mm[7]); - - 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("Call GETFPREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETFPREGS, child, &fpr, 0) != -1); - -#if defined(__x86_64__) -#define MM_REG(n) fpr.fxstate.fx_87_ac[n].r.f87_mantissa #else -#define MM_REG(n) fpr.fstate.s87_ac[n].f87_mantissa + __unreachable(); #endif - - MM_REG(0) = mm[0]; - MM_REG(1) = mm[1]; - MM_REG(2) = mm[2]; - MM_REG(3) = mm[3]; - MM_REG(4) = mm[4]; - MM_REG(5) = mm[5]; - MM_REG(6) = mm[6]; - MM_REG(7) = mm[7]; - -#undef MM_REG - - DPRINTF("Call SETFPREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_SETFPREGS, child, &fpr, 0) != -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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); } -__attribute__((target("sse"))) -static __inline void set_xmm_regs(const void* xmm) +static __inline void set_gp32_ebp_esp_regs(const union x86_test_register data[]) { +#if defined(__i386__) __asm__ __volatile__( - "movaps 0x00(%0), %%xmm0\n\t" - "movaps 0x10(%0), %%xmm1\n\t" - "movaps 0x20(%0), %%xmm2\n\t" - "movaps 0x30(%0), %%xmm3\n\t" - "movaps 0x40(%0), %%xmm4\n\t" - "movaps 0x50(%0), %%xmm5\n\t" - "movaps 0x60(%0), %%xmm6\n\t" - "movaps 0x70(%0), %%xmm7\n\t" -#if defined(__x86_64__) - "movaps 0x80(%0), %%xmm8\n\t" - "movaps 0x90(%0), %%xmm9\n\t" - "movaps 0xA0(%0), %%xmm10\n\t" - "movaps 0xB0(%0), %%xmm11\n\t" - "movaps 0xC0(%0), %%xmm12\n\t" - "movaps 0xD0(%0), %%xmm13\n\t" - "movaps 0xE0(%0), %%xmm14\n\t" - "movaps 0xF0(%0), %%xmm15\n\t" -#endif + /* ebp & ebp are a bit tricky, we must not clobber them */ + "movl %%esp, %%eax\n\t" + "movl %%ebp, %%ebx\n\t" + "movl %0, %%esp\n\t" + "movl %1, %%ebp\n\t" + "\n\t" "int3\n\t" + "\n\t" + "movl %%eax, %%esp\n\t" + "movl %%ebx, %%ebp\n\t" : - : "b"(xmm) - : "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", - "%xmm7" -#if defined(__x86_64__) - , "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", - "%xmm14", "%xmm15" -#endif + : "ri"(data[0].u32), "ri"(data[1].u32) + : "%eax", "%ebx" ); +#else + __unreachable(); +#endif } -ATF_TC(x86_regs_xmm_read); -ATF_TC_HEAD(x86_regs_xmm_read, tc) +static __inline void get_gp64_regs(union x86_test_register out[]) { - atf_tc_set_md_var(tc, "descr", - "Set xmm0..xmm15 (..xmm7 on i386) reg values from debugged program " - "and read them via PT_GETFPREGS (PT_GETXMMREGS on i386), comparing " - "values against expected."); +#if defined(__x86_64__) + const uint64_t fill = 0x0F0F0F0F0F0F0F0F; + + __asm__ __volatile__( + /* save rsp & rbp */ + "movq %%rsp, %6\n\t" + "movq %%rbp, %7\n\t" + "\n\t" + /* fill registers with clobber pattern */ + "movq %8, %%rax\n\t" + "movq %8, %%rbx\n\t" + "movq %8, %%rcx\n\t" + "movq %8, %%rdx\n\t" + "movq %8, %%rsp\n\t" + "movq %8, %%rbp\n\t" + "movq %8, %%rsi\n\t" + "movq %8, %%rdi\n\t" + "\n\t" + "int3\n\t" + "\n\t" + /* swap saved & current rsp & rbp */ + "xchgq %%rsp, %6\n\t" + "xchgq %%rbp, %7\n\t" + : "=a"(out[0].u64), "=b"(out[1].u64), "=c"(out[2].u64), + "=d"(out[3].u64), "=S"(out[4].u64), "=D"(out[5].u64), + "=r"(out[6].u64), "=r"(out[7].u64) + : "g"(fill) + ); +#else + __unreachable(); +#endif } -ATF_TC_BODY(x86_regs_xmm_read, tc) +static __inline void set_gp64_regs(const union x86_test_register data[]) { - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif #if defined(__x86_64__) - struct fpreg fpr; + __asm__ __volatile__( + /* rbp & rbp are a bit tricky, we must not clobber them */ + "movq %%rsp, %%r8\n\t" + "movq %%rbp, %%r9\n\t" + "movq %6, %%rsp\n\t" + "movq %7, %%rbp\n\t" + "\n\t" + "int3\n\t" + "\n\t" + "movq %%r8, %%rsp\n\t" + "movq %%r9, %%rbp\n\t" + : + : "a"(data[0].u64), "b"(data[1].u64), "c"(data[2].u64), + "d"(data[3].u64), "S"(data[4].u64), "D"(data[5].u64), + "r"(data[6].u64), "r"(data[7].u64) + : "%r8", "%r9" + ); #else - struct xmmregs fpr; + __unreachable(); #endif +} - const struct { - uint64_t a, b; - } xmm[] __aligned(16) = { - { 0x0706050403020100, 0x0F0E0D0C0B0A0908, }, - { 0x0807060504030201, 0x100F0E0D0C0B0A09, }, - { 0x0908070605040302, 0x11100F0E0D0C0B0A, }, - { 0x0A09080706050403, 0x1211100F0E0D0C0B, }, - { 0x0B0A090807060504, 0x131211100F0E0D0C, }, - { 0x0C0B0A0908070605, 0x14131211100F0E0D, }, - { 0x0D0C0B0A09080706, 0x1514131211100F0E, }, - { 0x0E0D0C0B0A090807, 0x161514131211100F, }, +static __inline void get_gp64_r8_regs(union x86_test_register out[]) +{ #if defined(__x86_64__) - { 0x0F0E0D0C0B0A0908, 0x1716151413121110, }, - { 0x100F0E0D0C0B0A09, 0x1817161514131211, }, - { 0x11100F0E0D0C0B0A, 0x1918171615141312, }, - { 0x1211100F0E0D0C0B, 0x1A19181716151413, }, - { 0x131211100F0E0D0C, 0x1B1A191817161514, }, - { 0x14131211100F0E0D, 0x1C1B1A1918171615, }, - { 0x1514131211100F0E, 0x1D1C1B1A19181716, }, - { 0x161514131211100F, 0x1E1D1C1B1A191817, }, -#endif - }; - - /* verify whether SSE is supported here */ - DPRINTF("Before invoking cpuid\n"); - { - unsigned int eax, ebx, ecx, edx; - if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) - atf_tc_skip("CPUID is not supported by the CPU"); - - DPRINTF("cpuid: EDX = %08x\n", edx); - - if (!(edx & bit_SSE)) - atf_tc_skip("SSE is not supported by the CPU"); - } - - 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 running assembly from child\n"); - set_xmm_regs(xmm); - - 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); + const uint64_t fill = 0x0F0F0F0F0F0F0F0F; -#if defined(__x86_64__) - DPRINTF("Call GETFPREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETFPREGS, child, &fpr, 0) != -1); + __asm__ __volatile__( + /* fill registers with clobber pattern */ + "movq %1, %%r8\n\t" + "movq %1, %%r9\n\t" + "movq %1, %%r10\n\t" + "movq %1, %%r11\n\t" + "movq %1, %%r12\n\t" + "movq %1, %%r13\n\t" + "movq %1, %%r14\n\t" + "movq %1, %%r15\n\t" + "\n\t" + "int3\n\t" + "\n\t" + "movq %%r8, 0x00(%0)\n\t" + "movq %%r9, 0x20(%0)\n\t" + "movq %%r10, 0x40(%0)\n\t" + "movq %%r11, 0x60(%0)\n\t" + "movq %%r12, 0x80(%0)\n\t" + "movq %%r13, 0xA0(%0)\n\t" + "movq %%r14, 0xC0(%0)\n\t" + "movq %%r15, 0xE0(%0)\n\t" + : + : "a"(out), "m"(fill) + : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" + ); #else - DPRINTF("Call GETXMMREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETXMMREGS, child, &fpr, 0) != -1); -#endif - - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[0], &xmm[0], sizeof(*xmm))); - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[1], &xmm[1], sizeof(*xmm))); - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[2], &xmm[2], sizeof(*xmm))); - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[3], &xmm[3], sizeof(*xmm))); - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[4], &xmm[4], sizeof(*xmm))); - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[5], &xmm[5], sizeof(*xmm))); - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[6], &xmm[6], sizeof(*xmm))); - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[7], &xmm[7], sizeof(*xmm))); -#if defined(__x86_64__) - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[8], &xmm[8], sizeof(*xmm))); - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[9], &xmm[9], sizeof(*xmm))); - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[10], &xmm[10], sizeof(*xmm))); - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[11], &xmm[11], sizeof(*xmm))); - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[12], &xmm[12], sizeof(*xmm))); - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[13], &xmm[13], sizeof(*xmm))); - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[14], &xmm[14], sizeof(*xmm))); - ATF_CHECK(!memcmp(&fpr.fxstate.fx_xmm[15], &xmm[15], sizeof(*xmm))); + __unreachable(); #endif - - 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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); } -__attribute__((target("sse"))) -static __inline void get_xmm_regs(void* v_xmm) +static __inline void set_gp64_r8_regs(const union x86_test_register data[]) { - const struct { - uint64_t a, b; - } fill __aligned(16) = {0x0F0F0F0F0F0F0F0F, 0x0F0F0F0F0F0F0F0F}; - - __asm__ __volatile__( - /* fill registers with clobber pattern */ - "movaps %1, %%xmm0\n\t" - "movaps %1, %%xmm1\n\t" - "movaps %1, %%xmm2\n\t" - "movaps %1, %%xmm3\n\t" - "movaps %1, %%xmm4\n\t" - "movaps %1, %%xmm5\n\t" - "movaps %1, %%xmm6\n\t" - "movaps %1, %%xmm7\n\t" -#if defined(__x86_64__) - "movaps %1, %%xmm8\n\t" - "movaps %1, %%xmm9\n\t" - "movaps %1, %%xmm10\n\t" - "movaps %1, %%xmm11\n\t" - "movaps %1, %%xmm12\n\t" - "movaps %1, %%xmm13\n\t" - "movaps %1, %%xmm14\n\t" - "movaps %1, %%xmm15\n\t" -#endif - "\n\t" - "int3\n\t" - "\n\t" - "movaps %%xmm0, 0x00(%0)\n\t" - "movaps %%xmm1, 0x10(%0)\n\t" - "movaps %%xmm2, 0x20(%0)\n\t" - "movaps %%xmm3, 0x30(%0)\n\t" - "movaps %%xmm4, 0x40(%0)\n\t" - "movaps %%xmm5, 0x50(%0)\n\t" - "movaps %%xmm6, 0x60(%0)\n\t" - "movaps %%xmm7, 0x70(%0)\n\t" -#if defined(__x86_64__) - "movaps %%xmm8, 0x80(%0)\n\t" - "movaps %%xmm9, 0x90(%0)\n\t" - "movaps %%xmm10, 0xA0(%0)\n\t" - "movaps %%xmm11, 0xB0(%0)\n\t" - "movaps %%xmm12, 0xC0(%0)\n\t" - "movaps %%xmm13, 0xD0(%0)\n\t" - "movaps %%xmm14, 0xE0(%0)\n\t" - "movaps %%xmm15, 0xF0(%0)\n\t" -#endif - : - : "a"(v_xmm), "m"(fill) - : "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" -#if defined(__x86_64__) - , "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", "%xmm14", - "%xmm15" -#endif - ); -} - -ATF_TC(x86_regs_xmm_write); -ATF_TC_HEAD(x86_regs_xmm_write, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set xmm0..xmm15 (..xmm7 on i386) reg values into a debugged " - "program via PT_SETFPREGS (PT_SETXMMREGS on i386) and compare " - "the result against expected."); -} - -ATF_TC_BODY(x86_regs_xmm_write, tc) -{ - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif #if defined(__x86_64__) - struct fpreg fpr; -#else - struct xmmregs fpr; -#endif - - const struct { - uint64_t a, b; - } xmm[] __aligned(16) = { - { 0x0706050403020100, 0x0F0E0D0C0B0A0908, }, - { 0x0807060504030201, 0x100F0E0D0C0B0A09, }, - { 0x0908070605040302, 0x11100F0E0D0C0B0A, }, - { 0x0A09080706050403, 0x1211100F0E0D0C0B, }, - { 0x0B0A090807060504, 0x131211100F0E0D0C, }, - { 0x0C0B0A0908070605, 0x14131211100F0E0D, }, - { 0x0D0C0B0A09080706, 0x1514131211100F0E, }, - { 0x0E0D0C0B0A090807, 0x161514131211100F, }, -#if defined(__x86_64__) - { 0x0F0E0D0C0B0A0908, 0x1716151413121110, }, - { 0x100F0E0D0C0B0A09, 0x1817161514131211, }, - { 0x11100F0E0D0C0B0A, 0x1918171615141312, }, - { 0x1211100F0E0D0C0B, 0x1A19181716151413, }, - { 0x131211100F0E0D0C, 0x1B1A191817161514, }, - { 0x14131211100F0E0D, 0x1C1B1A1918171615, }, - { 0x1514131211100F0E, 0x1D1C1B1A19181716, }, - { 0x161514131211100F, 0x1E1D1C1B1A191817, }, -#endif - }; - - /* verify whether SSE is supported here */ - DPRINTF("Before invoking cpuid\n"); - { - unsigned int eax, ebx, ecx, edx; - if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) - atf_tc_skip("CPUID is not supported by the CPU"); - - DPRINTF("cpuid: EDX = %08x\n", edx); - - if (!(edx & bit_SSE)) - atf_tc_skip("SSE is not supported by the CPU"); - } - - DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); - if (child == 0) { - struct { - uint64_t a, b; - } v_xmm[16] __aligned(16); - - DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); - FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); - - DPRINTF("Before running assembly from child\n"); - get_xmm_regs(v_xmm); - - DPRINTF("Before comparing results\n"); - FORKEE_ASSERT(!memcmp(&v_xmm[0], &xmm[0], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[1], &xmm[1], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[2], &xmm[2], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[3], &xmm[3], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[4], &xmm[4], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[5], &xmm[5], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[6], &xmm[6], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[7], &xmm[7], sizeof(*xmm))); -#if defined(__x86_64__) - FORKEE_ASSERT(!memcmp(&v_xmm[8], &xmm[8], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[9], &xmm[9], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[10], &xmm[10], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[11], &xmm[11], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[12], &xmm[12], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[13], &xmm[13], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[14], &xmm[14], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[15], &xmm[15], sizeof(*xmm))); -#endif - - 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); - -#if defined(__x86_64__) - DPRINTF("Call GETFPREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETFPREGS, child, &fpr, 0) != -1); -#else - DPRINTF("Call GETXMMREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETXMMREGS, child, &fpr, 0) != -1); -#endif - - memcpy(&fpr.fxstate.fx_xmm[0], &xmm[0], sizeof(*xmm)); - memcpy(&fpr.fxstate.fx_xmm[1], &xmm[1], sizeof(*xmm)); - memcpy(&fpr.fxstate.fx_xmm[2], &xmm[2], sizeof(*xmm)); - memcpy(&fpr.fxstate.fx_xmm[3], &xmm[3], sizeof(*xmm)); - memcpy(&fpr.fxstate.fx_xmm[4], &xmm[4], sizeof(*xmm)); - memcpy(&fpr.fxstate.fx_xmm[5], &xmm[5], sizeof(*xmm)); - memcpy(&fpr.fxstate.fx_xmm[6], &xmm[6], sizeof(*xmm)); - memcpy(&fpr.fxstate.fx_xmm[7], &xmm[7], sizeof(*xmm)); -#if defined(__x86_64__) - memcpy(&fpr.fxstate.fx_xmm[8], &xmm[8], sizeof(*xmm)); - memcpy(&fpr.fxstate.fx_xmm[9], &xmm[9], sizeof(*xmm)); - memcpy(&fpr.fxstate.fx_xmm[10], &xmm[10], sizeof(*xmm)); - memcpy(&fpr.fxstate.fx_xmm[11], &xmm[11], sizeof(*xmm)); - memcpy(&fpr.fxstate.fx_xmm[12], &xmm[12], sizeof(*xmm)); - memcpy(&fpr.fxstate.fx_xmm[13], &xmm[13], sizeof(*xmm)); - memcpy(&fpr.fxstate.fx_xmm[14], &xmm[14], sizeof(*xmm)); - memcpy(&fpr.fxstate.fx_xmm[15], &xmm[15], sizeof(*xmm)); -#endif - -#if defined(__x86_64__) - DPRINTF("Call SETFPREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_SETFPREGS, child, &fpr, 0) != -1); -#else - DPRINTF("Call SETXMMREGS for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_SETXMMREGS, child, &fpr, 0) != -1); -#endif - - 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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); -} - -ATF_TC(x86_xstate_mm_read); -ATF_TC_HEAD(x86_xstate_mm_read, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set MMX (mm0..mm7) reg values from debugged program and read " - "them via PT_GETXSTATE, comparing values against expected."); -} - -ATF_TC_BODY(x86_xstate_mm_read, tc) -{ - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct iovec iov; - struct xstate xst; - - const uint64_t mm[] = { - 0x0001020304050607, - 0x1011121314151617, - 0x2021222324252627, - 0x3031323334353637, - 0x4041424344454647, - 0x5051525354555657, - 0x6061626364656667, - 0x7071727374757677, - }; - - /* verify whether MMX is supported here */ - DPRINTF("Before invoking cpuid\n"); - { - unsigned int eax, ebx, ecx, edx; - if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) - atf_tc_skip("CPUID is not supported by the CPU"); - - DPRINTF("cpuid: EDX = %08x\n", edx); - - if (!(edx & bit_MMX)) - atf_tc_skip("MMX is not supported by the CPU"); - } - - 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 running assembly from child\n"); - set_mm_regs(mm); - - 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); - - iov.iov_base = &xst; - iov.iov_len = sizeof(xst); - - DPRINTF("Call GETXSTATE for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETXSTATE, child, &iov, 0) != -1); - - ATF_REQUIRE(xst.xs_rfbm & XCR0_X87); - ATF_REQUIRE(xst.xs_xstate_bv & XCR0_X87); - - ATF_CHECK_EQ(xst.xs_fxsave.fx_87_ac[0].r.f87_mantissa, mm[0]); - ATF_CHECK_EQ(xst.xs_fxsave.fx_87_ac[1].r.f87_mantissa, mm[1]); - ATF_CHECK_EQ(xst.xs_fxsave.fx_87_ac[2].r.f87_mantissa, mm[2]); - ATF_CHECK_EQ(xst.xs_fxsave.fx_87_ac[3].r.f87_mantissa, mm[3]); - ATF_CHECK_EQ(xst.xs_fxsave.fx_87_ac[4].r.f87_mantissa, mm[4]); - ATF_CHECK_EQ(xst.xs_fxsave.fx_87_ac[5].r.f87_mantissa, mm[5]); - ATF_CHECK_EQ(xst.xs_fxsave.fx_87_ac[6].r.f87_mantissa, mm[6]); - ATF_CHECK_EQ(xst.xs_fxsave.fx_87_ac[7].r.f87_mantissa, mm[7]); - - 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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); -} - -ATF_TC(x86_xstate_mm_write); -ATF_TC_HEAD(x86_xstate_mm_write, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set mm0..mm7 reg values into a debugged program via " - "PT_SETXSTATE and compare the result against expected."); -} - -ATF_TC_BODY(x86_xstate_mm_write, tc) -{ - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct iovec iov; - struct xstate xst; - - const uint64_t mm[] = { - 0x0001020304050607, - 0x1011121314151617, - 0x2021222324252627, - 0x3031323334353637, - 0x4041424344454647, - 0x5051525354555657, - 0x6061626364656667, - 0x7071727374757677, - }; - - /* verify whether MMX is supported here */ - DPRINTF("Before invoking cpuid\n"); - { - unsigned int eax, ebx, ecx, edx; - if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) - atf_tc_skip("CPUID is not supported by the CPU"); - - DPRINTF("cpuid: EDX = %08x\n", edx); - - if (!(edx & bit_MMX)) - atf_tc_skip("MMX is not supported by the CPU"); - } - - DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); - if (child == 0) { - uint64_t v_mm[8]; - - DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); - FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); - - DPRINTF("Before running assembly from child\n"); - get_mm_regs(v_mm); - - DPRINTF("Before comparing results\n"); - FORKEE_ASSERT_EQ(v_mm[0], mm[0]); - FORKEE_ASSERT_EQ(v_mm[1], mm[1]); - FORKEE_ASSERT_EQ(v_mm[2], mm[2]); - FORKEE_ASSERT_EQ(v_mm[3], mm[3]); - FORKEE_ASSERT_EQ(v_mm[4], mm[4]); - FORKEE_ASSERT_EQ(v_mm[5], mm[5]); - FORKEE_ASSERT_EQ(v_mm[6], mm[6]); - FORKEE_ASSERT_EQ(v_mm[7], mm[7]); - - 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); - - iov.iov_base = &xst; - iov.iov_len = sizeof(xst); - - DPRINTF("Call GETXSTATE for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETXSTATE, child, &iov, 0) != -1); - - ATF_REQUIRE(xst.xs_rfbm & XCR0_X87); - - xst.xs_rfbm = XCR0_X87; - xst.xs_xstate_bv = XCR0_X87; - - xst.xs_fxsave.fx_87_ac[0].r.f87_mantissa = mm[0]; - xst.xs_fxsave.fx_87_ac[1].r.f87_mantissa = mm[1]; - xst.xs_fxsave.fx_87_ac[2].r.f87_mantissa = mm[2]; - xst.xs_fxsave.fx_87_ac[3].r.f87_mantissa = mm[3]; - xst.xs_fxsave.fx_87_ac[4].r.f87_mantissa = mm[4]; - xst.xs_fxsave.fx_87_ac[5].r.f87_mantissa = mm[5]; - xst.xs_fxsave.fx_87_ac[6].r.f87_mantissa = mm[6]; - xst.xs_fxsave.fx_87_ac[7].r.f87_mantissa = mm[7]; - - DPRINTF("Call SETXSTATE for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_SETXSTATE, child, &iov, 0) != -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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); -} - -ATF_TC(x86_xstate_xmm_read); -ATF_TC_HEAD(x86_xstate_xmm_read, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set xmm0..xmm15 (..xmm7 on i386) reg values from debugged program " - "and read them via PT_GETXSTATE, comparing values against expected."); -} - -ATF_TC_BODY(x86_xstate_xmm_read, tc) -{ - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct xstate xst; - struct iovec iov; - - const struct { - uint64_t a, b; - } xmm[] __aligned(16) = { - { 0x0706050403020100, 0x0F0E0D0C0B0A0908, }, - { 0x0807060504030201, 0x100F0E0D0C0B0A09, }, - { 0x0908070605040302, 0x11100F0E0D0C0B0A, }, - { 0x0A09080706050403, 0x1211100F0E0D0C0B, }, - { 0x0B0A090807060504, 0x131211100F0E0D0C, }, - { 0x0C0B0A0908070605, 0x14131211100F0E0D, }, - { 0x0D0C0B0A09080706, 0x1514131211100F0E, }, - { 0x0E0D0C0B0A090807, 0x161514131211100F, }, -#if defined(__x86_64__) - { 0x0F0E0D0C0B0A0908, 0x1716151413121110, }, - { 0x100F0E0D0C0B0A09, 0x1817161514131211, }, - { 0x11100F0E0D0C0B0A, 0x1918171615141312, }, - { 0x1211100F0E0D0C0B, 0x1A19181716151413, }, - { 0x131211100F0E0D0C, 0x1B1A191817161514, }, - { 0x14131211100F0E0D, 0x1C1B1A1918171615, }, - { 0x1514131211100F0E, 0x1D1C1B1A19181716, }, - { 0x161514131211100F, 0x1E1D1C1B1A191817, }, -#endif - }; - - /* verify whether SSE is supported here */ - DPRINTF("Before invoking cpuid\n"); - { - unsigned int eax, ebx, ecx, edx; - if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) - atf_tc_skip("CPUID is not supported by the CPU"); - - DPRINTF("cpuid: EDX = %08x\n", edx); - - if (!(edx & bit_SSE)) - atf_tc_skip("SSE is not supported by the CPU"); - } - - 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 running assembly from child\n"); - set_xmm_regs(xmm); - - 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); - - iov.iov_base = &xst; - iov.iov_len = sizeof(xst); - - DPRINTF("Call GETXSTATE for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETXSTATE, child, &iov, 0) != -1); - - ATF_REQUIRE(xst.xs_rfbm & XCR0_SSE); - ATF_REQUIRE(xst.xs_xstate_bv & XCR0_SSE); - - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[0], &xmm[0], sizeof(*xmm))); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[1], &xmm[1], sizeof(*xmm))); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[2], &xmm[2], sizeof(*xmm))); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[3], &xmm[3], sizeof(*xmm))); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[4], &xmm[4], sizeof(*xmm))); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[5], &xmm[5], sizeof(*xmm))); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[6], &xmm[6], sizeof(*xmm))); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[7], &xmm[7], sizeof(*xmm))); -#if defined(__x86_64__) - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[8], &xmm[8], sizeof(*xmm))); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[9], &xmm[9], sizeof(*xmm))); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[10], &xmm[10], sizeof(*xmm))); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[11], &xmm[11], sizeof(*xmm))); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[12], &xmm[12], sizeof(*xmm))); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[13], &xmm[13], sizeof(*xmm))); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[14], &xmm[14], sizeof(*xmm))); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[15], &xmm[15], sizeof(*xmm))); -#endif - - 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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); -} - -ATF_TC(x86_xstate_xmm_write); -ATF_TC_HEAD(x86_xstate_xmm_write, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set xmm0..xmm15 (..xmm7 on i386) reg values into a debugged " - "program via PT_SETXSTATE and compare the result against expected."); -} - -ATF_TC_BODY(x86_xstate_xmm_write, tc) -{ - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct xstate xst; - struct iovec iov; - - const struct { - uint64_t a, b; - } xmm[] __aligned(16) = { - { 0x0706050403020100, 0x0F0E0D0C0B0A0908, }, - { 0x0807060504030201, 0x100F0E0D0C0B0A09, }, - { 0x0908070605040302, 0x11100F0E0D0C0B0A, }, - { 0x0A09080706050403, 0x1211100F0E0D0C0B, }, - { 0x0B0A090807060504, 0x131211100F0E0D0C, }, - { 0x0C0B0A0908070605, 0x14131211100F0E0D, }, - { 0x0D0C0B0A09080706, 0x1514131211100F0E, }, - { 0x0E0D0C0B0A090807, 0x161514131211100F, }, -#if defined(__x86_64__) - { 0x0F0E0D0C0B0A0908, 0x1716151413121110, }, - { 0x100F0E0D0C0B0A09, 0x1817161514131211, }, - { 0x11100F0E0D0C0B0A, 0x1918171615141312, }, - { 0x1211100F0E0D0C0B, 0x1A19181716151413, }, - { 0x131211100F0E0D0C, 0x1B1A191817161514, }, - { 0x14131211100F0E0D, 0x1C1B1A1918171615, }, - { 0x1514131211100F0E, 0x1D1C1B1A19181716, }, - { 0x161514131211100F, 0x1E1D1C1B1A191817, }, -#endif - }; - - /* verify whether SSE is supported here */ - DPRINTF("Before invoking cpuid\n"); - { - unsigned int eax, ebx, ecx, edx; - if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) - atf_tc_skip("CPUID is not supported by the CPU"); - - DPRINTF("cpuid: EDX = %08x\n", edx); - - if (!(edx & bit_SSE)) - atf_tc_skip("SSE is not supported by the CPU"); - } - - DPRINTF("Before forking process PID=%d\n", getpid()); - SYSCALL_REQUIRE((child = fork()) != -1); - if (child == 0) { - struct { - uint64_t a, b; - } v_xmm[16] __aligned(16); - - DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); - FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); - - DPRINTF("Before running assembly from child\n"); - get_xmm_regs(v_xmm); - - DPRINTF("Before comparing results\n"); - FORKEE_ASSERT(!memcmp(&v_xmm[0], &xmm[0], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[1], &xmm[1], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[2], &xmm[2], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[3], &xmm[3], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[4], &xmm[4], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[5], &xmm[5], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[6], &xmm[6], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[7], &xmm[7], sizeof(*xmm))); -#if defined(__x86_64__) - FORKEE_ASSERT(!memcmp(&v_xmm[8], &xmm[8], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[9], &xmm[9], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[10], &xmm[10], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[11], &xmm[11], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[12], &xmm[12], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[13], &xmm[13], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[14], &xmm[14], sizeof(*xmm))); - FORKEE_ASSERT(!memcmp(&v_xmm[15], &xmm[15], sizeof(*xmm))); -#endif - - 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); - - iov.iov_base = &xst; - iov.iov_len = sizeof(xst); - - DPRINTF("Call GETXSTATE for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETXSTATE, child, &iov, 0) != -1); - - ATF_REQUIRE(xst.xs_rfbm & XCR0_SSE); - - xst.xs_rfbm = XCR0_SSE; - xst.xs_xstate_bv = XCR0_SSE; - - memcpy(&xst.xs_fxsave.fx_xmm[0], &xmm[0], sizeof(*xmm)); - memcpy(&xst.xs_fxsave.fx_xmm[1], &xmm[1], sizeof(*xmm)); - memcpy(&xst.xs_fxsave.fx_xmm[2], &xmm[2], sizeof(*xmm)); - memcpy(&xst.xs_fxsave.fx_xmm[3], &xmm[3], sizeof(*xmm)); - memcpy(&xst.xs_fxsave.fx_xmm[4], &xmm[4], sizeof(*xmm)); - memcpy(&xst.xs_fxsave.fx_xmm[5], &xmm[5], sizeof(*xmm)); - memcpy(&xst.xs_fxsave.fx_xmm[6], &xmm[6], sizeof(*xmm)); - memcpy(&xst.xs_fxsave.fx_xmm[7], &xmm[7], sizeof(*xmm)); -#if defined(__x86_64__) - memcpy(&xst.xs_fxsave.fx_xmm[8], &xmm[8], sizeof(*xmm)); - memcpy(&xst.xs_fxsave.fx_xmm[9], &xmm[9], sizeof(*xmm)); - memcpy(&xst.xs_fxsave.fx_xmm[10], &xmm[10], sizeof(*xmm)); - memcpy(&xst.xs_fxsave.fx_xmm[11], &xmm[11], sizeof(*xmm)); - memcpy(&xst.xs_fxsave.fx_xmm[12], &xmm[12], sizeof(*xmm)); - memcpy(&xst.xs_fxsave.fx_xmm[13], &xmm[13], sizeof(*xmm)); - memcpy(&xst.xs_fxsave.fx_xmm[14], &xmm[14], sizeof(*xmm)); - memcpy(&xst.xs_fxsave.fx_xmm[15], &xmm[15], sizeof(*xmm)); + __asm__ __volatile__( + "movq 0x00(%0), %%r8\n\t" + "movq 0x20(%0), %%r9\n\t" + "movq 0x40(%0), %%r10\n\t" + "movq 0x60(%0), %%r11\n\t" + "movq 0x80(%0), %%r12\n\t" + "movq 0xA0(%0), %%r13\n\t" + "movq 0xC0(%0), %%r14\n\t" + "movq 0xE0(%0), %%r15\n\t" + "int3\n\t" + : + : "b"(data) + : "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" + ); +#else + __unreachable(); #endif +} - DPRINTF("Call SETXSTATE for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_SETXSTATE, child, &iov, 0) != -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\n", TWAIT_FNAME); - TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); +__attribute__((target("mmx"))) +static __inline void get_mm_regs(union x86_test_register out[]) +{ + const uint64_t fill = 0x0F0F0F0F0F0F0F0F; - validate_status_exited(status, exitval); + __asm__ __volatile__( + /* fill registers with clobber pattern */ + "movq %1, %%mm0\n\t" + "movq %1, %%mm1\n\t" + "movq %1, %%mm2\n\t" + "movq %1, %%mm3\n\t" + "movq %1, %%mm4\n\t" + "movq %1, %%mm5\n\t" + "movq %1, %%mm6\n\t" + "movq %1, %%mm7\n\t" + "\n\t" + "int3\n\t" + "\n\t" + "movq %%mm0, 0x00(%0)\n\t" + "movq %%mm1, 0x20(%0)\n\t" + "movq %%mm2, 0x40(%0)\n\t" + "movq %%mm3, 0x60(%0)\n\t" + "movq %%mm4, 0x80(%0)\n\t" + "movq %%mm5, 0xA0(%0)\n\t" + "movq %%mm6, 0xC0(%0)\n\t" + "movq %%mm7, 0xE0(%0)\n\t" + : + : "a"(out), "m"(fill) + : "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" + ); +} - DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); +__attribute__((target("mmx"))) +static __inline void set_mm_regs(const union x86_test_register data[]) +{ + __asm__ __volatile__( + "movq 0x00(%0), %%mm0\n\t" + "movq 0x20(%0), %%mm1\n\t" + "movq 0x40(%0), %%mm2\n\t" + "movq 0x60(%0), %%mm3\n\t" + "movq 0x80(%0), %%mm4\n\t" + "movq 0xA0(%0), %%mm5\n\t" + "movq 0xC0(%0), %%mm6\n\t" + "movq 0xE0(%0), %%mm7\n\t" + "int3\n\t" + : + : "b"(data) + : "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" + ); } -__attribute__((target("avx"))) -static __inline void set_ymm_regs(const void* ymm) +__attribute__((target("sse"))) +static __inline void get_xmm_regs(union x86_test_register out[]) { + union x86_test_register fill __aligned(32) = { + .xmm={ 0x0F0F0F0F0F0F0F0F, 0x0F0F0F0F0F0F0F0F } + }; + __asm__ __volatile__( - "vmovaps 0x000(%0), %%ymm0\n\t" - "vmovaps 0x020(%0), %%ymm1\n\t" - "vmovaps 0x040(%0), %%ymm2\n\t" - "vmovaps 0x060(%0), %%ymm3\n\t" - "vmovaps 0x080(%0), %%ymm4\n\t" - "vmovaps 0x0A0(%0), %%ymm5\n\t" - "vmovaps 0x0C0(%0), %%ymm6\n\t" - "vmovaps 0x0E0(%0), %%ymm7\n\t" + /* fill registers with clobber pattern */ + "movaps %1, %%xmm0\n\t" + "movaps %1, %%xmm1\n\t" + "movaps %1, %%xmm2\n\t" + "movaps %1, %%xmm3\n\t" + "movaps %1, %%xmm4\n\t" + "movaps %1, %%xmm5\n\t" + "movaps %1, %%xmm6\n\t" + "movaps %1, %%xmm7\n\t" #if defined(__x86_64__) - "vmovaps 0x100(%0), %%ymm8\n\t" - "vmovaps 0x120(%0), %%ymm9\n\t" - "vmovaps 0x140(%0), %%ymm10\n\t" - "vmovaps 0x160(%0), %%ymm11\n\t" - "vmovaps 0x180(%0), %%ymm12\n\t" - "vmovaps 0x1A0(%0), %%ymm13\n\t" - "vmovaps 0x1C0(%0), %%ymm14\n\t" - "vmovaps 0x1E0(%0), %%ymm15\n\t" + "movaps %1, %%xmm8\n\t" + "movaps %1, %%xmm9\n\t" + "movaps %1, %%xmm10\n\t" + "movaps %1, %%xmm11\n\t" + "movaps %1, %%xmm12\n\t" + "movaps %1, %%xmm13\n\t" + "movaps %1, %%xmm14\n\t" + "movaps %1, %%xmm15\n\t" #endif + "\n\t" "int3\n\t" + "\n\t" + "movaps %%xmm0, 0x000(%0)\n\t" + "movaps %%xmm1, 0x020(%0)\n\t" + "movaps %%xmm2, 0x040(%0)\n\t" + "movaps %%xmm3, 0x060(%0)\n\t" + "movaps %%xmm4, 0x080(%0)\n\t" + "movaps %%xmm5, 0x0A0(%0)\n\t" + "movaps %%xmm6, 0x0C0(%0)\n\t" + "movaps %%xmm7, 0x0E0(%0)\n\t" +#if defined(__x86_64__) + "movaps %%xmm8, 0x100(%0)\n\t" + "movaps %%xmm9, 0x120(%0)\n\t" + "movaps %%xmm10, 0x140(%0)\n\t" + "movaps %%xmm11, 0x160(%0)\n\t" + "movaps %%xmm12, 0x180(%0)\n\t" + "movaps %%xmm13, 0x1A0(%0)\n\t" + "movaps %%xmm14, 0x1C0(%0)\n\t" + "movaps %%xmm15, 0x1E0(%0)\n\t" +#endif : - : "b"(ymm) - : "%ymm0", "%ymm1", "%ymm2", "%ymm3", "%ymm4", "%ymm5", "%ymm6", - "%ymm7" + : "a"(out), "m"(fill) + : "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7" #if defined(__x86_64__) - , "%ymm8", "%ymm9", "%ymm10", "%ymm11", "%ymm12", "%ymm13", - "%ymm14", "%ymm15" + , "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", "%xmm14", + "%xmm15" #endif ); } -ATF_TC(x86_xstate_ymm_read); -ATF_TC_HEAD(x86_xstate_ymm_read, tc) -{ - atf_tc_set_md_var(tc, "descr", - "Set ymm0..ymm15 (..ymm7 on i386) reg values from debugged program " - "and read them via PT_GETXSTATE, comparing values against expected."); -} - -ATF_TC_BODY(x86_xstate_ymm_read, tc) +__attribute__((target("sse"))) +static __inline void set_xmm_regs(const union x86_test_register data[]) { - const int exitval = 5; - pid_t child, wpid; -#if defined(TWAIT_HAVE_STATUS) - const int sigval = SIGTRAP; - int status; -#endif - struct xstate xst; - struct iovec iov; - - const struct { - uint64_t a, b, c, d; - } ymm[] __aligned(32) = { - { 0x0706050403020100, 0x0F0E0D0C0B0A0908, - 0x1716151413121110, 0x1F1E1D1C1B1A1918, }, - { 0x0807060504030201, 0x100F0E0D0C0B0A09, - 0x1817161514131211, 0x201F1E1D1C1B1A19, }, - { 0x0908070605040302, 0x11100F0E0D0C0B0A, - 0x1918171615141312, 0x21201F1E1D1C1B1A, }, - { 0x0A09080706050403, 0x1211100F0E0D0C0B, - 0x1A19181716151413, 0x2221201F1E1D1C1B, }, - { 0x0B0A090807060504, 0x131211100F0E0D0C, - 0x1B1A191817161514, 0x232221201F1E1D1C, }, - { 0x0C0B0A0908070605, 0x14131211100F0E0D, - 0x1C1B1A1918171615, 0x24232221201F1E1D, }, - { 0x0D0C0B0A09080706, 0x1514131211100F0E, - 0x1D1C1B1A19181716, 0x2524232221201F1E, }, - { 0x0E0D0C0B0A090807, 0x161514131211100F, - 0x1E1D1C1B1A191817, 0x262524232221201F, }, + __asm__ __volatile__( + "movaps 0x000(%0), %%xmm0\n\t" + "movaps 0x020(%0), %%xmm1\n\t" + "movaps 0x040(%0), %%xmm2\n\t" + "movaps 0x060(%0), %%xmm3\n\t" + "movaps 0x080(%0), %%xmm4\n\t" + "movaps 0x0A0(%0), %%xmm5\n\t" + "movaps 0x0C0(%0), %%xmm6\n\t" + "movaps 0x0E0(%0), %%xmm7\n\t" #if defined(__x86_64__) - { 0x0F0E0D0C0B0A0908, 0x1716151413121110, - 0x1F1E1D1C1B1A1918, 0x2726252423222120, }, - { 0x100F0E0D0C0B0A09, 0x1817161514131211, - 0x201F1E1D1C1B1A19, 0x2827262524232221, }, - { 0x11100F0E0D0C0B0A, 0x1918171615141312, - 0x21201F1E1D1C1B1A, 0x2928272625242322, }, - { 0x1211100F0E0D0C0B, 0x1A19181716151413, - 0x2221201F1E1D1C1B, 0x2A29282726252423, }, - { 0x131211100F0E0D0C, 0x1B1A191817161514, - 0x232221201F1E1D1C, 0x2B2A292827262524, }, - { 0x14131211100F0E0D, 0x1C1B1A1918171615, - 0x24232221201F1E1D, 0x2C2B2A2928272625, }, - { 0x1514131211100F0E, 0x1D1C1B1A19181716, - 0x2524232221201F1E, 0x2D2C2B2A29282726, }, - { 0x161514131211100F, 0x1E1D1C1B1A191817, - 0x262524232221201F, 0x2E2D2C2B2A292827, }, + "movaps 0x100(%0), %%xmm8\n\t" + "movaps 0x120(%0), %%xmm9\n\t" + "movaps 0x140(%0), %%xmm10\n\t" + "movaps 0x160(%0), %%xmm11\n\t" + "movaps 0x180(%0), %%xmm12\n\t" + "movaps 0x1A0(%0), %%xmm13\n\t" + "movaps 0x1C0(%0), %%xmm14\n\t" + "movaps 0x1E0(%0), %%xmm15\n\t" #endif - }; - - /* verify whether AVX is supported here */ - DPRINTF("Before invoking cpuid\n"); - { - unsigned int eax, ebx, ecx, edx; - if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) - atf_tc_skip("CPUID is not supported by the CPU"); - - DPRINTF("cpuid: ECX = %08x\n", ecx); - - if (!(ecx & bit_AVX)) - atf_tc_skip("AVX is not supported by the CPU"); - } - - 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 running assembly from child\n"); - set_ymm_regs(ymm); - - 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); - - iov.iov_base = &xst; - iov.iov_len = sizeof(xst); - - DPRINTF("Call GETXSTATE for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETXSTATE, child, &iov, 0) != -1); - - ATF_REQUIRE(xst.xs_rfbm & XCR0_SSE); - ATF_REQUIRE(xst.xs_rfbm & XCR0_YMM_Hi128); - ATF_REQUIRE(xst.xs_xstate_bv & XCR0_SSE); - ATF_REQUIRE(xst.xs_xstate_bv & XCR0_YMM_Hi128); - - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[0], &ymm[0].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[0], &ymm[0].c, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[1], &ymm[1].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[1], &ymm[1].c, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[2], &ymm[2].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[2], &ymm[2].c, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[3], &ymm[3].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[3], &ymm[3].c, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[4], &ymm[4].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[4], &ymm[4].c, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[5], &ymm[5].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[5], &ymm[5].c, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[6], &ymm[6].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[6], &ymm[6].c, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[7], &ymm[7].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[7], &ymm[7].c, sizeof(*ymm)/2)); + "int3\n\t" + : + : "b"(data) + : "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", + "%xmm7" #if defined(__x86_64__) - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[8], &ymm[8].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[8], &ymm[8].c, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[9], &ymm[9].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[9], &ymm[9].c, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[10], &ymm[10].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[10], &ymm[10].c, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[11], &ymm[11].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[11], &ymm[11].c, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[12], &ymm[12].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[12], &ymm[12].c, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[13], &ymm[13].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[13], &ymm[13].c, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[14], &ymm[14].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[14], &ymm[14].c, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_fxsave.fx_xmm[15], &ymm[15].a, sizeof(*ymm)/2)); - ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[15], &ymm[15].c, sizeof(*ymm)/2)); + , "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", + "%xmm14", "%xmm15" #endif - - 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\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\n", TWAIT_FNAME); - TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); + ); } __attribute__((target("avx"))) -static __inline void get_ymm_regs(void* v_ymm) +static __inline void get_ymm_regs(union x86_test_register out[]) { - const struct { - uint64_t a, b, c, d; - } fill __aligned(32) = { - 0x0F0F0F0F0F0F0F0F, 0x0F0F0F0F0F0F0F0F, - 0x0F0F0F0F0F0F0F0F, 0x0F0F0F0F0F0F0F0F + union x86_test_register fill __aligned(32) = { + { 0x0F0F0F0F0F0F0F0F, 0x0F0F0F0F0F0F0F0F, + 0x0F0F0F0F0F0F0F0F, 0x0F0F0F0F0F0F0F0F } }; __asm__ __volatile__( @@ -3500,7 +2627,7 @@ static __inline void get_ymm_regs(void* v_ymm) "vmovaps %%ymm15, 0x1E0(%0)\n\t" #endif : - : "a"(v_ymm), "m"(fill) + : "a"(out), "m"(fill) : "%ymm0", "%ymm1", "%ymm2", "%ymm3", "%ymm4", "%ymm5", "%ymm6", "%ymm7" #if defined(__x86_64__) , "%ymm8", "%ymm9", "%ymm10", "%ymm11", "%ymm12", "%ymm13", "%ymm14", @@ -3509,109 +2636,328 @@ static __inline void get_ymm_regs(void* v_ymm) ); } -ATF_TC(x86_xstate_ymm_write); -ATF_TC_HEAD(x86_xstate_ymm_write, tc) +__attribute__((target("avx"))) +static __inline void set_ymm_regs(const union x86_test_register data[]) { - atf_tc_set_md_var(tc, "descr", - "Set ymm0..ymm15 (..ymm7 on i386) reg values into a debugged " - "program via PT_SETXSTATE and compare the result against expected."); + __asm__ __volatile__( + "vmovaps 0x000(%0), %%ymm0\n\t" + "vmovaps 0x020(%0), %%ymm1\n\t" + "vmovaps 0x040(%0), %%ymm2\n\t" + "vmovaps 0x060(%0), %%ymm3\n\t" + "vmovaps 0x080(%0), %%ymm4\n\t" + "vmovaps 0x0A0(%0), %%ymm5\n\t" + "vmovaps 0x0C0(%0), %%ymm6\n\t" + "vmovaps 0x0E0(%0), %%ymm7\n\t" +#if defined(__x86_64__) + "vmovaps 0x100(%0), %%ymm8\n\t" + "vmovaps 0x120(%0), %%ymm9\n\t" + "vmovaps 0x140(%0), %%ymm10\n\t" + "vmovaps 0x160(%0), %%ymm11\n\t" + "vmovaps 0x180(%0), %%ymm12\n\t" + "vmovaps 0x1A0(%0), %%ymm13\n\t" + "vmovaps 0x1C0(%0), %%ymm14\n\t" + "vmovaps 0x1E0(%0), %%ymm15\n\t" +#endif + "int3\n\t" + : + : "b"(data) + : "%ymm0", "%ymm1", "%ymm2", "%ymm3", "%ymm4", "%ymm5", "%ymm6", + "%ymm7" +#if defined(__x86_64__) + , "%ymm8", "%ymm9", "%ymm10", "%ymm11", "%ymm12", "%ymm13", + "%ymm14", "%ymm15" +#endif + ); } -ATF_TC_BODY(x86_xstate_ymm_write, tc) +static void +x86_register_test(enum x86_test_regset regset, enum x86_test_registers regs, + enum x86_test_regmode regmode) { const int exitval = 5; pid_t child, wpid; #if defined(TWAIT_HAVE_STATUS) const int sigval = SIGTRAP; int status; +#endif + struct reg gpr; + struct fpreg fpr; +#if defined(__i386__) + struct xmmregs xmm; #endif struct xstate xst; struct iovec iov; + struct fxsave* fxs; + uint64_t xst_flags = 0; + + const union x86_test_register expected[] __aligned(32) = { + {{ 0x0706050403020100, 0x0F0E0D0C0B0A0908, + 0x1716151413121110, 0x1F1E1D1C1B1A1918, }}, + {{ 0x0807060504030201, 0x100F0E0D0C0B0A09, + 0x1817161514131211, 0x201F1E1D1C1B1A19, }}, + {{ 0x0908070605040302, 0x11100F0E0D0C0B0A, + 0x1918171615141312, 0x21201F1E1D1C1B1A, }}, + {{ 0x0A09080706050403, 0x1211100F0E0D0C0B, + 0x1A19181716151413, 0x2221201F1E1D1C1B, }}, + {{ 0x0B0A090807060504, 0x131211100F0E0D0C, + 0x1B1A191817161514, 0x232221201F1E1D1C, }}, + {{ 0x0C0B0A0908070605, 0x14131211100F0E0D, + 0x1C1B1A1918171615, 0x24232221201F1E1D, }}, + {{ 0x0D0C0B0A09080706, 0x1514131211100F0E, + 0x1D1C1B1A19181716, 0x2524232221201F1E, }}, + {{ 0x0E0D0C0B0A090807, 0x161514131211100F, + 0x1E1D1C1B1A191817, 0x262524232221201F, }}, + {{ 0x0F0E0D0C0B0A0908, 0x1716151413121110, + 0x1F1E1D1C1B1A1918, 0x2726252423222120, }}, + {{ 0x100F0E0D0C0B0A09, 0x1817161514131211, + 0x201F1E1D1C1B1A19, 0x2827262524232221, }}, + {{ 0x11100F0E0D0C0B0A, 0x1918171615141312, + 0x21201F1E1D1C1B1A, 0x2928272625242322, }}, + {{ 0x1211100F0E0D0C0B, 0x1A19181716151413, + 0x2221201F1E1D1C1B, 0x2A29282726252423, }}, + {{ 0x131211100F0E0D0C, 0x1B1A191817161514, + 0x232221201F1E1D1C, 0x2B2A292827262524, }}, + {{ 0x14131211100F0E0D, 0x1C1B1A1918171615, + 0x24232221201F1E1D, 0x2C2B2A2928272625, }}, + {{ 0x1514131211100F0E, 0x1D1C1B1A19181716, + 0x2524232221201F1E, 0x2D2C2B2A29282726, }}, + {{ 0x161514131211100F, 0x1E1D1C1B1A191817, + 0x262524232221201F, 0x2E2D2C2B2A292827, }}, + }; - const struct { - uint64_t a, b, c, d; - } ymm[] __aligned(32) = { - { 0x0706050403020100, 0x0F0E0D0C0B0A0908, - 0x1716151413121110, 0x1F1E1D1C1B1A1918, }, - { 0x0807060504030201, 0x100F0E0D0C0B0A09, - 0x1817161514131211, 0x201F1E1D1C1B1A19, }, - { 0x0908070605040302, 0x11100F0E0D0C0B0A, - 0x1918171615141312, 0x21201F1E1D1C1B1A, }, - { 0x0A09080706050403, 0x1211100F0E0D0C0B, - 0x1A19181716151413, 0x2221201F1E1D1C1B, }, - { 0x0B0A090807060504, 0x131211100F0E0D0C, - 0x1B1A191817161514, 0x232221201F1E1D1C, }, - { 0x0C0B0A0908070605, 0x14131211100F0E0D, - 0x1C1B1A1918171615, 0x24232221201F1E1D, }, - { 0x0D0C0B0A09080706, 0x1514131211100F0E, - 0x1D1C1B1A19181716, 0x2524232221201F1E, }, - { 0x0E0D0C0B0A090807, 0x161514131211100F, - 0x1E1D1C1B1A191817, 0x262524232221201F, }, + bool need_32 = false, need_64 = false, need_cpuid = false; + + switch (regs) { + case GPREGS_32: + case GPREGS_32_EBP_ESP: + need_32 = true; + break; + case GPREGS_64: + case GPREGS_64_R8: + need_64 = true; + break; + case FPREGS_MM: + case FPREGS_XMM: + case FPREGS_YMM: + need_cpuid = true; + break; + } + + if (need_32) { #if defined(__x86_64__) - { 0x0F0E0D0C0B0A0908, 0x1716151413121110, - 0x1F1E1D1C1B1A1918, 0x2726252423222120, }, - { 0x100F0E0D0C0B0A09, 0x1817161514131211, - 0x201F1E1D1C1B1A19, 0x2827262524232221, }, - { 0x11100F0E0D0C0B0A, 0x1918171615141312, - 0x21201F1E1D1C1B1A, 0x2928272625242322, }, - { 0x1211100F0E0D0C0B, 0x1A19181716151413, - 0x2221201F1E1D1C1B, 0x2A29282726252423, }, - { 0x131211100F0E0D0C, 0x1B1A191817161514, - 0x232221201F1E1D1C, 0x2B2A292827262524, }, - { 0x14131211100F0E0D, 0x1C1B1A1918171615, - 0x24232221201F1E1D, 0x2C2B2A2928272625, }, - { 0x1514131211100F0E, 0x1D1C1B1A19181716, - 0x2524232221201F1E, 0x2D2C2B2A29282726, }, - { 0x161514131211100F, 0x1E1D1C1B1A191817, - 0x262524232221201F, 0x2E2D2C2B2A292827, }, + atf_tc_skip("Test requires 32-bit mode"); #endif - }; + } + if (need_64) { +#if defined(__i386__) + atf_tc_skip("Test requires 64-bit mode"); +#endif + } - /* verify whether AVX is supported here */ - DPRINTF("Before invoking cpuid\n"); - { + if (need_cpuid) { + /* verify whether needed instruction sets are supported here */ unsigned int eax, ebx, ecx, edx; + + DPRINTF("Before invoking cpuid\n"); if (!__get_cpuid(1, &eax, &ebx, &ecx, &edx)) atf_tc_skip("CPUID is not supported by the CPU"); - DPRINTF("cpuid: ECX = %08x\n", ecx); - - if (!(ecx & bit_AVX)) - atf_tc_skip("AVX is not supported by the CPU"); + DPRINTF("cpuid: ECX = %08x, EDX = %08xd\n", ecx, edx); + + switch (regs) { + case FPREGS_YMM: + if (!(ecx & bit_AVX)) + atf_tc_skip("AVX is not supported by the CPU"); + /*FALLTHROUGH*/ + case FPREGS_XMM: + if (!(edx & bit_SSE)) + atf_tc_skip("SSE is not supported by the CPU"); + break; + case FPREGS_MM: + if (!(edx & bit_MMX)) + atf_tc_skip("MMX is not supported by the CPU"); + break; + case GPREGS_32: + case GPREGS_32_EBP_ESP: + case GPREGS_64: + case GPREGS_64_R8: + __unreachable(); + } } DPRINTF("Before forking process PID=%d\n", getpid()); SYSCALL_REQUIRE((child = fork()) != -1); if (child == 0) { - struct { - uint64_t a, b, c, d; - } v_ymm[16] __aligned(32); + union x86_test_register vals[16] __aligned(32); DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); DPRINTF("Before running assembly from child\n"); - get_ymm_regs(v_ymm); - - DPRINTF("Before comparing results\n"); - FORKEE_ASSERT(!memcmp(&v_ymm[0], &ymm[0], sizeof(*ymm))); - FORKEE_ASSERT(!memcmp(&v_ymm[1], &ymm[1], sizeof(*ymm))); - FORKEE_ASSERT(!memcmp(&v_ymm[2], &ymm[2], sizeof(*ymm))); - FORKEE_ASSERT(!memcmp(&v_ymm[3], &ymm[3], sizeof(*ymm))); - FORKEE_ASSERT(!memcmp(&v_ymm[4], &ymm[4], sizeof(*ymm))); - FORKEE_ASSERT(!memcmp(&v_ymm[5], &ymm[5], sizeof(*ymm))); - FORKEE_ASSERT(!memcmp(&v_ymm[6], &ymm[6], sizeof(*ymm))); - FORKEE_ASSERT(!memcmp(&v_ymm[7], &ymm[7], sizeof(*ymm))); + switch (regmode) { + case TEST_GETREGS: + switch (regs) { + case GPREGS_32: + set_gp32_regs(expected); + break; + case GPREGS_32_EBP_ESP: + set_gp32_ebp_esp_regs(expected); + break; + case GPREGS_64: + set_gp64_regs(expected); + break; + case GPREGS_64_R8: + set_gp64_r8_regs(expected); + break; + case FPREGS_MM: + set_mm_regs(expected); + break; + case FPREGS_XMM: + set_xmm_regs(expected); + break; + case FPREGS_YMM: + set_ymm_regs(expected); + break; + } + break; + case TEST_SETREGS: + switch (regs) { + case GPREGS_32: + get_gp32_regs(vals); + break; + case GPREGS_32_EBP_ESP: + get_gp32_ebp_esp_regs(vals); + break; + case GPREGS_64: + get_gp64_regs(vals); + break; + case GPREGS_64_R8: + get_gp64_r8_regs(vals); + break; + case FPREGS_MM: + get_mm_regs(vals); + break; + case FPREGS_XMM: + get_xmm_regs(vals); + break; + case FPREGS_YMM: + get_ymm_regs(vals); + break; + } + + DPRINTF("Before comparing results\n"); + switch (regs) { + case GPREGS_32: + FORKEE_ASSERT(!memcmp(&vals[5].u32, + &expected[5].u32, sizeof(vals->u32))); + FORKEE_ASSERT(!memcmp(&vals[4].u32, + &expected[4].u32, sizeof(vals->u32))); + FORKEE_ASSERT(!memcmp(&vals[3].u32, + &expected[3].u32, sizeof(vals->u32))); + FORKEE_ASSERT(!memcmp(&vals[2].u32, + &expected[2].u32, sizeof(vals->u32))); + /*FALLTHROUGH*/ + case GPREGS_32_EBP_ESP: + FORKEE_ASSERT(!memcmp(&vals[1].u32, + &expected[1].u32, sizeof(vals->u32))); + FORKEE_ASSERT(!memcmp(&vals[0].u32, + &expected[0].u32, sizeof(vals->u32))); + break; + case GPREGS_64: + case GPREGS_64_R8: + case FPREGS_MM: + FORKEE_ASSERT(!memcmp(&vals[0].u64, + &expected[0].u64, sizeof(vals->u64))); + FORKEE_ASSERT(!memcmp(&vals[1].u64, + &expected[1].u64, sizeof(vals->u64))); + FORKEE_ASSERT(!memcmp(&vals[2].u64, + &expected[2].u64, sizeof(vals->u64))); + FORKEE_ASSERT(!memcmp(&vals[3].u64, + &expected[3].u64, sizeof(vals->u64))); + FORKEE_ASSERT(!memcmp(&vals[4].u64, + &expected[4].u64, sizeof(vals->u64))); + FORKEE_ASSERT(!memcmp(&vals[5].u64, + &expected[5].u64, sizeof(vals->u64))); + FORKEE_ASSERT(!memcmp(&vals[6].u64, + &expected[6].u64, sizeof(vals->u64))); + FORKEE_ASSERT(!memcmp(&vals[7].u64, + &expected[7].u64, sizeof(vals->u64))); + break; + case FPREGS_XMM: + FORKEE_ASSERT(!memcmp(&vals[0].xmm, + &expected[0].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT(!memcmp(&vals[1].xmm, + &expected[1].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT(!memcmp(&vals[2].xmm, + &expected[2].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT(!memcmp(&vals[3].xmm, + &expected[3].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT(!memcmp(&vals[4].xmm, + &expected[4].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT(!memcmp(&vals[5].xmm, + &expected[5].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT(!memcmp(&vals[6].xmm, + &expected[6].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT(!memcmp(&vals[7].xmm, + &expected[7].xmm, sizeof(vals->xmm))); +#if defined(__x86_64__) + FORKEE_ASSERT(!memcmp(&vals[8].xmm, + &expected[8].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT(!memcmp(&vals[9].xmm, + &expected[9].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT(!memcmp(&vals[10].xmm, + &expected[10].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT(!memcmp(&vals[11].xmm, + &expected[11].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT(!memcmp(&vals[12].xmm, + &expected[12].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT(!memcmp(&vals[13].xmm, + &expected[13].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT(!memcmp(&vals[14].xmm, + &expected[14].xmm, sizeof(vals->xmm))); + FORKEE_ASSERT(!memcmp(&vals[15].xmm, + &expected[15].xmm, sizeof(vals->xmm))); +#endif + break; + case FPREGS_YMM: + FORKEE_ASSERT(!memcmp(&vals[0].ymm, + &expected[0].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT(!memcmp(&vals[1].ymm, + &expected[1].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT(!memcmp(&vals[2].ymm, + &expected[2].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT(!memcmp(&vals[3].ymm, + &expected[3].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT(!memcmp(&vals[4].ymm, + &expected[4].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT(!memcmp(&vals[5].ymm, + &expected[5].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT(!memcmp(&vals[6].ymm, + &expected[6].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT(!memcmp(&vals[7].ymm, + &expected[7].ymm, sizeof(vals->ymm))); #if defined(__x86_64__) - FORKEE_ASSERT(!memcmp(&v_ymm[8], &ymm[8], sizeof(*ymm))); - FORKEE_ASSERT(!memcmp(&v_ymm[9], &ymm[9], sizeof(*ymm))); - FORKEE_ASSERT(!memcmp(&v_ymm[10], &ymm[10], sizeof(*ymm))); - FORKEE_ASSERT(!memcmp(&v_ymm[11], &ymm[11], sizeof(*ymm))); - FORKEE_ASSERT(!memcmp(&v_ymm[12], &ymm[12], sizeof(*ymm))); - FORKEE_ASSERT(!memcmp(&v_ymm[13], &ymm[13], sizeof(*ymm))); - FORKEE_ASSERT(!memcmp(&v_ymm[14], &ymm[14], sizeof(*ymm))); - FORKEE_ASSERT(!memcmp(&v_ymm[15], &ymm[15], sizeof(*ymm))); + FORKEE_ASSERT(!memcmp(&vals[8].ymm, + &expected[8].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT(!memcmp(&vals[9].ymm, + &expected[9].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT(!memcmp(&vals[10].ymm, + &expected[10].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT(!memcmp(&vals[11].ymm, + &expected[11].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT(!memcmp(&vals[12].ymm, + &expected[12].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT(!memcmp(&vals[13].ymm, + &expected[13].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT(!memcmp(&vals[14].ymm, + &expected[14].ymm, sizeof(vals->ymm))); + FORKEE_ASSERT(!memcmp(&vals[15].ymm, + &expected[15].ymm, sizeof(vals->ymm))); #endif + break; + } + break; + } DPRINTF("Before exiting of the child process\n"); _exit(exitval); @@ -3623,55 +2969,417 @@ ATF_TC_BODY(x86_xstate_ymm_write, tc) validate_status_stopped(status, sigval); - iov.iov_base = &xst; - iov.iov_len = sizeof(xst); - - DPRINTF("Call GETXSTATE for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_GETXSTATE, child, &iov, 0) != -1); - - ATF_REQUIRE(xst.xs_rfbm & XCR0_SSE); - ATF_REQUIRE(xst.xs_rfbm & XCR0_YMM_Hi128); - - xst.xs_rfbm = XCR0_SSE | XCR0_YMM_Hi128; - xst.xs_xstate_bv = XCR0_SSE | XCR0_YMM_Hi128; - - memcpy(&xst.xs_fxsave.fx_xmm[0], &ymm[0].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[0], &ymm[0].c, sizeof(*ymm)/2); - memcpy(&xst.xs_fxsave.fx_xmm[1], &ymm[1].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[1], &ymm[1].c, sizeof(*ymm)/2); - memcpy(&xst.xs_fxsave.fx_xmm[2], &ymm[2].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[2], &ymm[2].c, sizeof(*ymm)/2); - memcpy(&xst.xs_fxsave.fx_xmm[3], &ymm[3].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[3], &ymm[3].c, sizeof(*ymm)/2); - memcpy(&xst.xs_fxsave.fx_xmm[4], &ymm[4].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[4], &ymm[4].c, sizeof(*ymm)/2); - memcpy(&xst.xs_fxsave.fx_xmm[5], &ymm[5].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[5], &ymm[5].c, sizeof(*ymm)/2); - memcpy(&xst.xs_fxsave.fx_xmm[6], &ymm[6].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[6], &ymm[6].c, sizeof(*ymm)/2); - memcpy(&xst.xs_fxsave.fx_xmm[7], &ymm[7].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[7], &ymm[7].c, sizeof(*ymm)/2); + switch (regset) { + case TEST_GPREGS: + ATF_REQUIRE(regs < FPREGS_MM); + DPRINTF("Call GETREGS for the child process\n"); + SYSCALL_REQUIRE(ptrace(PT_GETREGS, child, &gpr, 0) != -1); + break; + case TEST_XMMREGS: +#if defined(__i386__) + ATF_REQUIRE(regs >= FPREGS_MM && regs < FPREGS_YMM); + DPRINTF("Call GETXMMREGS for the child process\n"); + SYSCALL_REQUIRE(ptrace(PT_GETXMMREGS, child, &xmm, 0) != -1); + fxs = &xmm.fxstate; + break; +#else + /*FALLTHROUGH*/ +#endif + case TEST_FPREGS: +#if defined(__x86_64__) + ATF_REQUIRE(regs >= FPREGS_MM && regs < FPREGS_YMM); + fxs = &fpr.fxstate; +#else + ATF_REQUIRE(regs >= FPREGS_MM && regs < FPREGS_XMM); +#endif + DPRINTF("Call GETFPREGS for the child process\n"); + SYSCALL_REQUIRE(ptrace(PT_GETFPREGS, child, &fpr, 0) != -1); + break; + case TEST_XSTATE: + ATF_REQUIRE(regs >= FPREGS_MM); + iov.iov_base = &xst; + iov.iov_len = sizeof(xst); + + DPRINTF("Call GETXSTATE for the child process\n"); + SYSCALL_REQUIRE(ptrace(PT_GETXSTATE, child, &iov, 0) != -1); + + switch (regs) { + case FPREGS_MM: + xst_flags |= XCR0_X87; + break; + case FPREGS_YMM: + xst_flags |= XCR0_YMM_Hi128; + /*FALLTHROUGH*/ + case FPREGS_XMM: + xst_flags |= XCR0_SSE; + break; + case GPREGS_32: + case GPREGS_32_EBP_ESP: + case GPREGS_64: + case GPREGS_64_R8: + __unreachable(); + break; + } + + ATF_REQUIRE((xst.xs_rfbm & xst_flags) == xst_flags); + switch (regmode) { + case TEST_SETREGS: + xst.xs_rfbm = xst_flags; + xst.xs_xstate_bv = xst_flags; + break; + case TEST_GETREGS: + ATF_REQUIRE((xst.xs_xstate_bv & xst_flags) + == xst_flags); + break; + } + + fxs = &xst.xs_fxsave; + break; + } + +#if defined(__x86_64__) +#define MM_REG(n) fpr.fxstate.fx_87_ac[n].r.f87_mantissa +#else +#define MM_REG(n) fpr.fstate.s87_ac[n].f87_mantissa +#endif + + switch (regmode) { + case TEST_GETREGS: + switch (regs) { + case GPREGS_32: +#if defined(__i386__) + ATF_CHECK_EQ((uint32_t)gpr.r_eax, expected[0].u32); + ATF_CHECK_EQ((uint32_t)gpr.r_ebx, expected[1].u32); + ATF_CHECK_EQ((uint32_t)gpr.r_ecx, expected[2].u32); + ATF_CHECK_EQ((uint32_t)gpr.r_edx, expected[3].u32); + ATF_CHECK_EQ((uint32_t)gpr.r_esi, expected[4].u32); + ATF_CHECK_EQ((uint32_t)gpr.r_edi, expected[5].u32); +#endif + break; + case GPREGS_32_EBP_ESP: +#if defined(__i386__) + ATF_CHECK_EQ((uint32_t)gpr.r_esp, expected[0].u32); + ATF_CHECK_EQ((uint32_t)gpr.r_ebp, expected[1].u32); +#endif + break; + case GPREGS_64: +#if defined(__x86_64__) + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RAX], + expected[0].u64); + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RBX], + expected[1].u64); + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RCX], + expected[2].u64); + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RDX], + expected[3].u64); + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RSI], + expected[4].u64); + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RDI], + expected[5].u64); + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RSP], + expected[6].u64); + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_RBP], + expected[7].u64); +#endif + break; + case GPREGS_64_R8: +#if defined(__x86_64__) + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R8], + expected[0].u64); + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R9], + expected[1].u64); + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R10], + expected[2].u64); + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R11], + expected[3].u64); + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R12], + expected[4].u64); + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R13], + expected[5].u64); + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R14], + expected[6].u64); + ATF_CHECK_EQ((uint64_t)gpr.regs[_REG_R15], + expected[7].u64); +#endif + break; + case FPREGS_MM: + if (regset == TEST_FPREGS) { + ATF_CHECK_EQ(MM_REG(0), expected[0].u64); + ATF_CHECK_EQ(MM_REG(1), expected[1].u64); + ATF_CHECK_EQ(MM_REG(2), expected[2].u64); + ATF_CHECK_EQ(MM_REG(3), expected[3].u64); + ATF_CHECK_EQ(MM_REG(4), expected[4].u64); + ATF_CHECK_EQ(MM_REG(5), expected[5].u64); + ATF_CHECK_EQ(MM_REG(6), expected[6].u64); + ATF_CHECK_EQ(MM_REG(7), expected[7].u64); + } else { + ATF_CHECK_EQ(fxs->fx_87_ac[0].r.f87_mantissa, + expected[0].u64); + ATF_CHECK_EQ(fxs->fx_87_ac[1].r.f87_mantissa, + expected[1].u64); + ATF_CHECK_EQ(fxs->fx_87_ac[2].r.f87_mantissa, + expected[2].u64); + ATF_CHECK_EQ(fxs->fx_87_ac[3].r.f87_mantissa, + expected[3].u64); + ATF_CHECK_EQ(fxs->fx_87_ac[4].r.f87_mantissa, + expected[4].u64); + ATF_CHECK_EQ(fxs->fx_87_ac[5].r.f87_mantissa, + expected[5].u64); + ATF_CHECK_EQ(fxs->fx_87_ac[6].r.f87_mantissa, + expected[6].u64); + ATF_CHECK_EQ(fxs->fx_87_ac[7].r.f87_mantissa, + expected[7].u64); + } + break; + case FPREGS_YMM: + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[0], + &expected[0].ymm.c, sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[1], + &expected[1].ymm.c, sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[2], + &expected[2].ymm.c, sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[3], + &expected[3].ymm.c, sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[4], + &expected[4].ymm.c, sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[5], + &expected[5].ymm.c, sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[6], + &expected[6].ymm.c, sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[7], + &expected[7].ymm.c, sizeof(expected->ymm)/2)); +#if defined(__x86_64__) + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[8], + &expected[8].ymm.c, sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[9], + &expected[9].ymm.c, sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[10], + &expected[10].ymm.c, sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[11], + &expected[11].ymm.c, sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[12], + &expected[12].ymm.c, sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[13], + &expected[13].ymm.c, sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[14], + &expected[14].ymm.c, sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&xst.xs_ymm_hi128.xs_ymm[15], + &expected[15].ymm.c, sizeof(expected->ymm)/2)); +#endif + /*FALLTHROUGH*/ + case FPREGS_XMM: + ATF_CHECK(!memcmp(&fxs->fx_xmm[0], &expected[0].ymm.a, + sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&fxs->fx_xmm[1], &expected[1].ymm.a, + sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&fxs->fx_xmm[2], &expected[2].ymm.a, + sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&fxs->fx_xmm[3], &expected[3].ymm.a, + sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&fxs->fx_xmm[4], &expected[4].ymm.a, + sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&fxs->fx_xmm[5], &expected[5].ymm.a, + sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&fxs->fx_xmm[6], &expected[6].ymm.a, + sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&fxs->fx_xmm[7], &expected[7].ymm.a, + sizeof(expected->ymm)/2)); +#if defined(__x86_64__) + ATF_CHECK(!memcmp(&fxs->fx_xmm[8], &expected[8].ymm.a, + sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&fxs->fx_xmm[9], &expected[9].ymm.a, + sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&fxs->fx_xmm[10], &expected[10].ymm.a, + sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&fxs->fx_xmm[11], &expected[11].ymm.a, + sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&fxs->fx_xmm[12], &expected[12].ymm.a, + sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&fxs->fx_xmm[13], &expected[13].ymm.a, + sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&fxs->fx_xmm[14], &expected[14].ymm.a, + sizeof(expected->ymm)/2)); + ATF_CHECK(!memcmp(&fxs->fx_xmm[15], &expected[15].ymm.a, + sizeof(expected->ymm)/2)); +#endif + break; + } + break; + case TEST_SETREGS: + switch (regs) { + case GPREGS_32: +#if defined(__i386__) + gpr.r_eax = expected[0].u32; + gpr.r_ebx = expected[1].u32; + gpr.r_ecx = expected[2].u32; + gpr.r_edx = expected[3].u32; + gpr.r_esi = expected[4].u32; + gpr.r_edi = expected[5].u32; +#endif + break; + case GPREGS_32_EBP_ESP: +#if defined(__i386__) + gpr.r_esp = expected[0].u32; + gpr.r_ebp = expected[1].u32; +#endif + break; + case GPREGS_64: +#if defined(__x86_64__) + gpr.regs[_REG_RAX] = expected[0].u64; + gpr.regs[_REG_RBX] = expected[1].u64; + gpr.regs[_REG_RCX] = expected[2].u64; + gpr.regs[_REG_RDX] = expected[3].u64; + gpr.regs[_REG_RSI] = expected[4].u64; + gpr.regs[_REG_RDI] = expected[5].u64; + gpr.regs[_REG_RSP] = expected[6].u64; + gpr.regs[_REG_RBP] = expected[7].u64; +#endif + break; + case GPREGS_64_R8: +#if defined(__x86_64__) + gpr.regs[_REG_R8] = expected[0].u64; + gpr.regs[_REG_R9] = expected[1].u64; + gpr.regs[_REG_R10] = expected[2].u64; + gpr.regs[_REG_R11] = expected[3].u64; + gpr.regs[_REG_R12] = expected[4].u64; + gpr.regs[_REG_R13] = expected[5].u64; + gpr.regs[_REG_R14] = expected[6].u64; + gpr.regs[_REG_R15] = expected[7].u64; +#endif + break; + case FPREGS_MM: + if (regset == TEST_FPREGS) { + MM_REG(0) = expected[0].u64; + MM_REG(1) = expected[1].u64; + MM_REG(2) = expected[2].u64; + MM_REG(3) = expected[3].u64; + MM_REG(4) = expected[4].u64; + MM_REG(5) = expected[5].u64; + MM_REG(6) = expected[6].u64; + MM_REG(7) = expected[7].u64; + } else { + fxs->fx_87_ac[0].r.f87_mantissa = + expected[0].u64; + fxs->fx_87_ac[1].r.f87_mantissa = + expected[1].u64; + fxs->fx_87_ac[2].r.f87_mantissa = + expected[2].u64; + fxs->fx_87_ac[3].r.f87_mantissa = + expected[3].u64; + fxs->fx_87_ac[4].r.f87_mantissa = + expected[4].u64; + fxs->fx_87_ac[5].r.f87_mantissa = + expected[5].u64; + fxs->fx_87_ac[6].r.f87_mantissa = + expected[6].u64; + fxs->fx_87_ac[7].r.f87_mantissa = + expected[7].u64; + } + break; + case FPREGS_YMM: + memcpy(&xst.xs_ymm_hi128.xs_ymm[0], + &expected[0].ymm.c, sizeof(expected->ymm)/2); + memcpy(&xst.xs_ymm_hi128.xs_ymm[1], + &expected[1].ymm.c, sizeof(expected->ymm)/2); + memcpy(&xst.xs_ymm_hi128.xs_ymm[2], + &expected[2].ymm.c, sizeof(expected->ymm)/2); + memcpy(&xst.xs_ymm_hi128.xs_ymm[3], + &expected[3].ymm.c, sizeof(expected->ymm)/2); + memcpy(&xst.xs_ymm_hi128.xs_ymm[4], + &expected[4].ymm.c, sizeof(expected->ymm)/2); + memcpy(&xst.xs_ymm_hi128.xs_ymm[5], + &expected[5].ymm.c, sizeof(expected->ymm)/2); + memcpy(&xst.xs_ymm_hi128.xs_ymm[6], + &expected[6].ymm.c, sizeof(expected->ymm)/2); + memcpy(&xst.xs_ymm_hi128.xs_ymm[7], + &expected[7].ymm.c, sizeof(expected->ymm)/2); +#if defined(__x86_64__) + memcpy(&xst.xs_ymm_hi128.xs_ymm[8], + &expected[8].ymm.c, sizeof(expected->ymm)/2); + memcpy(&xst.xs_ymm_hi128.xs_ymm[9], + &expected[9].ymm.c, sizeof(expected->ymm)/2); + memcpy(&xst.xs_ymm_hi128.xs_ymm[10], + &expected[10].ymm.c, sizeof(expected->ymm)/2); + memcpy(&xst.xs_ymm_hi128.xs_ymm[11], + &expected[11].ymm.c, sizeof(expected->ymm)/2); + memcpy(&xst.xs_ymm_hi128.xs_ymm[12], + &expected[12].ymm.c, sizeof(expected->ymm)/2); + memcpy(&xst.xs_ymm_hi128.xs_ymm[13], + &expected[13].ymm.c, sizeof(expected->ymm)/2); + memcpy(&xst.xs_ymm_hi128.xs_ymm[14], + &expected[14].ymm.c, sizeof(expected->ymm)/2); + memcpy(&xst.xs_ymm_hi128.xs_ymm[15], + &expected[15].ymm.c, sizeof(expected->ymm)/2); +#endif + /*FALLTHROUGH*/ + case FPREGS_XMM: + memcpy(&fxs->fx_xmm[0], &expected[0].ymm.a, + sizeof(expected->ymm)/2); + memcpy(&fxs->fx_xmm[1], &expected[1].ymm.a, + sizeof(expected->ymm)/2); + memcpy(&fxs->fx_xmm[2], &expected[2].ymm.a, + sizeof(expected->ymm)/2); + memcpy(&fxs->fx_xmm[3], &expected[3].ymm.a, + sizeof(expected->ymm)/2); + memcpy(&fxs->fx_xmm[4], &expected[4].ymm.a, + sizeof(expected->ymm)/2); + memcpy(&fxs->fx_xmm[5], &expected[5].ymm.a, + sizeof(expected->ymm)/2); + memcpy(&fxs->fx_xmm[6], &expected[6].ymm.a, + sizeof(expected->ymm)/2); + memcpy(&fxs->fx_xmm[7], &expected[7].ymm.a, + sizeof(expected->ymm)/2); #if defined(__x86_64__) - memcpy(&xst.xs_fxsave.fx_xmm[8], &ymm[8].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[8], &ymm[8].c, sizeof(*ymm)/2); - memcpy(&xst.xs_fxsave.fx_xmm[9], &ymm[9].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[9], &ymm[9].c, sizeof(*ymm)/2); - memcpy(&xst.xs_fxsave.fx_xmm[10], &ymm[10].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[10], &ymm[10].c, sizeof(*ymm)/2); - memcpy(&xst.xs_fxsave.fx_xmm[11], &ymm[11].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[11], &ymm[11].c, sizeof(*ymm)/2); - memcpy(&xst.xs_fxsave.fx_xmm[12], &ymm[12].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[12], &ymm[12].c, sizeof(*ymm)/2); - memcpy(&xst.xs_fxsave.fx_xmm[13], &ymm[13].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[13], &ymm[13].c, sizeof(*ymm)/2); - memcpy(&xst.xs_fxsave.fx_xmm[14], &ymm[14].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[14], &ymm[14].c, sizeof(*ymm)/2); - memcpy(&xst.xs_fxsave.fx_xmm[15], &ymm[15].a, sizeof(*ymm)/2); - memcpy(&xst.xs_ymm_hi128.xs_ymm[15], &ymm[15].c, sizeof(*ymm)/2); + memcpy(&fxs->fx_xmm[8], &expected[8].ymm.a, + sizeof(expected->ymm)/2); + memcpy(&fxs->fx_xmm[9], &expected[9].ymm.a, + sizeof(expected->ymm)/2); + memcpy(&fxs->fx_xmm[10], &expected[10].ymm.a, + sizeof(expected->ymm)/2); + memcpy(&fxs->fx_xmm[11], &expected[11].ymm.a, + sizeof(expected->ymm)/2); + memcpy(&fxs->fx_xmm[12], &expected[12].ymm.a, + sizeof(expected->ymm)/2); + memcpy(&fxs->fx_xmm[13], &expected[13].ymm.a, + sizeof(expected->ymm)/2); + memcpy(&fxs->fx_xmm[14], &expected[14].ymm.a, + sizeof(expected->ymm)/2); + memcpy(&fxs->fx_xmm[15], &expected[15].ymm.a, + sizeof(expected->ymm)/2); +#endif + break; + } + + switch (regset) { + case TEST_GPREGS: + DPRINTF("Call SETREGS for the child process\n"); + SYSCALL_REQUIRE(ptrace(PT_SETREGS, child, &gpr, 0) + != -1); + break; + case TEST_XMMREGS: +#if defined(__i386__) + DPRINTF("Call SETXMMREGS for the child process\n"); + SYSCALL_REQUIRE(ptrace(PT_SETXMMREGS, child, &xmm, 0) + != -1); + break; +#else + /*FALLTHROUGH*/ #endif + case TEST_FPREGS: + DPRINTF("Call SETFPREGS for the child process\n"); + SYSCALL_REQUIRE(ptrace(PT_SETFPREGS, child, &fpr, 0) + != -1); + break; + case TEST_XSTATE: + DPRINTF("Call SETXSTATE for the child process\n"); + SYSCALL_REQUIRE(ptrace(PT_SETXSTATE, child, &iov, 0) + != -1); + break; + } + break; + } - DPRINTF("Call SETXSTATE for the child process\n"); - SYSCALL_REQUIRE(ptrace(PT_SETXSTATE, child, &iov, 0) != -1); +#undef MM_REG DPRINTF("Before resuming the child process where it left off and " "without signal to be sent\n"); @@ -3686,6 +3394,75 @@ ATF_TC_BODY(x86_xstate_ymm_write, tc) TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); } +#define X86_REGISTER_TEST(test, regset, regs, regmode, descr) \ +ATF_TC(test); \ +ATF_TC_HEAD(test, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", descr); \ +} \ + \ +ATF_TC_BODY(test, tc) \ +{ \ + x86_register_test(regset, regs, regmode); \ +} + +X86_REGISTER_TEST(x86_gpregs32_read, TEST_GPREGS, GPREGS_32, TEST_GETREGS, + "Test reading basic 32-bit gp registers from debugged program " + "via PT_GETREGS."); +X86_REGISTER_TEST(x86_gpregs32_write, TEST_GPREGS, GPREGS_32, TEST_SETREGS, + "Test writing basic 32-bit gp registers into debugged program " + "via PT_SETREGS."); +X86_REGISTER_TEST(x86_gpregs32_ebp_esp_read, TEST_GPREGS, GPREGS_32_EBP_ESP, + TEST_GETREGS, "Test reading ebp & esp registers from debugged program " + "via PT_GETREGS."); +X86_REGISTER_TEST(x86_gpregs32_ebp_esp_write, TEST_GPREGS, GPREGS_32_EBP_ESP, + TEST_SETREGS, "Test writing ebp & esp registers into debugged program " + "via PT_SETREGS."); + +X86_REGISTER_TEST(x86_gpregs64_read, TEST_GPREGS, GPREGS_64, TEST_GETREGS, + "Test reading basic 64-bit gp registers from debugged program " + "via PT_GETREGS."); +X86_REGISTER_TEST(x86_gpregs64_write, TEST_GPREGS, GPREGS_64, TEST_SETREGS, + "Test writing basic 64-bit gp registers into debugged program " + "via PT_SETREGS."); +X86_REGISTER_TEST(x86_gpregs64_r8_read, TEST_GPREGS, GPREGS_64_R8, TEST_GETREGS, + "Test reading r8..r15 registers from debugged program via PT_GETREGS."); +X86_REGISTER_TEST(x86_gpregs64_r8_write, TEST_GPREGS, GPREGS_64_R8, + TEST_SETREGS, "Test writing r8..r15 registers into debugged program " + "via PT_SETREGS."); + +X86_REGISTER_TEST(x86_fpregs_mm_read, TEST_FPREGS, FPREGS_MM, TEST_GETREGS, + "Test reading mm0..mm7 registers from debugged program " + "via PT_GETFPREGS."); +X86_REGISTER_TEST(x86_fpregs_mm_write, TEST_FPREGS, FPREGS_MM, TEST_SETREGS, + "Test writing mm0..mm7 registers into debugged program " + "via PT_SETFPREGS."); +X86_REGISTER_TEST(x86_fpregs_xmm_read, TEST_XMMREGS, FPREGS_XMM, TEST_GETREGS, + "Test reading xmm0..xmm15 (..xmm7 on i386) from debugged program " + "via PT_GETFPREGS (PT_GETXMMREGS on i386)."); +X86_REGISTER_TEST(x86_fpregs_xmm_write, TEST_XMMREGS, FPREGS_XMM, TEST_SETREGS, + "Test writing xmm0..xmm15 (..xmm7 on i386) into debugged program " + "via PT_SETFPREGS (PT_SETXMMREGS on i386)."); + +X86_REGISTER_TEST(x86_xstate_mm_read, TEST_XSTATE, FPREGS_MM, TEST_GETREGS, + "Test reading mm0..mm7 registers from debugged program " + "via PT_GETXSTATE."); +X86_REGISTER_TEST(x86_xstate_mm_write, TEST_XSTATE, FPREGS_MM, TEST_SETREGS, + "Test writing mm0..mm7 registers into debugged program " + "via PT_SETXSTATE."); +X86_REGISTER_TEST(x86_xstate_xmm_read, TEST_XSTATE, FPREGS_XMM, TEST_GETREGS, + "Test reading xmm0..xmm15 (..xmm7 on i386) from debugged program " + "via PT_GETXSTATE."); +X86_REGISTER_TEST(x86_xstate_xmm_write, TEST_XSTATE, FPREGS_XMM, TEST_SETREGS, + "Test writing xmm0..xmm15 (..xmm7 on i386) into debugged program " + "via PT_SETXSTATE."); +X86_REGISTER_TEST(x86_xstate_ymm_read, TEST_XSTATE, FPREGS_YMM, TEST_GETREGS, + "Test reading ymm0..ymm15 (..ymm7 on i386) from debugged program " + "via PT_GETXSTATE."); +X86_REGISTER_TEST(x86_xstate_ymm_write, TEST_XSTATE, FPREGS_YMM, TEST_SETREGS, + "Test writing ymm0..ymm15 (..ymm7 on i386) into debugged program " + "via PT_SETXSTATE."); + /// ---------------------------------------------------------------------------- #define ATF_TP_ADD_TCS_PTRACE_WAIT_X86() \ @@ -3751,10 +3528,18 @@ ATF_TC_BODY(x86_xstate_ymm_write, tc) ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr2_dont_inherit_execve); \ ATF_TP_ADD_TC_HAVE_DBREGS(tp, dbregs_dr3_dont_inherit_execve); \ ATF_TP_ADD_TC_HAVE_DBREGS(tp, x86_cve_2018_8897); \ - ATF_TP_ADD_TC_HAVE_FPREGS(tp, x86_regs_mm_read); \ - ATF_TP_ADD_TC_HAVE_FPREGS(tp, x86_regs_mm_write); \ - ATF_TP_ADD_TC_HAVE_FPREGS(tp, x86_regs_xmm_read); \ - ATF_TP_ADD_TC_HAVE_FPREGS(tp, x86_regs_xmm_write); \ + ATF_TP_ADD_TC(tp, x86_gpregs32_read); \ + ATF_TP_ADD_TC(tp, x86_gpregs32_write); \ + ATF_TP_ADD_TC(tp, x86_gpregs32_ebp_esp_read); \ + ATF_TP_ADD_TC(tp, x86_gpregs32_ebp_esp_write); \ + ATF_TP_ADD_TC(tp, x86_gpregs64_read); \ + ATF_TP_ADD_TC(tp, x86_gpregs64_write); \ + ATF_TP_ADD_TC(tp, x86_gpregs64_r8_read); \ + ATF_TP_ADD_TC(tp, x86_gpregs64_r8_write); \ + ATF_TP_ADD_TC(tp, x86_fpregs_mm_read); \ + ATF_TP_ADD_TC(tp, x86_fpregs_mm_write); \ + ATF_TP_ADD_TC(tp, x86_fpregs_xmm_read); \ + ATF_TP_ADD_TC(tp, x86_fpregs_xmm_write); \ ATF_TP_ADD_TC(tp, x86_xstate_mm_read); \ ATF_TP_ADD_TC(tp, x86_xstate_mm_write); \ ATF_TP_ADD_TC(tp, x86_xstate_xmm_read); \ -- 2.24.1