valentinagiusti updated this revision to Diff 71371.
valentinagiusti added a comment.

moved header to the bottom and moved enum into header file


https://reviews.llvm.org/D24559

Files:
  source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
  source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
  source/Plugins/Process/Utility/RegisterContext_x86.h

Index: source/Plugins/Process/Utility/RegisterContext_x86.h
===================================================================
--- source/Plugins/Process/Utility/RegisterContext_x86.h
+++ source/Plugins/Process/Utility/RegisterContext_x86.h
@@ -277,7 +277,9 @@
   uint32_t mxcsrmask; // MXCSR Mask
   MMSReg stmm[8];     // 8*16 bytes for each FP-reg = 128 bytes
   XMMReg xmm[16];     // 16*16 bytes for each XMM-reg = 256 bytes
-  uint32_t padding[24];
+  uint8_t padding1[48];
+  uint64_t xcr0;
+  uint8_t padding2[40];
 };
 
 //---------------------------------------------------------------------------
Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
===================================================================
--- source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
+++ source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h
@@ -77,7 +77,8 @@
 
 private:
   // Private member types.
-  enum FPRType { eFPRTypeNotValid = 0, eFPRTypeFXSAVE, eFPRTypeXSAVE };
+  enum XStateType { eXStateTypeNotValid = 0, eXStateTypeFXSAVE, eXStateTypeXSAVE };
+  enum RegSet { gpr, fpu, avx, mpx };
 
   // Info about register ranges.
   struct RegInfo {
@@ -106,26 +107,30 @@
   };
 
   // Private member variables.
-  mutable FPRType m_fpr_type;
-  FPR m_fpr;
+  mutable XStateType m_xstate_type;
+  FPR m_fpr; // Extended States Area, named FPR for historical reasons.
   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;
 
   // Private member methods.
+  bool HasFXSAVE() const;
+
+  bool HasXSAVE() const;
+
+  bool IsCPUFeatureAvailable(RegSet feature_code) const;
+
   bool IsRegisterSetAvailable(uint32_t set_index) const;
 
   bool IsGPR(uint32_t reg_index) const;
 
-  FPRType GetFPRType() const;
+  XStateType GetXStateType() const;
 
   bool IsFPR(uint32_t reg_index) const;
 
-  bool IsFPR(uint32_t reg_index, FPRType fpr_type) const;
-
   bool CopyXSTATEtoYMM(uint32_t reg_index, lldb::ByteOrder byte_order);
 
   bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order);
Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
===================================================================
--- source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
+++ source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp
@@ -20,6 +20,8 @@
 #include "Plugins/Process/Utility/RegisterContextLinux_i386.h"
 #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
 
+#include <cpuid.h>
+
 using namespace lldb_private;
 using namespace lldb_private::process_linux;
 
@@ -218,6 +220,23 @@
 #define NT_PRXFPREG 0x46e62b7f
 #endif
 
+// ----------------------------------------------------------------------------
+// Required MPX define.
+// ----------------------------------------------------------------------------
+
+// Support MPX extensions also if compiled with compiler without MPX support.
+#ifndef bit_MPX
+#define bit_MPX 0x4000
+#endif
+
+// ----------------------------------------------------------------------------
+// XCR0 extended register sets masks.
+// ----------------------------------------------------------------------------
+#define mask_XSTATE_AVX (1ULL << 2)
+#define mask_XSTATE_BNDREGS (1ULL << 3)
+#define mask_XSTATE_BNDCFG (1ULL << 4)
+#define mask_XSTATE_MPX (mask_XSTATE_BNDREGS | mask_XSTATE_BNDCFG)
+
 NativeRegisterContextLinux *
 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(
     const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
@@ -249,7 +268,7 @@
     uint32_t concrete_frame_idx)
     : NativeRegisterContextLinux(native_thread, concrete_frame_idx,
                                  CreateRegisterInfoInterface(target_arch)),
