[Lldb-commits] [lldb] 567ba6c - [LLDB] Add ptrace register access for AArch64 SVE registers

Muhammad Omair Javaid via lldb-commits lldb-commits at lists.llvm.org
Wed Aug 19 03:11:14 PDT 2020


Author: Muhammad Omair Javaid
Date: 2020-08-19T15:11:01+05:00
New Revision: 567ba6c468b93accefed944e5a44b1052d3597de

URL: https://github.com/llvm/llvm-project/commit/567ba6c468b93accefed944e5a44b1052d3597de
DIFF: https://github.com/llvm/llvm-project/commit/567ba6c468b93accefed944e5a44b1052d3597de.diff

LOG: [LLDB] Add ptrace register access for AArch64 SVE registers

This patch adds NativeRegisterContext_arm64 ptrace routines to access
AArch64 SVE register set. This patch also adds a test-case to test
AArch64 SVE register access and dynamic size configuration capability.

Reviewed By: labath

Differential Revision: https://reviews.llvm.org/D79699

Added: 
    lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/Makefile
    lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/TestSVERegisters.py
    lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/main.c

Modified: 
    lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
    lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
    lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
    lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
    lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
index beae3aef7c07..f7b398ce620d 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
@@ -21,14 +21,17 @@
 #include "Plugins/Process/Linux/NativeProcessLinux.h"
 #include "Plugins/Process/Linux/Procfs.h"
 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
 
 // System includes - They have to be included after framework includes because
 // they define some macros which collide with variable names in other modules
 #include <sys/socket.h>
 // NT_PRSTATUS and NT_FPREGSET definition
 #include <elf.h>
-// user_hwdebug_state definition
-#include <asm/ptrace.h>
+
+#ifndef NT_ARM_SVE
+#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension */
+#endif
 
 #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize())
 
@@ -59,14 +62,21 @@ NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64(
   ::memset(&m_gpr_arm64, 0, sizeof(m_gpr_arm64));
   ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
   ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs));
+  ::memset(&m_sve_header, 0, sizeof(m_sve_header));
 
   // 16 is just a maximum value, query hardware for actual watchpoint count
   m_max_hwp_supported = 16;
   m_max_hbp_supported = 16;
+
   m_refresh_hwdebug_info = true;
 
   m_gpr_is_valid = false;
   m_fpu_is_valid = false;
+  m_sve_buffer_is_valid = false;
+  m_sve_header_is_valid = false;
+
+  // SVE is not enabled until we query user_sve_header
+  m_sve_state = SVEState::Unknown;
 }
 
 RegisterInfoPOSIX_arm64 &
@@ -109,28 +119,96 @@ NativeRegisterContextLinux_arm64::ReadRegister(const RegisterInfo *reg_info,
 
   uint8_t *src;
   uint32_t offset;
+  uint64_t sve_vg;
+  std::vector<uint8_t> sve_reg_non_live;
 
   if (IsGPR(reg)) {
-    if (!m_gpr_is_valid) {
-      error = ReadGPR();
-      if (error.Fail())
-        return error;
-    }
+    error = ReadGPR();
+    if (error.Fail())
+      return error;
 
     offset = reg_info->byte_offset;
     assert(offset < GetGPRSize());
     src = (uint8_t *)GetGPRBuffer() + offset;
 
   } else if (IsFPR(reg)) {
-    if (!m_fpu_is_valid) {
-
+    if (m_sve_state == SVEState::Disabled) {
+      // SVE is disabled take legacy route for FPU register access
       error = ReadFPR();
       if (error.Fail())
         return error;
+
+      offset = CalculateFprOffset(reg_info);
+      assert(offset < GetFPRSize());
+      src = (uint8_t *)GetFPRBuffer() + offset;
+    } else {
+      // SVE enabled, we will read and cache SVE ptrace data
+      error = ReadAllSVE();
+      if (error.Fail())
+        return error;
+
+      // FPSR and FPCR will be located right after Z registers in
+      // SVEState::FPSIMD while in SVEState::Full they will be located at the
+      // end of register data after an alignment correction based on currently
+      // selected vector length.
+      uint32_t sve_reg_num = LLDB_INVALID_REGNUM;
+      if (reg == GetRegisterInfo().GetRegNumFPSR()) {
+        sve_reg_num = reg;
+        if (m_sve_state == SVEState::Full)
+          offset = SVE_PT_SVE_FPSR_OFFSET(sve_vq_from_vl(m_sve_header.vl));
+        else if (m_sve_state == SVEState::FPSIMD)
+          offset = SVE_PT_FPSIMD_OFFSET + (32 * 16);
+      } else if (reg == GetRegisterInfo().GetRegNumFPCR()) {
+        sve_reg_num = reg;
+        if (m_sve_state == SVEState::Full)
+          offset = SVE_PT_SVE_FPCR_OFFSET(sve_vq_from_vl(m_sve_header.vl));
+        else if (m_sve_state == SVEState::FPSIMD)
+          offset = SVE_PT_FPSIMD_OFFSET + (32 * 16) + 4;
+      } else {
+        // Extract SVE Z register value register number for this reg_info
+        if (reg_info->value_regs &&
+            reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
+          sve_reg_num = reg_info->value_regs[0];
+        offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num));
+      }
+
+      offset = CalculateSVEOffset(reg_info);
+      assert(offset < GetSVEBufferSize());
+      src = (uint8_t *)GetSVEBuffer() + offset;
+    }
+  } else if (IsSVE(reg)) {
+
+    if (m_sve_state == SVEState::Disabled || m_sve_state == SVEState::Unknown)
+      return Status("SVE disabled or not supported");
+
+    if (GetRegisterInfo().IsSVERegVG(reg)) {
+      sve_vg = GetSVERegVG();
+      src = (uint8_t *)&sve_vg;
+    } else {
+      // SVE enabled, we will read and cache SVE ptrace data
+      error = ReadAllSVE();
+      if (error.Fail())
+        return error;
+
+      if (m_sve_state == SVEState::FPSIMD) {
+        // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so
+        // just copy 16 bytes of v register to the start of z register. All
+        // other SVE register will be set to zero.
+        sve_reg_non_live.resize(reg_info->byte_size, 0);
+        src = sve_reg_non_live.data();
+
+        if (GetRegisterInfo().IsSVEZReg(reg)) {
+          offset = CalculateSVEOffset(reg_info);
+          assert(offset < GetSVEBufferSize());
+          ::memcpy(sve_reg_non_live.data(), (uint8_t *)GetSVEBuffer() + offset,
+                   16);
+        }
+      } else {
+        offset = CalculateSVEOffset(reg_info);
+        assert(offset < GetSVEBufferSize());
+        src = (uint8_t *)GetSVEBuffer() + offset;
+      }
     }
-    offset = CalculateFprOffset(reg_info);
-    assert(offset < GetFPRSize());
-    src = (uint8_t *)GetFPRBuffer() + offset;
   } else
     return Status("failed - register wasn't recognized to be a GPR or an FPR, "
                   "write strategy unknown");
@@ -157,37 +235,125 @@ Status NativeRegisterContextLinux_arm64::WriteRegister(
 
   uint8_t *dst;
   uint32_t offset;
+  std::vector<uint8_t> sve_reg_non_live;
 
   if (IsGPR(reg)) {
-    if (!m_gpr_is_valid) {
-      error = ReadGPR();
-      if (error.Fail())
-        return error;
-    }
-
-    offset = reg_info->byte_offset;
-    assert(offset < GetGPRSize());
-    dst = (uint8_t *)GetGPRBuffer() + offset;
+    error = ReadGPR();
+    if (error.Fail())
+      return error;
 
+    assert(reg_info->byte_offset < GetGPRSize());
+    dst = (uint8_t *)GetGPRBuffer() + reg_info->byte_offset;
     ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
 
     return WriteGPR();
   } else if (IsFPR(reg)) {
-    if (!m_fpu_is_valid) {
+    if (m_sve_state == SVEState::Disabled) {
+      // SVE is disabled take legacy route for FPU register access
       error = ReadFPR();
       if (error.Fail())
         return error;
-    }
-    offset = CalculateFprOffset(reg_info);
-    assert(offset < GetFPRSize());
-    dst = (uint8_t *)GetFPRBuffer() + offset;
 
-    ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
+      offset = CalculateFprOffset(reg_info);
+      assert(offset < GetFPRSize());
+      dst = (uint8_t *)GetFPRBuffer() + offset;
+      ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
+
+      return WriteFPR();
+    } else {
+      // SVE enabled, we will read and cache SVE ptrace data
+      error = ReadAllSVE();
+      if (error.Fail())
+        return error;
+
+      // FPSR and FPCR will be located right after Z registers in
+      // SVEState::FPSIMD while in SVEState::Full they will be located at the
+      // end of register data after an alignment correction based on currently
+      // selected vector length.
+      uint32_t sve_reg_num = LLDB_INVALID_REGNUM;
+      if (reg == GetRegisterInfo().GetRegNumFPSR()) {
+        sve_reg_num = reg;
+        if (m_sve_state == SVEState::Full)
+          offset = SVE_PT_SVE_FPSR_OFFSET(sve_vq_from_vl(m_sve_header.vl));
+        else if (m_sve_state == SVEState::FPSIMD)
+          offset = SVE_PT_FPSIMD_OFFSET + (32 * 16);
+      } else if (reg == GetRegisterInfo().GetRegNumFPCR()) {
+        sve_reg_num = reg;
+        if (m_sve_state == SVEState::Full)
+          offset = SVE_PT_SVE_FPCR_OFFSET(sve_vq_from_vl(m_sve_header.vl));
+        else if (m_sve_state == SVEState::FPSIMD)
+          offset = SVE_PT_FPSIMD_OFFSET + (32 * 16) + 4;
+      } else {
+        // Extract SVE Z register value register number for this reg_info
+        if (reg_info->value_regs &&
+            reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
+          sve_reg_num = reg_info->value_regs[0];
+        offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num));
+      }
 
-    return WriteFPR();
+      offset = CalculateSVEOffset(reg_info);
+      assert(offset < GetSVEBufferSize());
+      dst = (uint8_t *)GetSVEBuffer() + offset;
+      ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
+      return WriteAllSVE();
+    }
+  } else if (IsSVE(reg)) {
+    if (m_sve_state == SVEState::Disabled || m_sve_state == SVEState::Unknown)
+      return Status("SVE disabled or not supported");
+    else {
+      if (GetRegisterInfo().IsSVERegVG(reg))
+        return Status("SVE state change operation not supported");
+
+      // Target has SVE enabled, we will read and cache SVE ptrace data
+      error = ReadAllSVE();
+      if (error.Fail())
+        return error;
+
+      // If target supports SVE but currently in FPSIMD mode.
+      if (m_sve_state == SVEState::FPSIMD) {
+        // Here we will check if writing this SVE register enables
+        // SVEState::Full
+        bool set_sve_state_full = false;
+        const uint8_t *reg_bytes = (const uint8_t *)reg_value.GetBytes();
+        if (GetRegisterInfo().IsSVEZReg(reg)) {
+          for (uint32_t i = 16; i < reg_info->byte_size; i++) {
+            if (reg_bytes[i]) {
+              set_sve_state_full = true;
+              break;
+            }
+          }
+        } else if (GetRegisterInfo().IsSVEPReg(reg) ||
+                   reg == GetRegisterInfo().GetRegNumSVEFFR()) {
+          for (uint32_t i = 0; i < reg_info->byte_size; i++) {
+            if (reg_bytes[i]) {
+              set_sve_state_full = true;
+              break;
+            }
+          }
+        }
+
+        if (!set_sve_state_full && GetRegisterInfo().IsSVEZReg(reg)) {
+          // We are writing a Z register which is zero beyond 16 bytes so copy
+          // first 16 bytes only as SVE payload mirrors legacy fpsimd structure
+          offset = CalculateSVEOffset(reg_info);
+          assert(offset < GetSVEBufferSize());
+          dst = (uint8_t *)GetSVEBuffer() + offset;
+          ::memcpy(dst, reg_value.GetBytes(), 16);
+
+          return WriteAllSVE();
+        } else
+          return Status("SVE state change operation not supported");
+      } else {
+        offset = CalculateSVEOffset(reg_info);
+        assert(offset < GetSVEBufferSize());
+        dst = (uint8_t *)GetSVEBuffer() + offset;
+        ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size);
+        return WriteAllSVE();
+      }
+    }
   }
 
