Author: Michał Górny Date: 2020-10-03T19:54:38+02:00 New Revision: 381bdc75ee2ca2fb9784ffb2f6b90accd8eab3b6
URL: https://github.com/llvm/llvm-project/commit/381bdc75ee2ca2fb9784ffb2f6b90accd8eab3b6 DIFF: https://github.com/llvm/llvm-project/commit/381bdc75ee2ca2fb9784ffb2f6b90accd8eab3b6.diff LOG: [lldb] [test/Register] Add read/write tests for x87 regs Add a partial read/write tests for x87 FPU registers. This includes reading and writing ST registers, control registers and floating-point exception data registers (fop, fip, fdp). The tests assume the current (roughly incorrect) behavior of reporting the 'abridged' 8-bit ftag state as 16-bit ftag. They also assume Linux plugin behavior of reporting fip/fdp split into halves as (fiseg, fioff) and (foseg, fooff). Differential Revision: https://reviews.llvm.org/D88583 Added: lldb/test/Shell/Register/Inputs/x86-fp-read.cpp lldb/test/Shell/Register/Inputs/x86-fp-write.cpp lldb/test/Shell/Register/x86-64-fp-write.test lldb/test/Shell/Register/x86-fp-read.test lldb/test/Shell/Register/x86-fp-write.test Modified: Removed: ################################################################################ diff --git a/lldb/test/Shell/Register/Inputs/x86-fp-read.cpp b/lldb/test/Shell/Register/Inputs/x86-fp-read.cpp new file mode 100644 index 000000000000..1bd2d60affa2 --- /dev/null +++ b/lldb/test/Shell/Register/Inputs/x86-fp-read.cpp @@ -0,0 +1,45 @@ +#include <cstdint> + +struct alignas(16) float80_raw { + uint64_t mantissa; + uint16_t sign_exp; +}; + +int main() { + float80_raw st[] = { + {0x8000000000000000, 0x4000}, // +2.0 + {0x3f00000000000000, 0x0000}, // 1.654785e-4932 (denormal) + {0x0000000000000000, 0x0000}, // +0 + {0x0000000000000000, 0x8000}, // -0 + {0x8000000000000000, 0x7fff}, // +inf + {0x8000000000000000, 0xffff}, // -inf + {0xc000000000000000, 0xffff}, // nan + // leave st7 empty to test tag word better + }; + + // unmask divide-by-zero exception + uint16_t cw = 0x037b; + // used as single-precision float + uint32_t zero = 0; + + asm volatile( + "finit\n\t" + "fldcw %1\n\t" + // load on stack in reverse order to make the result easier to read + "fldt 0x60(%0)\n\t" + "fldt 0x50(%0)\n\t" + "fldt 0x40(%0)\n\t" + "fldt 0x30(%0)\n\t" + "fldt 0x20(%0)\n\t" + "fldt 0x10(%0)\n\t" + "fldt 0x00(%0)\n\t" + // this should trigger a divide-by-zero + "fdivs (%2)\n\t" + "int3\n\t" + : + : "a"(st), "m"(cw), "b"(&zero) + : "st" + ); + + return 0; +} diff --git a/lldb/test/Shell/Register/Inputs/x86-fp-write.cpp b/lldb/test/Shell/Register/Inputs/x86-fp-write.cpp new file mode 100644 index 000000000000..63791a8eff2e --- /dev/null +++ b/lldb/test/Shell/Register/Inputs/x86-fp-write.cpp @@ -0,0 +1,69 @@ +#include <cassert> +#include <cinttypes> +#include <cstdint> +#include <cstdio> + +struct alignas(16) float80_raw { + uint8_t data[10]; +}; + +int main() { + float80_raw st[8]; + uint16_t env[14]; + union alignas(16) { + uint16_t i16[256]; + uint32_t i32[128]; + uint64_t i64[64]; + } fxsave; + + asm volatile( + "finit\n\t" + "int3\n\t" +#if defined(__x86_64__) + "fxsave64 %2\n\t" +#else + "fxsave %2\n\t" +#endif + "fnstenv %1\n\t" + "fnclex\n\t" + "fstpt 0x00(%0)\n\t" + "fstpt 0x10(%0)\n\t" + "fstpt 0x20(%0)\n\t" + "fstpt 0x30(%0)\n\t" + "fstpt 0x40(%0)\n\t" + "fstpt 0x50(%0)\n\t" + "fstpt 0x60(%0)\n\t" + "fstpt 0x70(%0)\n\t" + : + : "a"(st), "m"(env), "m"(fxsave) + : "st" + ); + + assert(env[0] == fxsave.i16[0]); + assert(env[2] == fxsave.i16[1]); + + printf("fctrl = 0x%04" PRIx16 "\n", env[0]); + printf("fstat = 0x%04" PRIx16 "\n", env[2]); + printf("ftag = 0x%04" PRIx16 "\n", env[4]); + printf("fop = 0x%04" PRIx16 "\n", fxsave.i16[3]); +#if defined(__x86_64__) + printf("fip = 0x%016" PRIx64 "\n", fxsave.i64[1]); + printf("fdp = 0x%016" PRIx64 "\n", fxsave.i64[2]); +#else + printf("fip = 0x%08" PRIx32 "\n", fxsave.i32[2]); + printf("fcs = 0x%04" PRIx16 "\n", fxsave.i16[6]); + printf("fdp = 0x%08" PRIx32 "\n", fxsave.i32[4]); + printf("fds = 0x%04" PRIx16 "\n", fxsave.i16[10]); +#endif + printf("mxcsr = 0x%08" PRIx32 "\n", fxsave.i32[6]); + printf("mxcsr_mask = 0x%08" PRIx32 "\n", fxsave.i32[7]); + + for (int i = 0; i < 8; ++i) { + printf("st%d = { ", i); + for (int j = 0; j < sizeof(st->data); ++j) + printf("0x%02" PRIx8 " ", st[i].data[j]); + printf("}\n"); + } + + return 0; +} diff --git a/lldb/test/Shell/Register/x86-64-fp-write.test b/lldb/test/Shell/Register/x86-64-fp-write.test new file mode 100644 index 000000000000..b2e8c271b51b --- /dev/null +++ b/lldb/test/Shell/Register/x86-64-fp-write.test @@ -0,0 +1,48 @@ +# REQUIRES: native && target-x86_64 +# RUN: %clangxx_host %p/Inputs/x86-fp-write.cpp -o %t +# RUN: %lldb -b -s %s %t | FileCheck %s +process launch + +register write fctrl 0x037b +register write fstat 0x8884 +# note: this needs to enable all registers for writes to be effective +# TODO: fix it to use proper ftag values instead of 'abridged' +register write ftag 0x00ff +register write fop 0x0033 +# the exact addresses do not matter, we want just to verify FXSAVE +# note: fxrstor64 apparently truncates this to 48 bits, and sign extends +# the highest bits, so let's keep the value safely below +register write fiseg 0x00000567 +register write fioff 0x89abcdef +register write foseg 0x00000a98 +register write fooff 0x76543210 + +register write st0 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x40}" +register write st1 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x3f 0x00 0x00}" +register write st2 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}" +register write st3 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80}" +register write st4 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x7f}" +register write st5 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0xff}" +register write st6 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc0 0xff 0xff}" +register write st7 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}" + +process continue + +# CHECK: process continue +# CHECK-DAG: fctrl = 0x037b +# CHECK-DAG: fstat = 0x8884 +# CHECK-DAG: ftag = 0xa961 +# CHECK-DAG: fop = 0x0033 +# CHECK-DAG: fip = 0x0000056789abcdef +# CHECK-DAG: fdp = 0x00000a9876543210 + +# CHECK-DAG: st0 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x40 } +# CHECK-DAG: st1 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x3f 0x00 0x00 } +# CHECK-DAG: st2 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 } +# CHECK-DAG: st3 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 } +# CHECK-DAG: st4 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x7f } +# CHECK-DAG: st5 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0xff } +# CHECK-DAG: st6 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc0 0xff 0xff } +# CHECK-DAG: st7 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 } + +# CHECK: Process {{[0-9]+}} exited with status = 0 diff --git a/lldb/test/Shell/Register/x86-fp-read.test b/lldb/test/Shell/Register/x86-fp-read.test new file mode 100644 index 000000000000..9ecc5634e729 --- /dev/null +++ b/lldb/test/Shell/Register/x86-fp-read.test @@ -0,0 +1,36 @@ +# REQUIRES: native && (target-x86 || target-x86_64) +# RUN: %clangxx_host -g %p/Inputs/x86-fp-read.cpp -o %t +# RUN: %lldb -b -s %s %t | FileCheck %s +process launch +# CHECK: Process {{.*}} stopped + +register read --all +# CHECK-DAG: fctrl = 0x037b +# CHECK-DAG: fstat = 0x8884 +# TODO: the following value is incorrect, it's a bug in the way +# FXSAVE/XSAVE is interpreted; it should be 0xa963 once fixed +# CHECK-DAG: ftag = 0x00fe +# CHECK-DAG: fop = 0x0033 + +# CHECK-DAG: st0 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x40} +# CHECK-DAG: st1 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x3f 0x00 0x00} +# CHECK-DAG: st2 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} +# CHECK-DAG: st3 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80} +# CHECK-DAG: st4 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x7f} +# CHECK-DAG: st5 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0xff} +# CHECK-DAG: st6 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc0 0xff 0xff} +# CHECK-DAG: st7 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} + +# fdiv (%rbx) gets encoded into 2 bytes, int3 into 1 byte +print (void*)($pc-3) +# CHECK: (void *) $0 = [[FDIV:0x[0-9a-f]*]] +# TODO: we probably should not split it like this +print (void*)($fiseg*0x100000000 + $fioff) +# CHECK: (void *) $1 = [[FDIV]] +print &zero +# CHECK: (uint32_t *) $2 = [[ZERO:0x[0-9a-f]*]] +print (uint32_t*)($foseg * 0x100000000 + $fooff) +# CHECK: (uint32_t *) $3 = [[ZERO]] + +process continue +# CHECK: Process {{[0-9]+}} exited with status = 0 diff --git a/lldb/test/Shell/Register/x86-fp-write.test b/lldb/test/Shell/Register/x86-fp-write.test new file mode 100644 index 000000000000..81f542c419af --- /dev/null +++ b/lldb/test/Shell/Register/x86-fp-write.test @@ -0,0 +1,45 @@ +# REQUIRES: native && target-x86 +# RUN: %clangxx_host %p/Inputs/x86-fp-write.cpp -o %t +# RUN: %lldb -b -s %s %t | FileCheck %s +process launch + +register write fctrl 0x037b +register write fstat 0x8884 +# note: this needs to enable all registers for writes to be effective +# TODO: fix it to use proper ftag values instead of 'abridged' +register write ftag 0x00ff +register write fop 0x0033 +# the exact addresses do not matter, we want just to verify FXSAVE +# note: segment registers are not supported on all CPUs +register write fioff 0x89abcdef +register write fooff 0x76543210 + +register write st0 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x40}" +register write st1 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x3f 0x00 0x00}" +register write st2 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}" +register write st3 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80}" +register write st4 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x7f}" +register write st5 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0xff}" +register write st6 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc0 0xff 0xff}" +register write st7 "{0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}" + +process continue + +# CHECK: process continue +# CHECK-DAG: fctrl = 0x037b +# CHECK-DAG: fstat = 0x8884 +# CHECK-DAG: ftag = 0xa961 +# CHECK-DAG: fop = 0x0033 +# CHECK-DAG: fip = 0x89abcdef +# CHECK-DAG: fdp = 0x76543210 + +# CHECK-DAG: st0 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x40 } +# CHECK-DAG: st1 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x3f 0x00 0x00 } +# CHECK-DAG: st2 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 } +# CHECK-DAG: st3 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 } +# CHECK-DAG: st4 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x7f } +# CHECK-DAG: st5 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0xff } +# CHECK-DAG: st6 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc0 0xff 0xff } +# CHECK-DAG: st7 = { 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 } + +# CHECK: Process {{[0-9]+}} exited with status = 0 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits