diff options
author | Valentina Giusti <valentina.giusti@intel.com> | 2016-09-05 17:43:10 +0000 |
---|---|---|
committer | Valentina Giusti <valentina.giusti@intel.com> | 2016-09-05 17:43:10 +0000 |
commit | f105abbc0d0bf316f43ca6a3e0b2aae6daedf1d6 (patch) | |
tree | 9547ee4b31a6203a7a6e3745ae475ad792befc46 /lldb/source/Plugins/Process/Linux | |
parent | 9bd34f975157df546bd57e7a5d86a8aace7d573b (diff) | |
download | bcm5719-llvm-f105abbc0d0bf316f43ca6a3e0b2aae6daedf1d6.tar.gz bcm5719-llvm-f105abbc0d0bf316f43ca6a3e0b2aae6daedf1d6.zip |
Intel(R) Memory Protection Extensions (Intel(R) MPX) support.
Summary:
The Intel(R) Memory Protection Extensions (Intel(R) MPX) associates pointers
to bounds, against which the software can check memory references to
prevent out of bound memory access.
This patch allows accessing the MPX registers:
* bnd0-3: 128-bit registers to hold the bound values,
* bndcfgu, bndstatus: 64-bit configuration registers,
This patch also adds read/write tests for the MPX registers in the register
command tests and adds a new subdirectory for MPX specific tests.
Signed-off-by: Valentina Giusti <valentina.giusti@intel.com>
Reviewers: labath, granata.enrico, lldb-commits, clayborg
Subscribers: lldb-commits
Differential Revision: https://reviews.llvm.org/D24187
llvm-svn: 280668
Diffstat (limited to 'lldb/source/Plugins/Process/Linux')
-rwxr-xr-x | lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp | 179 | ||||
-rw-r--r-- | lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h | 17 |
2 files changed, 185 insertions, 11 deletions
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp index 2080d2ede37..93ee50273b9 100755 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp @@ -130,6 +130,21 @@ namespace static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - 1 == k_num_avx_registers_i386, " g_avx_regnums_i386 has wrong number of register infos"); + // x64 32-bit MPX registers. + static const uint32_t + g_mpx_regnums_i386[] = + { + lldb_bnd0_i386, + lldb_bnd1_i386, + lldb_bnd2_i386, + lldb_bnd3_i386, + lldb_bndcfgu_i386, + lldb_bndstatus_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag + }; + static_assert((sizeof(g_mpx_regnums_i386) / sizeof(g_mpx_regnums_i386[0])) - 1 == k_num_mpx_registers_i386, + "g_mpx_regnums_x86_64 has wrong number of register infos"); + // x86 64-bit general purpose registers. static const uint32_t g_gpr_regnums_x86_64[] = @@ -291,29 +306,47 @@ namespace static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - 1 == k_num_avx_registers_x86_64, "g_avx_regnums_x86_64 has wrong number of register infos"); + // x86 64-bit MPX registers. + static const uint32_t + g_mpx_regnums_x86_64[] = + { + lldb_bnd0_x86_64, + lldb_bnd1_x86_64, + lldb_bnd2_x86_64, + lldb_bnd3_x86_64, + lldb_bndcfgu_x86_64, + lldb_bndstatus_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag + }; + static_assert((sizeof(g_mpx_regnums_x86_64) / sizeof(g_mpx_regnums_x86_64[0])) - 1 == k_num_mpx_registers_x86_64, + "g_mpx_regnums_x86_64 has wrong number of register infos"); + // Number of register sets provided by this context. enum { k_num_extended_register_sets = 1, - k_num_register_sets = 3 + k_num_register_sets = 4 }; // Register sets for x86 32-bit. static const RegisterSet g_reg_sets_i386[k_num_register_sets] = { - { "General Purpose Registers", "gpr", k_num_gpr_registers_i386, g_gpr_regnums_i386 }, - { "Floating Point Registers", "fpu", k_num_fpr_registers_i386, g_fpu_regnums_i386 }, - { "Advanced Vector Extensions", "avx", k_num_avx_registers_i386, g_avx_regnums_i386 } + { "General Purpose Registers", "gpr", k_num_gpr_registers_i386, g_gpr_regnums_i386 }, + { "Floating Point Registers", "fpu", k_num_fpr_registers_i386, g_fpu_regnums_i386 }, + { "Advanced Vector Extensions", "avx", k_num_avx_registers_i386, g_avx_regnums_i386 }, + { "Memory Protection Extensions", "mpx", k_num_mpx_registers_i386, g_mpx_regnums_i386 } }; // Register sets for x86 64-bit. static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = { - { "General Purpose Registers", "gpr", k_num_gpr_registers_x86_64, g_gpr_regnums_x86_64 }, - { "Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, g_fpu_regnums_x86_64 }, - { "Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, g_avx_regnums_x86_64 } + { "General Purpose Registers", "gpr", k_num_gpr_registers_x86_64, g_gpr_regnums_x86_64 }, + { "Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, g_fpu_regnums_x86_64 }, + { "Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, g_avx_regnums_x86_64 }, + { "Memory Protection Extensions", "mpx", k_num_mpx_registers_x86_64, g_mpx_regnums_x86_64 } + }; } @@ -368,6 +401,7 @@ NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64 (const Arch m_fpr (), m_iovec (), m_ymm_set (), + m_mpx_set (), m_reg_info (), m_gpr_x86_64 () { @@ -379,6 +413,7 @@ NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64 (const Arch m_reg_info.num_gpr_registers = k_num_gpr_registers_i386; m_reg_info.num_fpr_registers = k_num_fpr_registers_i386; m_reg_info.num_avx_registers = k_num_avx_registers_i386; + m_reg_info.num_mpx_registers = k_num_mpx_registers_i386; m_reg_info.last_gpr = k_last_gpr_i386; m_reg_info.first_fpr = k_first_fpr_i386; m_reg_info.last_fpr = k_last_fpr_i386; @@ -390,6 +425,10 @@ NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64 (const Arch m_reg_info.last_xmm = lldb_xmm7_i386; m_reg_info.first_ymm = lldb_ymm0_i386; m_reg_info.last_ymm = lldb_ymm7_i386; + m_reg_info.first_mpxr = lldb_bnd0_i386; + m_reg_info.last_mpxr = lldb_bnd3_i386; + m_reg_info.first_mpxc = lldb_bndcfgu_i386; + m_reg_info.last_mpxc = lldb_bndstatus_i386; m_reg_info.first_dr = lldb_dr0_i386; m_reg_info.gpr_flags = lldb_eflags_i386; break; @@ -398,6 +437,7 @@ NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64 (const Arch m_reg_info.num_gpr_registers = k_num_gpr_registers_x86_64; m_reg_info.num_fpr_registers = k_num_fpr_registers_x86_64; m_reg_info.num_avx_registers = k_num_avx_registers_x86_64; + m_reg_info.num_mpx_registers = k_num_mpx_registers_x86_64; m_reg_info.last_gpr = k_last_gpr_x86_64; m_reg_info.first_fpr = k_first_fpr_x86_64; m_reg_info.last_fpr = k_last_fpr_x86_64; @@ -409,6 +449,10 @@ NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64 (const Arch m_reg_info.last_xmm = lldb_xmm15_x86_64; m_reg_info.first_ymm = lldb_ymm0_x86_64; m_reg_info.last_ymm = lldb_ymm15_x86_64; + m_reg_info.first_mpxr = lldb_bnd0_x86_64; + m_reg_info.last_mpxr = lldb_bnd3_x86_64; + m_reg_info.first_mpxc = lldb_bndcfgu_x86_64; + m_reg_info.last_mpxc = lldb_bndstatus_x86_64; m_reg_info.first_dr = lldb_dr0_x86_64; m_reg_info.gpr_flags = lldb_rflags_x86_64; break; @@ -554,7 +598,28 @@ NativeRegisterContextLinux_x86_64::ReadRegister (const RegisterInfo *reg_info, R return error; } } - + if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) + { + if (GetFPRType() == eFPRTypeXSAVE && CopyXSTATEtoMPX(reg)) + reg_value.SetBytes(m_mpx_set.mpxr[reg - m_reg_info.first_mpxr].bytes, reg_info->byte_size, + byte_order); + else + { + error.SetErrorString("failed to copy mpx register value"); + return error; + } + } + if (reg >= m_reg_info.first_mpxc && reg <= m_reg_info.last_mpxc) + { + if (GetFPRType() == eFPRTypeXSAVE && CopyXSTATEtoMPX(reg)) + reg_value.SetBytes(m_mpx_set.mpxc[reg - m_reg_info.first_mpxc].bytes, reg_info->byte_size, + byte_order); + else + { + error.SetErrorString("failed to copy mpx register value"); + return error; + } + } if (reg_value.GetType() != RegisterValue::eTypeBytes) error.SetErrorString ("write failed - type was expected to be RegisterValue::eTypeBytes"); @@ -634,6 +699,26 @@ NativeRegisterContextLinux_x86_64::WriteRegister (const RegisterInfo *reg_info, if (!CopyYMMtoXSTATE(reg_index, GetByteOrder())) return Error ("CopyYMMtoXSTATE() failed"); } + if (reg_index >= m_reg_info.first_mpxr && reg_index <= m_reg_info.last_mpxr) + { + if (GetFPRType() != eFPRTypeXSAVE) + return Error("target processor does not support MPX"); + + ::memcpy(m_mpx_set.mpxr[reg_index - m_reg_info.first_mpxr].bytes, reg_value.GetBytes(), + reg_value.GetByteSize()); + if (!CopyMPXtoXSTATE(reg_index)) + return Error("CopyMPXtoXSTATE() failed"); + } + if (reg_index >= m_reg_info.first_mpxc && reg_index <= m_reg_info.last_mpxc) + { + if (GetFPRType() != eFPRTypeXSAVE) + return Error("target processor does not support MPX"); + + ::memcpy(m_mpx_set.mpxc[reg_index - m_reg_info.first_mpxc].bytes, reg_value.GetBytes(), + reg_value.GetByteSize()); + if (!CopyMPXtoXSTATE(reg_index)) + return Error("CopyMPXtoXSTATE() failed"); + } } else { @@ -677,6 +762,12 @@ NativeRegisterContextLinux_x86_64::WriteRegister (const RegisterInfo *reg_info, if (!CopyYMMtoXSTATE(reg_index, GetByteOrder())) return Error ("CopyYMMtoXSTATE() failed"); } + + if (IsMPX(reg_index)) + { + if (!CopyMPXtoXSTATE(reg_index)) + return Error("CopyMPXtoXSTATE() failed"); + } return Error (); } return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown"); @@ -727,6 +818,17 @@ NativeRegisterContextLinux_x86_64::ReadAllRegisterValues (lldb::DataBufferSP &da } } + for (uint32_t reg = m_reg_info.first_mpxr; reg <= m_reg_info.last_mpxc; ++reg) + { + if (!CopyXSTATEtoMPX(reg)) + { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_x86_64::%s CopyXSTATEtoMPX() failed for reg num %" PRIu32, __FUNCTION__, + reg); + return error; + } + } + // Copy the extended register state including the assembled ymm registers. ::memcpy (dst, &m_fpr, sizeof (m_fpr)); } @@ -806,6 +908,17 @@ NativeRegisterContextLinux_x86_64::WriteAllRegisterValues (const lldb::DataBuffe return error; } } + + for (uint32_t reg = m_reg_info.first_mpxr; reg <= m_reg_info.last_mpxc; ++reg) + { + if (!CopyMPXtoXSTATE(reg)) + { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_x86_64::%s CopyMPXtoXSTATE() failed for reg num %" PRIu32, __FUNCTION__, + reg); + return error; + } + } } return error; @@ -820,7 +933,7 @@ NativeRegisterContextLinux_x86_64::IsRegisterSetAvailable (uint32_t set_index) c if (GetFPRType () == eFPRTypeXSAVE) { // AVX is the first extended register set. - ++num_sets; + num_sets += 2; } return (set_index < num_sets); } @@ -870,7 +983,8 @@ NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index, FPRType fpr_type) c bool generic_fpr = IsFPR(reg_index); if (fpr_type == eFPRTypeXSAVE) - return generic_fpr || IsAVX(reg_index); + return generic_fpr || IsAVX(reg_index) || IsMPX(reg_index); + return generic_fpr; } @@ -1005,6 +1119,7 @@ NativeRegisterContextLinux_x86_64::ReadFPR () { const FPRType fpr_type = GetFPRType (); const lldb_private::ArchSpec& target_arch = GetRegisterInfoInterface().GetTargetArchitecture(); + switch (fpr_type) { case FPRType::eFPRTypeFXSAVE: @@ -1029,6 +1144,50 @@ NativeRegisterContextLinux_x86_64::ReadFPR () } } +bool +NativeRegisterContextLinux_x86_64::IsMPX(uint32_t reg_index) const +{ + return (m_reg_info.first_mpxr <= reg_index && reg_index <= m_reg_info.last_mpxc); +} + +bool +NativeRegisterContextLinux_x86_64::CopyXSTATEtoMPX(uint32_t reg) +{ + if (!IsMPX(reg)) + return false; + + if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) + { + ::memcpy(m_mpx_set.mpxr[reg - m_reg_info.first_mpxr].bytes, + m_fpr.xstate.xsave.mpxr[reg - m_reg_info.first_mpxr].bytes, sizeof(MPXReg)); + } + else + { + ::memcpy(m_mpx_set.mpxc[reg - m_reg_info.first_mpxc].bytes, + m_fpr.xstate.xsave.mpxc[reg - m_reg_info.first_mpxc].bytes, sizeof(MPXCsr)); + } + return true; +} + +bool +NativeRegisterContextLinux_x86_64::CopyMPXtoXSTATE(uint32_t reg) +{ + if (!IsMPX(reg)) + return false; + + if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) + { + ::memcpy(m_fpr.xstate.xsave.mpxr[reg - m_reg_info.first_mpxr].bytes, + m_mpx_set.mpxr[reg - m_reg_info.first_mpxr].bytes, sizeof(MPXReg)); + } + else + { + ::memcpy(m_fpr.xstate.xsave.mpxc[reg - m_reg_info.first_mpxc].bytes, + m_mpx_set.mpxc[reg - m_reg_info.first_mpxc].bytes, sizeof(MPXCsr)); + } + return true; +} + Error NativeRegisterContextLinux_x86_64::IsWatchpointHit(uint32_t wp_index, bool &is_hit) { diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h index b04be4bb768..5ac5f85ce57 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h @@ -111,6 +111,7 @@ namespace process_linux { uint32_t num_gpr_registers; uint32_t num_fpr_registers; uint32_t num_avx_registers; + uint32_t num_mpx_registers; uint32_t last_gpr; uint32_t first_fpr; @@ -124,6 +125,10 @@ namespace process_linux { uint32_t last_xmm; uint32_t first_ymm; uint32_t last_ymm; + uint32_t first_mpxr; + uint32_t last_mpxr; + uint32_t first_mpxc; + uint32_t last_mpxc; uint32_t first_dr; uint32_t gpr_flags; @@ -134,6 +139,7 @@ namespace process_linux { FPR m_fpr; IOVEC m_iovec; YMM m_ymm_set; + MPX m_mpx_set; RegInfo m_reg_info; uint64_t m_gpr_x86_64[k_num_gpr_registers_x86_64]; uint32_t m_fctrl_offset_in_userarea; @@ -160,7 +166,16 @@ namespace process_linux { CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order); bool - IsAVX (uint32_t reg_index) const; + CopyXSTATEtoMPX(uint32_t reg); + + bool + CopyMPXtoXSTATE(uint32_t reg); + + bool + IsAVX(uint32_t reg_index) const; + + bool + IsMPX(uint32_t reg_index) const; }; } // namespace process_linux |