-  return error;
+  return Status("Failed to write register value");
 }
 
 Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues(
@@ -195,17 +361,15 @@ Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues(
   Status error;
 
   data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0));
-  if (!m_gpr_is_valid) {
-    error = ReadGPR();
-    if (error.Fail())
-      return error;
-  }
 
-  if (!m_fpu_is_valid) {
-    error = ReadFPR();
-    if (error.Fail())
-      return error;
-  }
+  error = ReadGPR();
+  if (error.Fail())
+    return error;
+
+  error = ReadFPR();
+  if (error.Fail())
+    return error;
+
   uint8_t *dst = data_sp->GetBytes();
   ::memcpy(dst, GetGPRBuffer(), GetGPRSize());
   dst += GetGPRSize();
@@ -271,6 +435,13 @@ bool NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const {
   return false;
 }
 
+bool NativeRegisterContextLinux_arm64::IsSVE(unsigned reg) const {
+  if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
+      RegisterInfoPOSIX_arm64::SVERegSet)
+    return true;
+  return false;
+}
+
 uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareBreakpoints() {
   Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS));
 
@@ -762,8 +933,10 @@ Status NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) {
 Status NativeRegisterContextLinux_arm64::ReadGPR() {
   Status error;
 
-  struct iovec ioVec;
+  if (m_gpr_is_valid)
+    return error;
 
+  struct iovec ioVec;
   ioVec.iov_base = GetGPRBuffer();
   ioVec.iov_len = GetGPRSize();
 
@@ -776,21 +949,26 @@ Status NativeRegisterContextLinux_arm64::ReadGPR() {
 }
 
 Status NativeRegisterContextLinux_arm64::WriteGPR() {
-  struct iovec ioVec;
-
-  m_gpr_is_valid = false;
+  Status error = ReadGPR();
+  if (error.Fail())
+    return error;
 
+  struct iovec ioVec;
   ioVec.iov_base = GetGPRBuffer();
   ioVec.iov_len = GetGPRSize();
 
+  m_gpr_is_valid = false;
+
   return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS);
 }
 
 Status NativeRegisterContextLinux_arm64::ReadFPR() {
   Status error;
 
-  struct iovec ioVec;
+  if (m_fpu_is_valid)
+    return error;
 
+  struct iovec ioVec;
   ioVec.iov_base = GetFPRBuffer();
   ioVec.iov_len = GetFPRSize();
 
@@ -803,19 +981,122 @@ Status NativeRegisterContextLinux_arm64::ReadFPR() {
 }
 
 Status NativeRegisterContextLinux_arm64::WriteFPR() {
-  struct iovec ioVec;
-
-  m_fpu_is_valid = false;
+  Status error = ReadFPR();
+  if (error.Fail())
+    return error;
 
+  struct iovec ioVec;
   ioVec.iov_base = GetFPRBuffer();
   ioVec.iov_len = GetFPRSize();
 
+  m_fpu_is_valid = false;
+
   return WriteRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET);
 }
 
 void NativeRegisterContextLinux_arm64::InvalidateAllRegisters() {
   m_gpr_is_valid = false;
   m_fpu_is_valid = false;
+  m_sve_buffer_is_valid = false;
+  m_sve_header_is_valid = false;
+
+  // Update SVE registers in case there is change in configuration.
+  ConfigureRegisterContext();
+}
+
+Status NativeRegisterContextLinux_arm64::ReadSVEHeader() {
+  Status error;
+
+  if (m_sve_header_is_valid)
+    return error;
+
+  struct iovec ioVec;
+  ioVec.iov_base = GetSVEHeader();
+  ioVec.iov_len = GetSVEHeaderSize();
+
+  error = ReadRegisterSet(&ioVec, GetSVEHeaderSize(), NT_ARM_SVE);
+
+  m_sve_header_is_valid = true;
+
+  return error;
+}
+
+Status NativeRegisterContextLinux_arm64::WriteSVEHeader() {
+  Status error;
+
+  error = ReadSVEHeader();
+  if (error.Fail())
+    return error;
+
+  struct iovec ioVec;
+  ioVec.iov_base = GetSVEHeader();
+  ioVec.iov_len = GetSVEHeaderSize();
+
+  m_sve_buffer_is_valid = false;
+  m_sve_header_is_valid = false;
+  m_fpu_is_valid = false;
+
+  return WriteRegisterSet(&ioVec, GetSVEHeaderSize(), NT_ARM_SVE);
+}
+
+Status NativeRegisterContextLinux_arm64::ReadAllSVE() {
+  Status error;
+
+  if (m_sve_buffer_is_valid)
+    return error;
+
+  struct iovec ioVec;
+  ioVec.iov_base = GetSVEBuffer();
+  ioVec.iov_len = GetSVEBufferSize();
+
+  error = ReadRegisterSet(&ioVec, GetSVEBufferSize(), NT_ARM_SVE);
+
+  if (error.Success())
+    m_sve_buffer_is_valid = true;
+
+  return error;
+}
+
+Status NativeRegisterContextLinux_arm64::WriteAllSVE() {
+  Status error;
+
+  error = ReadAllSVE();
+  if (error.Fail())
+    return error;
+
+  struct iovec ioVec;
+
+  ioVec.iov_base = GetSVEBuffer();
+  ioVec.iov_len = GetSVEBufferSize();
+
+  m_sve_buffer_is_valid = false;
+  m_sve_header_is_valid = false;
+  m_fpu_is_valid = false;
+
+  return WriteRegisterSet(&ioVec, GetSVEBufferSize(), NT_ARM_SVE);
+}
+
+void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() {
+  // Read SVE configuration data and configure register infos.
+  if (!m_sve_header_is_valid && m_sve_state != SVEState::Disabled) {
+    Status error = ReadSVEHeader();
+    if (!error.Success() && m_sve_state == SVEState::Unknown) {
+      m_sve_state = SVEState::Disabled;
+      GetRegisterInfo().ConfigureVectorRegisterInfos(
+          RegisterInfoPOSIX_arm64::eVectorQuadwordAArch64);
+    } else {
+      if ((m_sve_header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD)
+        m_sve_state = SVEState::FPSIMD;
+      else if ((m_sve_header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE)
+        m_sve_state = SVEState::Full;
+
+      uint32_t vq = RegisterInfoPOSIX_arm64::eVectorQuadwordAArch64SVE;
+      if (sve_vl_valid(m_sve_header.vl))
+        vq = sve_vq_from_vl(m_sve_header.vl);
+      GetRegisterInfo().ConfigureVectorRegisterInfos(vq);
+      m_sve_ptrace_payload.resize(SVE_PT_SIZE(vq, SVE_PT_REGS_SVE));
+    }
+  }
 }
 
 uint32_t NativeRegisterContextLinux_arm64::CalculateFprOffset(
@@ -823,4 +1104,27 @@ uint32_t NativeRegisterContextLinux_arm64::CalculateFprOffset(
   return reg_info->byte_offset - GetGPRSize();
 }
 
+uint32_t NativeRegisterContextLinux_arm64::CalculateSVEOffset(
+    const RegisterInfo *reg_info) const {
+  // Start of Z0 data is after GPRs plus 8 bytes of vg register
+  uint32_t sve_reg_offset = LLDB_INVALID_INDEX32;
+  if (m_sve_state == SVEState::FPSIMD) {
+    const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
+    sve_reg_offset =
+        SVE_PT_FPSIMD_OFFSET + (reg - GetRegisterInfo().GetRegNumSVEZ0()) * 16;
+  } else if (m_sve_state == SVEState::Full) {
+    uint32_t sve_z0_offset = GetGPRSize() + 8;
+    sve_reg_offset =
+        SVE_SIG_REGS_OFFSET + reg_info->byte_offset - sve_z0_offset;
+  }
+  return sve_reg_offset;
+}
+
+void *NativeRegisterContextLinux_arm64::GetSVEBuffer() {
+  if (m_sve_state == SVEState::FPSIMD)
+    return m_sve_ptrace_payload.data() + SVE_PT_FPSIMD_OFFSET;
+
+  return m_sve_ptrace_payload.data();
+}
+
 #endif // defined (__arm64__) || defined (__aarch64__)

diff  --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
index 0fbbea51d217..da45f1c2d2c3 100644
--- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
+++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
@@ -14,6 +14,8 @@
 #include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
 
+#include <asm/ptrace.h>
+
 namespace lldb_private {
 namespace process_linux {
 
@@ -97,11 +99,19 @@ class NativeRegisterContextLinux_arm64 : public NativeRegisterContextLinux {
 private:
   bool m_gpr_is_valid;
   bool m_fpu_is_valid;
+  bool m_sve_buffer_is_valid;
+
+  bool m_sve_header_is_valid;
 
   RegisterInfoPOSIX_arm64::GPR m_gpr_arm64; // 64-bit general purpose registers.
 
   RegisterInfoPOSIX_arm64::FPU
       m_fpr; // floating-point registers including extended register sets.
+
+  SVEState m_sve_state;
+  struct user_sve_header m_sve_header;
+  std::vector<uint8_t> m_sve_ptrace_payload;
+
   // Debug register info for hardware breakpoints and watchpoints management.
   struct DREG {
     lldb::addr_t address;  // Breakpoint/watchpoint address value.
@@ -123,6 +133,28 @@ class NativeRegisterContextLinux_arm64 : public NativeRegisterContextLinux {
 
   bool IsFPR(unsigned reg) const;
 
+  Status ReadAllSVE();
+
+  Status WriteAllSVE();
+
+  Status ReadSVEHeader();
+
+  Status WriteSVEHeader();
+
+  bool IsSVE(unsigned reg) const;
+
+  uint64_t GetSVERegVG() { return m_sve_header.vl / 8; }
+
+  void SetSVERegVG(uint64_t vg) { m_sve_header.vl = vg * 8; }
+
+  void *GetSVEHeader() { return &m_sve_header; }
+
+  void *GetSVEBuffer();
+
+  size_t GetSVEHeaderSize() { return sizeof(m_sve_header); }
+
+  size_t GetSVEBufferSize() { return m_sve_ptrace_payload.size(); }
+
   Status ReadHardwareDebugInfo();
 
   Status WriteHardwareDebugRegs(int hwbType);
@@ -130,6 +162,10 @@ class NativeRegisterContextLinux_arm64 : public NativeRegisterContextLinux {
   uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;
 
   RegisterInfoPOSIX_arm64 &GetRegisterInfo() const;
+
+  void ConfigureRegisterContext();
+
+  uint32_t CalculateSVEOffset(const RegisterInfo *reg_info) const;
 };
 
 } // namespace process_linux

diff  --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
index fdb8b9cfeee8..c5fda7c1f041 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
@@ -66,7 +66,9 @@ class RegisterContextPOSIX_arm64 : public lldb_private::RegisterContext {
   uint32_t GetRegNumSVEZ0() const {
     return m_register_info_up->GetRegNumSVEZ0();
   }
-
+  uint32_t GetRegNumSVEFFR() const {
+    return m_register_info_up->GetRegNumSVEFFR();
+  }
   uint32_t GetRegNumFPCR() const { return m_register_info_up->GetRegNumFPCR(); }
   uint32_t GetRegNumFPSR() const { return m_register_info_up->GetRegNumFPSR(); }
 

diff  --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
index e28e46449b1d..2e8335f23b65 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
@@ -336,6 +336,8 @@ bool RegisterInfoPOSIX_arm64::IsSVERegVG(unsigned reg) const {
 
 uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEZ0() const { return sve_z0; }
 
+uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEFFR() const { return sve_ffr; }
+
 uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPCR() const { return fpu_fpcr; }
 
 uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPSR() const { return fpu_fpsr; }

diff  --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
index 892a759b9115..d5eaf4cfbe9e 100644
--- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
+++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
@@ -98,6 +98,7 @@ class RegisterInfoPOSIX_arm64
   bool IsSVERegVG(unsigned reg) const;
 
   uint32_t GetRegNumSVEZ0() const;
+  uint32_t GetRegNumSVEFFR() const;
   uint32_t GetRegNumFPCR() const;
   uint32_t GetRegNumFPSR() const;
 

diff  --git a/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/Makefile b/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/Makefile
new file mode 100644
index 000000000000..5fc881c2db97
--- /dev/null
+++ b/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/Makefile
@@ -0,0 +1,5 @@
+C_SOURCES := main.c
+
+CFLAGS_EXTRAS := -march=armv8-a+sve
+
+include Makefile.rules

diff  --git a/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/TestSVERegisters.py b/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/TestSVERegisters.py
new file mode 100644
index 000000000000..c34f4ae27802
--- /dev/null
+++ b/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/TestSVERegisters.py
@@ -0,0 +1,176 @@
+"""
+Test the AArch64 SVE registers.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class RegisterCommandsTestCase(TestBase):
+
+    def targetHasSVE(self):
+        triple = self.dbg.GetSelectedPlatform().GetTriple()
+
+        # TODO other platforms, please implement this function
+        if not re.match(".*-.*-linux", triple):
+            return False
+
+        # Need to do something 
diff erent for non-Linux/Android targets
+        cpuinfo_path = self.getBuildArtifact("cpuinfo")
+        if configuration.lldb_platform_name:
+            self.runCmd('platform get-file "/proc/cpuinfo" ' + cpuinfo_path)
+
+        f = open(cpuinfo_path, 'r')
+        cpuinfo = f.read()
+        f.close()
+        return " sve " in cpuinfo
+
+    def check_sve_register_size(self, set, name, expected):
+        reg_value = set.GetChildMemberWithName(name)
+        self.assertTrue(reg_value.IsValid(),
+                        'Verify we have a register named "%s"' % (name))
+        self.assertEqual(reg_value.GetByteSize(), expected,
+                         'Verify "%s" == %i' % (name, expected))
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @no_debug_info_test
+    @skipIf(archs=no_match(["aarch64"]))
+    @skipIf(oslist=no_match(['linux']))
+    def test_sve_registers_configuration(self):
+        """Test AArch64 SVE registers size configuration."""
+        self.build()
+        self.line = line_number('main.c', '// Set a break point here.')
+
+        exe = self.getBuildArtifact("a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        if not self.targetHasSVE():
+            self.skipTest('SVE registers must be supported.')
+
+        lldbutil.run_break_set_by_file_and_line(
+            self, "main.c", self.line, num_expected_locations=1)
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
+                    substrs=["stop reason = breakpoint 1."])
+
+        target = self.dbg.GetSelectedTarget()
+        process = target.GetProcess()
+        thread = process.GetThreadAtIndex(0)
+        currentFrame = thread.GetFrameAtIndex(0)
+
+        has_sve = False
+        for registerSet in currentFrame.GetRegisters():
+            if 'Scalable Vector Extension Registers' in registerSet.GetName():
+                has_sve = True
+
+        registerSets = process.GetThreadAtIndex(
+            0).GetFrameAtIndex(0).GetRegisters()
+
+        sve_registers = registerSets.GetValueAtIndex(2)
+
+        vg_reg = sve_registers.GetChildMemberWithName("vg")
+
+        vg_reg_value = sve_registers.GetChildMemberWithName(
+            "vg").GetValueAsUnsigned()
+
+        z_reg_size = vg_reg_value * 8
+
+        p_reg_size = z_reg_size / 8
+
+        for i in range(32):
+            self.check_sve_register_size(
+                sve_registers, 'z%i' % (i), z_reg_size)
+
+        for i in range(16):
+            self.check_sve_register_size(
+                sve_registers, 'p%i' % (i), p_reg_size)
+
+        self.check_sve_register_size(sve_registers, 'ffr', p_reg_size)
+
+    @no_debug_info_test
+    @skipIf(archs=no_match(["aarch64"]))
+    @skipIf(oslist=no_match(['linux']))
+    def test_sve_registers_read_write(self):
+        """Test AArch64 SVE registers read and write."""
+        self.build()
+        self.line = line_number('main.c', '// Set a break point here.')
+
+        exe = self.getBuildArtifact("a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        if not self.targetHasSVE():
+            self.skipTest('SVE registers must be supported.')
+
+        lldbutil.run_break_set_by_file_and_line(
+            self, "main.c", self.line, num_expected_locations=1)
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        self.expect("thread backtrace", STOPPED_DUE_TO_BREAKPOINT,
+                    substrs=["stop reason = breakpoint 1."])
+
+        target = self.dbg.GetSelectedTarget()
+        process = target.GetProcess()
+        thread = process.GetThreadAtIndex(0)
+        currentFrame = thread.GetFrameAtIndex(0)
+
+        has_sve = False
+        for registerSet in currentFrame.GetRegisters():
+            if 'Scalable Vector Extension Registers' in registerSet.GetName():
+                has_sve = True
+
+        registerSets = process.GetThreadAtIndex(
+            0).GetFrameAtIndex(0).GetRegisters()
+
+        sve_registers = registerSets.GetValueAtIndex(2)
+
+        vg_reg = sve_registers.GetChildMemberWithName("vg")
+
+        vg_reg_value = sve_registers.GetChildMemberWithName(
+            "vg").GetValueAsUnsigned()
+
+        z_reg_size = vg_reg_value * 8
+
+        p_reg_size = int(z_reg_size / 8)
+
+        for i in range(32):
+            z_regs_value = '{' + \
+                ' '.join('0x{:02x}'.format(i + 1)
+                         for _ in range(z_reg_size)) + '}'
+            self.expect("register read " + 'z%i' %
+                        (i), substrs=[z_regs_value])
+
+        p_value_bytes = ['0xff', '0x55', '0x11', '0x01', '0x00']
+        for i in range(16):
+            p_regs_value = '{' + \
+                ' '.join(p_value_bytes[i % 5] for _ in range(p_reg_size)) + '}'
+            self.expect("register read " + 'p%i' % (i), substrs=[p_regs_value])
+
+        self.expect("register read ffr", substrs=[p_regs_value])
+
+        z_regs_value = '{' + \
+            ' '.join(('0x9d' for _ in range(z_reg_size))) + '}'
+
+        p_regs_value = '{' + \
+            ' '.join(('0xee' for _ in range(p_reg_size))) + '}'
+
+        for i in range(32):
+            self.runCmd('register write ' + 'z%i' %
+                        (i) + " '" + z_regs_value + "'")
+
+        for i in range(32):
+            self.expect("register read " + 'z%i' % (i), substrs=[z_regs_value])
+
+        for i in range(16):
+            self.runCmd('register write ' + 'p%i' %
+                        (i) + " '" + p_regs_value + "'")
+
+        for i in range(16):
+            self.expect("register read " + 'p%i' % (i), substrs=[p_regs_value])
+
+        self.runCmd('register write ' + 'ffr ' + "'" + p_regs_value + "'")
+
+        self.expect("register read " + 'ffr', substrs=[p_regs_value])

diff  --git a/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/main.c b/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/main.c
new file mode 100644
index 000000000000..0c2573864eeb
--- /dev/null
+++ b/lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/main.c
@@ -0,0 +1,53 @@
+int main() {
+  asm volatile("setffr\n\t");
+  asm volatile("ptrue p0.b\n\t");
+  asm volatile("ptrue p1.h\n\t");
+  asm volatile("ptrue p2.s\n\t");
+  asm volatile("ptrue p3.d\n\t");
+  asm volatile("pfalse p4.b\n\t");
+  asm volatile("ptrue p5.b\n\t");
+  asm volatile("ptrue p6.h\n\t");
+  asm volatile("ptrue p7.s\n\t");
+  asm volatile("ptrue p8.d\n\t");
+  asm volatile("pfalse p9.b\n\t");
+  asm volatile("ptrue p10.b\n\t");
+  asm volatile("ptrue p11.h\n\t");
+  asm volatile("ptrue p12.s\n\t");
+  asm volatile("ptrue p13.d\n\t");
+  asm volatile("pfalse p14.b\n\t");
+  asm volatile("ptrue p15.b\n\t");
+
+  asm volatile("cpy  z0.b, p0/z, #1\n\t");
+  asm volatile("cpy  z1.b, p5/z, #2\n\t");
+  asm volatile("cpy  z2.b, p10/z, #3\n\t");
+  asm volatile("cpy  z3.b, p15/z, #4\n\t");
+  asm volatile("cpy  z4.b, p0/z, #5\n\t");
+  asm volatile("cpy  z5.b, p5/z, #6\n\t");
+  asm volatile("cpy  z6.b, p10/z, #7\n\t");
+  asm volatile("cpy  z7.b, p15/z, #8\n\t");
+  asm volatile("cpy  z8.b, p0/z, #9\n\t");
+  asm volatile("cpy  z9.b, p5/z, #10\n\t");
+  asm volatile("cpy  z10.b, p10/z, #11\n\t");
+  asm volatile("cpy  z11.b, p15/z, #12\n\t");
+  asm volatile("cpy  z12.b, p0/z, #13\n\t");
+  asm volatile("cpy  z13.b, p5/z, #14\n\t");
+  asm volatile("cpy  z14.b, p10/z, #15\n\t");
+  asm volatile("cpy  z15.b, p15/z, #16\n\t");
+  asm volatile("cpy  z16.b, p0/z, #17\n\t");
+  asm volatile("cpy  z17.b, p5/z, #18\n\t");
+  asm volatile("cpy  z18.b, p10/z, #19\n\t");
+  asm volatile("cpy  z19.b, p15/z, #20\n\t");
+  asm volatile("cpy  z20.b, p0/z, #21\n\t");
+  asm volatile("cpy  z21.b, p5/z, #22\n\t");
+  asm volatile("cpy  z22.b, p10/z, #23\n\t");
+  asm volatile("cpy  z23.b, p15/z, #24\n\t");
+  asm volatile("cpy  z24.b, p0/z, #25\n\t");
+  asm volatile("cpy  z25.b, p5/z, #26\n\t");
+  asm volatile("cpy  z26.b, p10/z, #27\n\t");
+  asm volatile("cpy  z27.b, p15/z, #28\n\t");
+  asm volatile("cpy  z28.b, p0/z, #29\n\t");
+  asm volatile("cpy  z29.b, p5/z, #30\n\t");
+  asm volatile("cpy  z30.b, p10/z, #31\n\t");
+  asm volatile("cpy  z31.b, p15/z, #32\n\t");
+  return 0; // Set a break point here.
+}


        


More information about the lldb-commits mailing list