mgorny created this revision.
mgorny added reviewers: krytarowski, labath, JDevlieghere.
Herald added a subscriber: emaste.

Provide a (conditional) support for the new PT_GETXSTATE
and PT_SETXSTATE ptrace() requests, and use them to implement getting
and setting YMM registers.  The functions used for splitting
and recombining YMM register data are based on matching functions
in FreeBSD plugin, with some simplification and updates to match NetBSD
structures.

// Note: the needed NetBSD kernel patches have not been committed yet, I'm 
asking for early feedback.


https://reviews.llvm.org/D63545

Files:
  lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
  lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
  lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
  lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h

Index: lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
===================================================================
--- lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
+++ lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h
@@ -14,6 +14,7 @@
 // clang-format off
 #include <sys/param.h>
 #include <sys/types.h>
+#include <sys/ptrace.h>
 #include <machine/reg.h>
 // clang-format on
 
@@ -21,6 +22,10 @@
 #include "Plugins/Process/Utility/RegisterContext_x86.h"
 #include "Plugins/Process/Utility/lldb-x86-register-enums.h"
 
+#if defined(PT_GETXSTATE) && defined(PT_SETXSTATE)
+#define HAVE_XSTATE
+#endif
+
 namespace lldb_private {
 namespace process_netbsd {
 
@@ -70,20 +75,31 @@
   void *GetGPRBuffer() override { return &m_gpr_x86_64; }
   void *GetFPRBuffer() override { return &m_fpr_x86_64; }
   void *GetDBRBuffer() override { return &m_dbr_x86_64; }
+#ifdef HAVE_XSTATE
+  void *GetXStateBuffer() override { return &m_xstate_x86_64; }
+  size_t GetXStateSize() override { return sizeof(m_xstate_x86_64); }
+#endif
 
 private:
   // Private member types.
-  enum { GPRegSet, FPRegSet, DBRegSet };
+  enum { GPRegSet, FPRegSet, DBRegSet, XStateRegSet };
 
   // Private member variables.
   struct reg m_gpr_x86_64;
   struct fpreg m_fpr_x86_64;
   struct dbreg m_dbr_x86_64;
+#ifdef HAVE_XSTATE
+  struct xstate m_xstate_x86_64;
+#endif
 
   int GetSetForNativeRegNum(int reg_num) const;
 
   Status ReadRegisterSet(uint32_t set);
   Status WriteRegisterSet(uint32_t set);
+
+  YMMReg CopyXSTATEtoYMM(uint32_t reg_index, lldb::ByteOrder byte_order);
+  void CopyYMMtoXSTATE(uint32_t reg_index, lldb::ByteOrder byte_order,
+                       YMMReg reg);
 };
 
 } // namespace process_netbsd
Index: lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
===================================================================
--- lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
+++ lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp
@@ -22,6 +22,8 @@
 #include <sys/types.h>
 #include <sys/sysctl.h>
 #include <x86/cpu.h>
+#include <x86/cpu_extended_state.h>
+#include <x86/specialreg.h>
 #include <elf.h>
 #include <err.h>
 #include <stdint.h>
@@ -199,7 +201,7 @@
   else if (reg_num <= k_last_fpr_x86_64)
     return (fpu_present == 1 && osfxsr == 1 && fpu_save >= 1) ? FPRegSet : -1;
   else if (reg_num <= k_last_avx_x86_64)
-    return -1; // AVX
+    return (fpu_present == 1 && fpu_save >= 2) ? XStateRegSet : -1; // AVX
   else if (reg_num <= k_last_mpxr_x86_64)
     return -1; // MPXR
   else if (reg_num <= k_last_mpxc_x86_64)
@@ -218,6 +220,10 @@
     return ReadFPR();
   case DBRegSet:
     return ReadDBR();
+  case XStateRegSet:
+    return ReadXState();
+  default:
+    break;
   }
   llvm_unreachable("NativeRegisterContextNetBSD_x86_64::ReadRegisterSet");
 }
@@ -230,10 +236,74 @@
     return WriteFPR();
   case DBRegSet:
     return WriteDBR();
+  case XStateRegSet:
+    return WriteXState();
+  default:
+    break;
   }
   llvm_unreachable("NativeRegisterContextNetBSD_x86_64::WriteRegisterSet");
 }
 
