| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| //===-- RegisterContext_x86.cpp ---------------------------------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "RegisterContext_x86.h" | ||
|
|
||
| using namespace lldb_private; | ||
|
|
||
| // Convert the 8-bit abridged FPU Tag Word (as found in FXSAVE) to the full | ||
| // 16-bit FPU Tag Word (as found in FSAVE, and used by gdb protocol). This | ||
| // requires knowing the values of the ST(i) registers and the FPU Status Word. | ||
| uint16_t lldb_private::AbridgedToFullTagWord(uint8_t abridged_tw, uint16_t sw, | ||
| llvm::ArrayRef<MMSReg> st_regs) { | ||
| // Tag word is using internal FPU register numbering rather than ST(i). | ||
| // Mapping to ST(i): i = FPU regno - TOP (Status Word, bits 11:13). | ||
| // Here we start with FPU reg 7 and go down. | ||
| int st = 7 - ((sw >> 11) & 7); | ||
| uint16_t tw = 0; | ||
| for (uint8_t mask = 0x80; mask != 0; mask >>= 1) { | ||
| tw <<= 2; | ||
| if (abridged_tw & mask) { | ||
| // The register is non-empty, so we need to check the value of ST(i). | ||
| uint16_t exp = | ||
| st_regs[st].comp.sign_exp & 0x7fff; // Discard the sign bit. | ||
| if (exp == 0) { | ||
| if (st_regs[st].comp.mantissa == 0) | ||
| tw |= 1; // Zero | ||
| else | ||
| tw |= 2; // Denormal | ||
| } else if (exp == 0x7fff) | ||
| tw |= 2; // Infinity or NaN | ||
| // 0 if normal number | ||
| } else | ||
| tw |= 3; // Empty register | ||
|
|
||
| // Rotate ST down. | ||
| st = (st - 1) & 7; | ||
| } | ||
|
|
||
| return tw; | ||
| } | ||
|
|
||
| // Convert the 16-bit FPU Tag Word to the abridged 8-bit value, to be written | ||
| // into FXSAVE. | ||
| uint8_t lldb_private::FullToAbridgedTagWord(uint16_t tw) { | ||
| uint8_t abridged_tw = 0; | ||
| for (uint16_t mask = 0xc000; mask != 0; mask >>= 2) { | ||
| abridged_tw <<= 1; | ||
| // full TW uses 11 for empty registers, aTW uses 0 | ||
| if ((tw & mask) != mask) | ||
| abridged_tw |= 1; | ||
| } | ||
| return abridged_tw; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| # XFAIL: system-windows | ||
| # XFAIL: system-darwin | ||
| # REQUIRES: native && 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 | ||
|
|
||
| # fdiv (%rbx) gets encoded into 2 bytes, int3 into 1 byte | ||
| print (void*)($pc-3) | ||
| # CHECK: (void *) $0 = [[FDIV:0x[0-9a-f]*]] | ||
| print &zero | ||
| # CHECK: (uint32_t *) $1 = [[ZERO:0x[0-9a-f]*]] | ||
|
|
||
| register read --all | ||
| # CHECK-DAG: fctrl = 0x037b | ||
| # CHECK-DAG: fstat = 0x8084 | ||
| # CHECK-DAG: ftag = 0xea58 | ||
| # CHECK-DAG: fop = 0x0033 | ||
| # CHECK-DAG: fip = [[FDIV]] | ||
| # CHECK-DAG: fdp = [[ZERO]] | ||
|
|
||
| # CHECK-DAG: st{{(mm)?}}0 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x40} | ||
| # CHECK-DAG: st{{(mm)?}}1 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x3f 0x00 0x00} | ||
| # CHECK-DAG: st{{(mm)?}}2 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} | ||
| # CHECK-DAG: st{{(mm)?}}3 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80} | ||
| # CHECK-DAG: st{{(mm)?}}4 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0x7f} | ||
| # CHECK-DAG: st{{(mm)?}}5 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xff 0xff} | ||
| # CHECK-DAG: st{{(mm)?}}6 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc0 0xff 0xff} | ||
| # CHECK-DAG: st{{(mm)?}}7 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00} | ||
|
|
||
| # legacy approach, superseded by fip/fdp registers | ||
| print (void*)($fiseg*0x100000000 + $fioff) | ||
| # CHECK: (void *) $2 = [[FDIV]] | ||
| print (uint32_t*)($foseg * 0x100000000 + $fooff) | ||
| # CHECK: (uint32_t *) $3 = [[ZERO]] | ||
|
|
||
| process continue | ||
| # CHECK: Process {{[0-9]+}} exited with status = 0 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| add_lldb_unittest(ProcessUtilityTests | ||
| RegisterContextTest.cpp | ||
| RegisterContextFreeBSDTest.cpp | ||
|
|
||
| LINK_LIBS | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| //===-- RegisterContextTest.cpp -------------------------------------------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "gtest/gtest.h" | ||
|
|
||
| #include "Plugins/Process/Utility/RegisterContext_x86.h" | ||
|
|
||
| #include "llvm/ADT/STLExtras.h" | ||
| #include "llvm/Support/FormatVariadic.h" | ||
|
|
||
| #include <array> | ||
|
|
||
| using namespace lldb_private; | ||
|
|
||
| struct TagWordTestVector { | ||
| uint16_t sw; | ||
| uint16_t tw; | ||
| uint8_t tw_abridged; | ||
| int st_reg_num; | ||
| }; | ||
|
|
||
| constexpr MMSReg st_from_comp(uint64_t mantissa, uint16_t sign_exp) { | ||
| MMSReg ret = {}; | ||
| ret.comp.mantissa = mantissa; | ||
| ret.comp.sign_exp = sign_exp; | ||
| return ret; | ||
| } | ||
|
|
||
| const std::array<MMSReg, 8> st_regs = { | ||
| st_from_comp(0x8000000000000000, 0x4000), // +2.0 | ||
| st_from_comp(0x3f00000000000000, 0x0000), // 1.654785e-4932 | ||
| st_from_comp(0x0000000000000000, 0x0000), // +0 | ||
| st_from_comp(0x0000000000000000, 0x8000), // -0 | ||
| st_from_comp(0x8000000000000000, 0x7fff), // +inf | ||
| st_from_comp(0x8000000000000000, 0xffff), // -inf | ||
| st_from_comp(0xc000000000000000, 0xffff), // nan | ||
| st_from_comp(0x8000000000000000, 0xc000), // -2.0 | ||
| }; | ||
|
|
||
| const std::array<TagWordTestVector, 8> tag_word_test_vectors{ | ||
| TagWordTestVector{0x3800, 0x3fff, 0x80, 1}, | ||
| TagWordTestVector{0x3000, 0x2fff, 0xc0, 2}, | ||
| TagWordTestVector{0x2800, 0x27ff, 0xe0, 3}, | ||
| TagWordTestVector{0x2000, 0x25ff, 0xf0, 4}, | ||
| TagWordTestVector{0x1800, 0x25bf, 0xf8, 5}, | ||
| TagWordTestVector{0x1000, 0x25af, 0xfc, 6}, | ||
| TagWordTestVector{0x0800, 0x25ab, 0xfe, 7}, | ||
| TagWordTestVector{0x0000, 0x25a8, 0xff, 8}, | ||
| }; | ||
|
|
||
| TEST(RegisterContext_x86Test, AbridgedToFullTagWord) { | ||
| for (const auto &x : llvm::enumerate(tag_word_test_vectors)) { | ||
| SCOPED_TRACE(llvm::formatv("tag_word_test_vectors[{0}]", x.index())); | ||
| std::array<MMSReg, 8> test_regs; | ||
| for (int i = 0; i < x.value().st_reg_num; ++i) | ||
| test_regs[i] = st_regs[x.value().st_reg_num - i - 1]; | ||
| EXPECT_EQ( | ||
| AbridgedToFullTagWord(x.value().tw_abridged, x.value().sw, test_regs), | ||
| x.value().tw); | ||
| } | ||
| } | ||
|
|
||
| TEST(RegisterContext_x86Test, FullToAbridgedTagWord) { | ||
| for (const auto &x : llvm::enumerate(tag_word_test_vectors)) { | ||
| SCOPED_TRACE(llvm::formatv("tag_word_test_vectors[{0}]", x.index())); | ||
| EXPECT_EQ(FullToAbridgedTagWord(x.value().tw), x.value().tw_abridged); | ||
| } | ||
| } |