diff --git a/lldb/packages/Python/lldbsuite/test/commands/register/register/intel_xtended_registers/mpx_offset_intersection/Makefile b/lldb/packages/Python/lldbsuite/test/commands/register/register/intel_xtended_registers/mpx_offset_intersection/Makefile new file mode 100644 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/commands/register/register/intel_xtended_registers/mpx_offset_intersection/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/packages/Python/lldbsuite/test/commands/register/register/intel_xtended_registers/mpx_offset_intersection/TestMPXOffsetIntersection.py b/lldb/packages/Python/lldbsuite/test/commands/register/register/intel_xtended_registers/mpx_offset_intersection/TestMPXOffsetIntersection.py new file mode 100644 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/commands/register/register/intel_xtended_registers/mpx_offset_intersection/TestMPXOffsetIntersection.py @@ -0,0 +1,73 @@ +""" +Test Intel(R) MPX registers do not get overwritten by AVX data. +""" + +from __future__ import print_function + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class MPXOffsetIntersectionTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + AVX_REGS = ('ymm' + str(i) for i in range(16)) + YMM_VALUE = '{' + ' '.join(('0x00' for _ in range(32))) + '}' + + MPX_REGULAR_REGS = ('bnd0', 'bnd1', 'bnd2', 'bnd3') + MPX_CONFIG_REGS = ('bndcfgu', 'bndstatus') + BND_VALUE = '{' + ' '.join(('0xff' for _ in range(16))) + '}' + + def setUp(self): + TestBase.setUp(self) + + @skipIf(oslist=no_match(['linux'])) + @skipIf(archs=no_match(['x86_64'])) + def test_mpx_registers_offset_intersection(self): + """Test if AVX data does not overwrite MPX values.""" + self.build() + self.mpx_registers_offset_intersection() + + def mpx_registers_offset_intersection(self): + exe = self.getBuildArtifact('a.out') + self.runCmd('file ' + exe, CURRENT_EXECUTABLE_SET) + self.runCmd('run', RUN_SUCCEEDED) + target = self.dbg.GetSelectedTarget() + process = target.GetProcess() + thread = process.GetThreadAtIndex(0) + currentFrame = thread.GetFrameAtIndex(0) + + has_avx = False + has_mpx = False + for registerSet in currentFrame.GetRegisters(): + if 'advanced vector extensions' in registerSet.GetName().lower(): + has_avx = True + if 'memory protection extension' in registerSet.GetName().lower(): + has_mpx = True + if not (has_avx and has_mpx): + self.skipTest('Both AVX and MPX registers must be supported.') + + for reg in self.AVX_REGS: + self.runCmd('register write ' + reg + " '" + self.YMM_VALUE + " '") + for reg in self.MPX_REGULAR_REGS + self.MPX_CONFIG_REGS: + self.runCmd('register write ' + reg + " '" + self.BND_VALUE + " '") + + self.verify_mpx() + self.verify_avx() + self.verify_mpx() + + def verify_mpx(self): + for reg in self.MPX_REGULAR_REGS: + self.expect('register read ' + reg, + substrs = [reg + ' = {0xffffffffffffffff 0xffffffffffffffff}']) + for reg in self.MPX_CONFIG_REGS: + self.expect('register read ' + reg, + substrs = [reg + ' = {0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff}']) + + def verify_avx(self): + for reg in self.AVX_REGS: + self.expect('register read ' + reg, substrs = [reg + ' = ' + self.YMM_VALUE]) diff --git a/lldb/packages/Python/lldbsuite/test/commands/register/register/intel_xtended_registers/mpx_offset_intersection/main.cpp b/lldb/packages/Python/lldbsuite/test/commands/register/register/intel_xtended_registers/mpx_offset_intersection/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/commands/register/register/intel_xtended_registers/mpx_offset_intersection/main.cpp @@ -0,0 +1,6 @@ +#include + +int main() { + asm volatile("int3"); + return 0; +} diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h @@ -60,6 +60,10 @@ virtual size_t GetFPRSize() = 0; + virtual uint32_t GetPtraceOffset(uint32_t reg_index) { + return GetRegisterInfoAtIndex(reg_index)->byte_offset; + } + // The Do*** functions are executed on the privileged thread and can perform // ptrace // operations directly. diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp @@ -34,7 +34,7 @@ if (!reg_info) return Status("register %" PRIu32 " not found", reg_index); - return DoReadRegisterValue(reg_info->byte_offset, reg_info->name, + return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name, reg_info->byte_size, reg_value); } @@ -91,7 +91,8 @@ "for write register index %" PRIu32, __FUNCTION__, reg_to_write); - return DoWriteRegisterValue(reg_info->byte_offset, reg_info->name, reg_value); + return DoWriteRegisterValue(GetPtraceOffset(reg_index), reg_info->name, + reg_value); } Status NativeRegisterContextLinux::ReadGPR() { diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h @@ -75,6 +75,8 @@ Status WriteFPR() override; + uint32_t GetPtraceOffset(uint32_t reg_index) override; + private: // Private member types. enum class XStateType { Invalid, FXSAVE, XSAVE }; diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp @@ -1213,4 +1213,11 @@ return 4; } +uint32_t +NativeRegisterContextLinux_x86_64::GetPtraceOffset(uint32_t reg_index) { + // If register is MPX, remove extra factor from gdb offset + return GetRegisterInfoAtIndex(reg_index)->byte_offset - + (IsMPX(reg_index) ? 128 : 0); +} + #endif // defined(__i386__) || defined(__x86_64__) diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h b/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h --- a/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h @@ -25,15 +25,18 @@ LLVM_EXTENSION offsetof(FPR, xsave) + \ LLVM_EXTENSION offsetof(XSAVE, ymmh[0]) + (32 * reg_index)) +// Guarantees BNDR/BNDC offsets do not overlap with YMM offsets. +#define GDB_REMOTE_OFFSET 128 + #define BNDR_OFFSET(reg_index) \ (LLVM_EXTENSION offsetof(UserArea, fpr) + \ LLVM_EXTENSION offsetof(FPR, xsave) + \ - LLVM_EXTENSION offsetof(XSAVE, mpxr[reg_index])) + LLVM_EXTENSION offsetof(XSAVE, mpxr[reg_index]) + GDB_REMOTE_OFFSET) #define BNDC_OFFSET(reg_index) \ (LLVM_EXTENSION offsetof(UserArea, fpr) + \ LLVM_EXTENSION offsetof(FPR, xsave) + \ - LLVM_EXTENSION offsetof(XSAVE, mpxc[reg_index])) + LLVM_EXTENSION offsetof(XSAVE, mpxc[reg_index]) + GDB_REMOTE_OFFSET) #ifdef DECLARE_REGISTER_INFOS_X86_64_STRUCT