-      m_fpr_type(eFPRTypeNotValid), m_fpr(), m_iovec(), m_ymm_set(),
+      m_xstate_type(eXStateTypeNotValid), m_fpr(), m_iovec(), m_ymm_set(),
       m_mpx_set(), m_reg_info(), m_gpr_x86_64() {
   // Set up data about ranges of valid registers.
   switch (target_arch.GetMachine()) {
@@ -379,7 +398,7 @@
     return error;
   }
 
-  if (IsFPR(reg, GetFPRType())) {
+  if (IsFPR(reg) || IsAVX(reg) || IsMPX(reg)) {
     error = ReadFPR();
     if (error.Fail())
       return error;
@@ -428,25 +447,25 @@
             reg_info->byte_size, byte_order);
       if (reg >= m_reg_info.first_ymm && reg <= m_reg_info.last_ymm) {
         // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes
-        if (GetFPRType() == eFPRTypeXSAVE && CopyXSTATEtoYMM(reg, byte_order))
+        if (CopyXSTATEtoYMM(reg, byte_order))
           reg_value.SetBytes(m_ymm_set.ymm[reg - m_reg_info.first_ymm].bytes,
                              reg_info->byte_size, byte_order);
         else {
           error.SetErrorString("failed to copy ymm register value");
           return error;
         }
       }
       if (reg >= m_reg_info.first_mpxr && reg <= m_reg_info.last_mpxr) {
-        if (GetFPRType() == eFPRTypeXSAVE && CopyXSTATEtoMPX(reg))
+        if (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))
+        if (CopyXSTATEtoMPX(reg))
           reg_value.SetBytes(m_mpx_set.mpxc[reg - m_reg_info.first_mpxc].bytes,
                              reg_info->byte_size, byte_order);
         else {
@@ -517,7 +536,7 @@
   if (IsGPR(reg_index))
     return WriteRegisterRaw(reg_index, reg_value);
 
-  if (IsFPR(reg_index, GetFPRType())) {
+  if (IsFPR(reg_index) || IsAVX(reg_index) || IsMPX(reg_index)) {
     if (reg_info->encoding == lldb::eEncodingVector) {
       if (reg_index >= m_reg_info.first_st && reg_index <= m_reg_info.last_st)
         ::memcpy(
@@ -536,9 +555,6 @@
 
       if (reg_index >= m_reg_info.first_ymm &&
           reg_index <= m_reg_info.last_ymm) {
-        if (GetFPRType() != eFPRTypeXSAVE)
-          return Error("target processor does not support AVX");
-
         // Store ymm register content, and split into the register halves in
         // xmm.bytes and ymmh.bytes
         ::memcpy(m_ymm_set.ymm[reg_index - m_reg_info.first_ymm].bytes,
@@ -549,20 +565,14 @@
 
       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))
@@ -654,31 +664,37 @@
 
   ::memcpy(dst, &m_gpr_x86_64, GetRegisterInfoInterface().GetGPRSize());
   dst += GetRegisterInfoInterface().GetGPRSize();
-  if (GetFPRType() == eFPRTypeFXSAVE)
+  if (GetXStateType() == eXStateTypeFXSAVE)
     ::memcpy(dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
-  else if (GetFPRType() == eFPRTypeXSAVE) {
+  else if (GetXStateType() == eXStateTypeXSAVE) {
     lldb::ByteOrder byte_order = GetByteOrder();
 
-    // Assemble the YMM register content from the register halves.
-    for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm;
-         ++reg) {
-      if (!CopyXSTATEtoYMM(reg, byte_order)) {
-        error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s "
-                                       "CopyXSTATEtoYMM() failed for reg num "
-                                       "%" PRIu32,
-                                       __FUNCTION__, reg);
-        return error;
+    if (IsCPUFeatureAvailable(avx)) {
+      // Assemble the YMM register content from the register halves.
+      for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm;
+           ++reg) {
+        if (!CopyXSTATEtoYMM(reg, byte_order)) {
+          error.SetErrorStringWithFormat(
+              "NativeRegisterContextLinux_x86_64::%s "
+              "CopyXSTATEtoYMM() failed for reg num "
+              "%" PRIu32,
+              __FUNCTION__, reg);
+          return error;
+        }
       }
     }
 
-    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;
+    if (IsCPUFeatureAvailable(mpx)) {
+      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.
@@ -740,110 +756,149 @@
     return error;
 
   src += GetRegisterInfoInterface().GetGPRSize();
-  if (GetFPRType() == eFPRTypeFXSAVE)
+  if (GetXStateType() == eXStateTypeFXSAVE)
     ::memcpy(&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave));
-  else if (GetFPRType() == eFPRTypeXSAVE)
+  else if (GetXStateType() == eXStateTypeXSAVE)
     ::memcpy(&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));
 
   error = WriteFPR();
   if (error.Fail())
     return error;
 
-  if (GetFPRType() == eFPRTypeXSAVE) {
+  if (GetXStateType() == eXStateTypeXSAVE) {
     lldb::ByteOrder byte_order = GetByteOrder();
 
-    // Parse the YMM register content from the register halves.
-    for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm;
-         ++reg) {
-      if (!CopyYMMtoXSTATE(reg, byte_order)) {
-        error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s "
-                                       "CopyYMMtoXSTATE() failed for reg num "
-                                       "%" PRIu32,
-                                       __FUNCTION__, reg);
-        return error;
+    if (IsCPUFeatureAvailable(avx)) {
+      // Parse the YMM register content from the register halves.
+      for (uint32_t reg = m_reg_info.first_ymm; reg <= m_reg_info.last_ymm;
+           ++reg) {
+        if (!CopyYMMtoXSTATE(reg, byte_order)) {
+          error.SetErrorStringWithFormat(
+              "NativeRegisterContextLinux_x86_64::%s "
+              "CopyYMMtoXSTATE() failed for reg num "
+              "%" PRIu32,
+              __FUNCTION__, reg);
+          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;
+    if (IsCPUFeatureAvailable(mpx)) {
+      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;
 }
 
+bool NativeRegisterContextLinux_x86_64::HasFXSAVE() const {
+  unsigned int rax, rbx, rcx, rdx;
+
+  // Check if FXSAVE is enabled.
+  if (!__get_cpuid(1, &rax, &rbx, &rcx, &rdx))
+    return false;
+  if ((rdx & bit_FXSAVE) == bit_FXSAVE) {
+    m_xstate_type = eXStateTypeFXSAVE;
+    if (const_cast<NativeRegisterContextLinux_x86_64 *>(this)->ReadFPR().Fail())
+      return false;
+    return true;
+  }
+  return false;
+}
+
+bool NativeRegisterContextLinux_x86_64::HasXSAVE() const {
+  unsigned int rax, rbx, rcx, rdx;
+
+  // Check if XSAVE is enabled.
+  if (!__get_cpuid(1, &rax, &rbx, &rcx, &rdx))
+    return false;
+  if ((rcx & bit_OSXSAVE) == bit_OSXSAVE) {
+    m_xstate_type = eXStateTypeXSAVE;
+    if (const_cast<NativeRegisterContextLinux_x86_64 *>(this)->ReadFPR().Fail())
+      return false;
+    return true;
+  }
+  return false;
+}
+
+bool NativeRegisterContextLinux_x86_64::IsCPUFeatureAvailable(
+    RegSet feature_code) const {
+  unsigned int rax, rbx, rcx, rdx;
+
+  // Check if XSAVE is enabled.
+  if (!HasXSAVE())
+    return false;
+
+  __get_cpuid(1, &rax, &rbx, &rcx, &rdx);
+  switch (feature_code) {
+  case avx: // Check if CPU has AVX and if there is kernel support, by reading in the XCR0 area of XSAVE.
+    if (((rcx & bit_AVX) != 0) && ((m_fpr.xstate.xsave.i387.xcr0 & mask_XSTATE_AVX) == mask_XSTATE_AVX))
+      return true;
+  case mpx: // Check if CPU has MPX and if there is kernel support, by reading in the XCR0 area of XSAVE.
+    if (__get_cpuid_max(0, NULL) > 7) {
+      __cpuid_count(7, 0, rax, rbx, rcx, rdx);
+      if (((rbx & bit_MPX) != 0) && ((m_fpr.xstate.xsave.i387.xcr0 & mask_XSTATE_MPX) == mask_XSTATE_MPX))
+        return true;
+    }
+  default:
+    return false;
+  }
+}
+
 bool NativeRegisterContextLinux_x86_64::IsRegisterSetAvailable(
     uint32_t set_index) const {
-  // Note: Extended register sets are assumed to be at the end of g_reg_sets.
   uint32_t num_sets = k_num_register_sets - k_num_extended_register_sets;
 
-  if (GetFPRType() == eFPRTypeXSAVE) {
-    // AVX is the first extended register set.
-    num_sets += 2;
+  switch (set_index) {
+  case gpr:
+  case fpu:
+    return (set_index < num_sets);
+  case avx:
+    return IsCPUFeatureAvailable(avx);
+  case mpx:
+    return IsCPUFeatureAvailable(mpx);
+  default:
+    return false;
   }
-  return (set_index < num_sets);
 }
 
 bool NativeRegisterContextLinux_x86_64::IsGPR(uint32_t reg_index) const {
   // GPRs come first.
   return reg_index <= m_reg_info.last_gpr;
 }
 
-NativeRegisterContextLinux_x86_64::FPRType
-NativeRegisterContextLinux_x86_64::GetFPRType() const {
-  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
-  if (m_fpr_type == eFPRTypeNotValid) {
-    // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx.
-
-    // Try and see if AVX register retrieval works.
-    m_fpr_type = eFPRTypeXSAVE;
-    if (const_cast<NativeRegisterContextLinux_x86_64 *>(this)
-            ->ReadFPR()
-            .Fail()) {
-      // Fall back to general floating point with no AVX support.
-      m_fpr_type = eFPRTypeFXSAVE;
-
-      // Check if FXSAVE area can be read.
-      if (const_cast<NativeRegisterContextLinux_x86_64 *>(this)
-              ->ReadFPR()
-              .Fail()) {
-        if (log)
-          log->Printf("NativeRegisterContextLinux_x86_64::%s ptrace APIs "
-                      "failed to read XSAVE/FXSAVE area",
-                      __FUNCTION__);
-      }
-    }
+NativeRegisterContextLinux_x86_64::XStateType
+NativeRegisterContextLinux_x86_64::GetXStateType() const {
+  if (m_xstate_type == eXStateTypeNotValid) {
+    if (HasXSAVE())
+      m_xstate_type = eXStateTypeXSAVE;
+    else if (HasFXSAVE())
+      m_xstate_type = eXStateTypeFXSAVE;
   }
-  return m_fpr_type;
+  return m_xstate_type;
 }
 
 bool NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index) const {
   return (m_reg_info.first_fpr <= reg_index &&
           reg_index <= m_reg_info.last_fpr);
 }
 
-bool NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index,
-                                              FPRType fpr_type) const {
-  bool generic_fpr = IsFPR(reg_index);
-
-  if (fpr_type == eFPRTypeXSAVE)
-    return generic_fpr || IsAVX(reg_index) || IsMPX(reg_index);
-  return generic_fpr;
-}
-
 Error NativeRegisterContextLinux_x86_64::WriteFPR() {
-  const FPRType fpr_type = GetFPRType();
+  const XStateType fpr_type = GetXStateType();
   const lldb_private::ArchSpec &target_arch =
       GetRegisterInfoInterface().GetTargetArchitecture();
   switch (fpr_type) {
-  case FPRType::eFPRTypeFXSAVE:
+  case XStateType::eXStateTypeFXSAVE:
     // For 32-bit inferiors on x86_32/x86_64 architectures,
     // FXSAVE area can be written using PTRACE_SETREGSET ptrace api
     // For 64-bit inferiors on x86_64 architectures,
@@ -858,15 +913,17 @@
       assert(false && "Unhandled target architecture.");
       break;
     }
-  case FPRType::eFPRTypeXSAVE:
+  case XStateType::eXStateTypeXSAVE:
     return WriteRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave),
                             NT_X86_XSTATE);
   default:
     return Error("Unrecognized FPR type");
   }
 }
 
 bool NativeRegisterContextLinux_x86_64::IsAVX(uint32_t reg_index) const {
+  if (!IsCPUFeatureAvailable(avx))
+    return false;
   return (m_reg_info.first_ymm <= reg_index &&
           reg_index <= m_reg_info.last_ymm);
 }
@@ -926,35 +983,35 @@
 }
 
 void *NativeRegisterContextLinux_x86_64::GetFPRBuffer() {
-  const FPRType fpr_type = GetFPRType();
-  switch (fpr_type) {
-  case FPRType::eFPRTypeFXSAVE:
+  const XStateType xstate_type = GetXStateType();
+  switch (xstate_type) {
+  case XStateType::eXStateTypeFXSAVE:
     return &m_fpr.xstate.fxsave;
-  case FPRType::eFPRTypeXSAVE:
+  case XStateType::eXStateTypeXSAVE:
     return &m_iovec;
   default:
     return nullptr;
   }
 }
 
 size_t NativeRegisterContextLinux_x86_64::GetFPRSize() {
-  const FPRType fpr_type = GetFPRType();
-  switch (fpr_type) {
-  case FPRType::eFPRTypeFXSAVE:
+  const XStateType xstate_type = GetXStateType();
+  switch (xstate_type) {
+  case XStateType::eXStateTypeFXSAVE:
     return sizeof(m_fpr.xstate.fxsave);
-  case FPRType::eFPRTypeXSAVE:
+  case XStateType::eXStateTypeXSAVE:
     return sizeof(m_iovec);
   default:
     return 0;
   }
 }
 
 Error NativeRegisterContextLinux_x86_64::ReadFPR() {
-  const FPRType fpr_type = GetFPRType();
+  const XStateType xstate_type = GetXStateType();
   const lldb_private::ArchSpec &target_arch =
       GetRegisterInfoInterface().GetTargetArchitecture();
-  switch (fpr_type) {
-  case FPRType::eFPRTypeFXSAVE:
+  switch (xstate_type) {
+  case XStateType::eXStateTypeFXSAVE:
     // For 32-bit inferiors on x86_32/x86_64 architectures,
     // FXSAVE area can be read using PTRACE_GETREGSET ptrace api
     // For 64-bit inferiors on x86_64 architectures,
@@ -968,16 +1025,18 @@
       assert(false && "Unhandled target architecture.");
       break;
     }
-  case FPRType::eFPRTypeXSAVE:
+  case XStateType::eXStateTypeXSAVE:
     return ReadRegisterSet(&m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
   default:
     return Error("Unrecognized FPR type");
   }
 }
 
 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);
+  if (!IsCPUFeatureAvailable(mpx))
+    return false;
+  return (m_reg_info.first_mpxr <= reg_index &&
+          reg_index <= m_reg_info.last_mpxc);
 }
 
 bool NativeRegisterContextLinux_x86_64::CopyXSTATEtoMPX(uint32_t reg) {
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to