+YMMReg NativeRegisterContextNetBSD_x86_64::CopyXSTATEtoYMM(
+    uint32_t reg_index, lldb::ByteOrder byte_order) {
+#ifdef HAVE_XSTATE
+  YMMReg ret;
+
+  if (byte_order == lldb::eByteOrderLittle) {
+    ::memcpy(ret.bytes,
+             m_xstate_x86_64.xs_fxsave.fx_xmm[reg_index].xmm_bytes,
+             sizeof(XMMReg));
+    ::memcpy(ret.bytes + sizeof(XMMReg),
+             m_xstate_x86_64.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes,
+             sizeof(YMMHReg));
+    return ret;
+  }
+
+  if (byte_order == lldb::eByteOrderBig) {
+    ::memcpy(ret.bytes + sizeof(XMMReg),
+             m_xstate_x86_64.xs_fxsave.fx_xmm[reg_index].xmm_bytes,
+             sizeof(XMMReg));
+    ::memcpy(ret.bytes,
+             m_xstate_x86_64.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes,
+             sizeof(YMMHReg));
+    return ret;
+  }
+
+  llvm_unreachable("invalid byte order");
+#else
+  llvm_unreachable("CopyXSTATEtoYMM() called without XState support");
+#endif
+}
+
+void NativeRegisterContextNetBSD_x86_64::CopyYMMtoXSTATE(
+    uint32_t reg_index, lldb::ByteOrder byte_order, YMMReg reg) {
+#ifdef HAVE_XSTATE
+  if (byte_order == lldb::eByteOrderLittle) {
+    ::memcpy(m_xstate_x86_64.xs_fxsave.fx_xmm[reg_index].xmm_bytes,
+             reg.bytes,
+             sizeof(XMMReg));
+    ::memcpy(m_xstate_x86_64.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes,
+             reg.bytes + sizeof(XMMReg),
+             sizeof(YMMHReg));
+    return;
+  }
+
+  if (byte_order == lldb::eByteOrderBig) {
+    ::memcpy(m_xstate_x86_64.xs_fxsave.fx_xmm[reg_index].xmm_bytes,
+             reg.bytes + sizeof(XMMReg),
+             sizeof(XMMReg));
+    ::memcpy(m_xstate_x86_64.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes,
+             reg.bytes,
+             sizeof(YMMHReg));
+    return;
+  }
+
+  llvm_unreachable("invalid byte order");
+#else
+  llvm_unreachable("CopyYMMtoXSTATE() called without XState support");
+#endif
+}
+
 Status
 NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info,
                                                  RegisterValue &reg_value) {
@@ -411,6 +481,37 @@
     reg_value.SetBytes(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
                        reg_info->byte_size, endian::InlHostByteOrder());
     break;
+  case lldb_ymm0_x86_64:
+  case lldb_ymm1_x86_64:
+  case lldb_ymm2_x86_64:
+  case lldb_ymm3_x86_64:
+  case lldb_ymm4_x86_64:
+  case lldb_ymm5_x86_64:
+  case lldb_ymm6_x86_64:
+  case lldb_ymm7_x86_64:
+  case lldb_ymm8_x86_64:
+  case lldb_ymm9_x86_64:
+  case lldb_ymm10_x86_64:
+  case lldb_ymm11_x86_64:
+  case lldb_ymm12_x86_64:
+  case lldb_ymm13_x86_64:
+  case lldb_ymm14_x86_64:
+  case lldb_ymm15_x86_64:
+#ifdef HAVE_XSTATE
+    if (!(m_xstate_x86_64.xs_rfbm & XCR0_SSE) ||
+        !(m_xstate_x86_64.xs_rfbm & XCR0_YMM_Hi128)) {
+      error.SetErrorStringWithFormat("register \"%s\" not supported by CPU/kernel",
+                                     reg_info->name);
+    } else {
+      YMMReg ymm = CopyXSTATEtoYMM(reg - lldb_ymm0_x86_64,
+                                   endian::InlHostByteOrder());
+      reg_value.SetBytes(ymm.bytes, reg_info->byte_size,
+                         endian::InlHostByteOrder());
+    }
+#else
+    error.SetErrorString("XState queries not supported by the kernel");
+#endif
+    break;
   case lldb_dr0_x86_64:
   case lldb_dr1_x86_64:
   case lldb_dr2_x86_64:
@@ -603,6 +704,36 @@
     ::memcpy(&m_fpr_x86_64.fxstate.fx_xmm[reg - lldb_xmm0_x86_64],
              reg_value.GetBytes(), reg_value.GetByteSize());
     break;
+  case lldb_ymm0_x86_64:
+  case lldb_ymm1_x86_64:
+  case lldb_ymm2_x86_64:
+  case lldb_ymm3_x86_64:
+  case lldb_ymm4_x86_64:
+  case lldb_ymm5_x86_64:
+  case lldb_ymm6_x86_64:
+  case lldb_ymm7_x86_64:
+  case lldb_ymm8_x86_64:
+  case lldb_ymm9_x86_64:
+  case lldb_ymm10_x86_64:
+  case lldb_ymm11_x86_64:
+  case lldb_ymm12_x86_64:
+  case lldb_ymm13_x86_64:
+  case lldb_ymm14_x86_64:
+  case lldb_ymm15_x86_64:
+#ifdef HAVE_XSTATE
+    if (!(m_xstate_x86_64.xs_rfbm & XCR0_SSE) ||
+        !(m_xstate_x86_64.xs_rfbm & XCR0_YMM_Hi128)) {
+      error.SetErrorStringWithFormat("register \"%s\" not supported by CPU/kernel",
+                                     reg_info->name);
+    } else {
+      YMMReg ymm;
+      ::memcpy(ymm.bytes, reg_value.GetBytes(), reg_value.GetByteSize());
+      CopyYMMtoXSTATE(reg - lldb_ymm0_x86_64, endian::InlHostByteOrder(), ymm);
+    }
+#else
+    error.SetErrorString("XState not supported by the kernel");
+#endif
+    break;
   case lldb_dr0_x86_64:
   case lldb_dr1_x86_64:
   case lldb_dr2_x86_64:
Index: lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
===================================================================
--- lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
+++ lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h
@@ -41,6 +41,9 @@
   virtual Status ReadDBR();
   virtual Status WriteDBR();
 
+  virtual Status ReadXState();
+  virtual Status WriteXState();
+
   virtual void *GetGPRBuffer() { return nullptr; }
   virtual size_t GetGPRSize() {
     return GetRegisterInfoInterface().GetGPRSize();
@@ -52,6 +55,9 @@
   virtual void *GetDBRBuffer() { return nullptr; }
   virtual size_t GetDBRSize() { return 0; }
 
+  virtual void *GetXStateBuffer() { return nullptr; }
+  virtual size_t GetXStateSize() { return 0; }
+
   virtual Status DoReadGPR(void *buf);
   virtual Status DoWriteGPR(void *buf);
 
@@ -61,6 +67,9 @@
   virtual Status DoReadDBR(void *buf);
   virtual Status DoWriteDBR(void *buf);
 
+  virtual Status DoReadXState(void *buf, size_t buflen);
+  virtual Status DoWriteXState(void *buf, size_t buflen);
+
   virtual NativeProcessNetBSD &GetProcess();
   virtual ::pid_t GetProcessPid();
 };
Index: lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
===================================================================
--- lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
+++ lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp
@@ -16,6 +16,7 @@
 // clang-format off
 #include <sys/types.h>
 #include <sys/ptrace.h>
+#include <sys/uio.h>
 // clang-format on
 
 NativeRegisterContextNetBSD::NativeRegisterContextNetBSD(
@@ -72,6 +73,28 @@
   return DoWriteDBR(buf);
 }
 
+Status NativeRegisterContextNetBSD::ReadXState() {
+  void *buf = GetXStateBuffer();
+  size_t buflen = GetXStateSize();
+  if (!buf)
+    return Status("XState buffer is NULL");
+  if (buflen == 0)
+    return Status("XState length is zero");
+
+  return DoReadXState(buf, buflen);
+}
+
+Status NativeRegisterContextNetBSD::WriteXState() {
+  void *buf = GetXStateBuffer();
+  size_t buflen = GetXStateSize();
+  if (!buf)
+    return Status("XState buffer is NULL");
+  if (buflen == 0)
+    return Status("XState length is zero");
+
+  return DoWriteXState(buf, buflen);
+}
+
 Status NativeRegisterContextNetBSD::DoReadGPR(void *buf) {
   return NativeProcessNetBSD::PtraceWrapper(PT_GETREGS, GetProcessPid(), buf,
                                             m_thread.GetID());
@@ -102,6 +125,32 @@
                                             m_thread.GetID());
 }
 
+Status NativeRegisterContextNetBSD::DoReadXState(void *buf, size_t buflen) {
+#ifdef PT_GETXSTATE
+  struct iovec iov = {
+    .iov_base = buf,
+    .iov_len = buflen
+  };
+  return NativeProcessNetBSD::PtraceWrapper(PT_GETXSTATE, GetProcessPid(), &iov,
+                                            m_thread.GetID());
+#else
+  return Status("PT_GETXSTATE not supported by the kernel");
+#endif
+}
+
+Status NativeRegisterContextNetBSD::DoWriteXState(void *buf, size_t buflen) {
+#ifdef PT_SETXSTATE
+  struct iovec iov = {
+    .iov_base = buf,
+    .iov_len = buflen
+  };
+  return NativeProcessNetBSD::PtraceWrapper(PT_SETXSTATE, GetProcessPid(), &iov,
+                                            m_thread.GetID());
+#else
+  return Status("PT_SETXSTATE not supported by the kernel");
+#endif
+}
+
 NativeProcessNetBSD &NativeRegisterContextNetBSD::GetProcess() {
   return static_cast<NativeProcessNetBSD &>(m_thread.GetProcess());
 }
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to