omjavaid updated this revision to Diff 284328.
omjavaid added a comment.

This patch fixes review items from last review cycles. Now we do not use 
LinuxPTraceDefines_arm64sve.h for NativeProcessLinux_arm64 as these defs are 
already back ported into libc ptrace.h available on most distros. LLDB arm64 
build bot and release builders should already have the header included.

We have updated LinuxPTraceDefines_arm64sve.h in D85641 
<https://reviews.llvm.org/D85641> where macros are converted into c++ consts 
and inlines.

Also test case now include ASM writing of by all SVE registers and they are 
read back and verified by the test case. I have also retained the writing test 
that was already there previously.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D79699/new/

https://reviews.llvm.org/D79699

Files:
  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
  
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

Index: lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/main.c
===================================================================
--- /dev/null
+++ 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.b\n\t");
+  asm volatile("ptrue p2.b\n\t");
+  asm volatile("ptrue p3.b\n\t");
+  asm volatile("ptrue p4.b\n\t");
+  asm volatile("ptrue p5.b\n\t");
+  asm volatile("ptrue p6.b\n\t");
+  asm volatile("ptrue p7.b\n\t");
+  asm volatile("ptrue p8.b\n\t");
+  asm volatile("ptrue p9.b\n\t");
+  asm volatile("ptrue p10.b\n\t");
+  asm volatile("ptrue p11.b\n\t");
+  asm volatile("ptrue p12.b\n\t");
+  asm volatile("ptrue p13.b\n\t");
+  asm volatile("ptrue 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, p1/z, #2\n\t");
+  asm volatile("cpy  z2.b, p2/z, #3\n\t");
+  asm volatile("cpy  z3.b, p3/z, #4\n\t");
+  asm volatile("cpy  z4.b, p4/z, #5\n\t");
+  asm volatile("cpy  z5.b, p5/z, #6\n\t");
+  asm volatile("cpy  z6.b, p6/z, #7\n\t");
+  asm volatile("cpy  z7.b, p7/z, #8\n\t");
+  asm volatile("cpy  z8.b, p8/z, #9\n\t");
+  asm volatile("cpy  z9.b, p9/z, #10\n\t");
+  asm volatile("cpy  z10.b, p10/z, #11\n\t");
+  asm volatile("cpy  z11.b, p11/z, #12\n\t");
+  asm volatile("cpy  z12.b, p12/z, #13\n\t");
+  asm volatile("cpy  z13.b, p13/z, #14\n\t");
+  asm volatile("cpy  z14.b, p14/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, p1/z, #18\n\t");
+  asm volatile("cpy  z18.b, p2/z, #19\n\t");
+  asm volatile("cpy  z19.b, p3/z, #20\n\t");
+  asm volatile("cpy  z20.b, p4/z, #21\n\t");
+  asm volatile("cpy  z21.b, p5/z, #22\n\t");
+  asm volatile("cpy  z22.b, p6/z, #23\n\t");
+  asm volatile("cpy  z23.b, p7/z, #24\n\t");
+  asm volatile("cpy  z24.b, p8/z, #25\n\t");
+  asm volatile("cpy  z25.b, p9/z, #26\n\t");
+  asm volatile("cpy  z26.b, p10/z, #27\n\t");
+  asm volatile("cpy  z27.b, p11/z, #28\n\t");
+  asm volatile("cpy  z28.b, p12/z, #29\n\t");
+  asm volatile("cpy  z29.b, p13/z, #30\n\t");
+  asm volatile("cpy  z30.b, p14/z, #31\n\t");
+  asm volatile("cpy  z31.b, p15/z, #32\n\t");
+  return 0; // Set a break point here.
+}
Index: lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/TestSVERegisters.py
===================================================================
--- /dev/null
+++ lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/TestSVERegisters.py
@@ -0,0 +1,158 @@
+"""
+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 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)
+
+        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
+
+        if not has_sve:
+            self.skipTest('SVE registers must be supported.')
+
+        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)
+
+        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
+
+        if not has_sve:
+            self.skipTest('SVE registers must be supported.')
+
+        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_regs_value = '{' + ' '.join('0xff' for _ in range(p_reg_size)) + '}'
+
+        self.expect("register read ffr", substrs=[p_regs_value])
+
+        for i in range(16):
+            self.expect("register read " + 'p%i' % (i), 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])
Index: lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/Makefile
===================================================================
--- /dev/null
+++ 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
Index: lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
===================================================================
--- lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
+++ lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h
@@ -98,6 +98,7 @@
   bool IsSVERegVG(unsigned reg) const;
 
   uint32_t GetRegNumSVEZ0() const;
+  uint32_t GetRegNumSVEFFR() const;
   uint32_t GetRegNumFPCR() const;
   uint32_t GetRegNumFPSR() const;
 
Index: lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
===================================================================
--- lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
+++ lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp
@@ -336,6 +336,8 @@
 
 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; }
Index: lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
===================================================================
--- lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
+++ lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h
@@ -66,7 +66,9 @@
   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(); }
 
Index: lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h
+++ 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 @@
 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 @@
 
   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 @@
   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
Index: lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp
+++ 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 @@
   ::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 @@
 
   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 @@
 
   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 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 @@
   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::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::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::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 @@
   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__)
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to