omjavaid updated this revision to Diff 280037.
omjavaid added a comment.
This update fixes issues highlighted in last review iteration.
@labath any further action on this?
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,5 @@
+int main() {
+ asm volatile("ptrue p0.s\n\t");
+ asm volatile("fcpy z0.s, p0/m, #5.00000000\n\t");
+ return 0; // Set a break point here.
+}
\ No newline at end of file
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,144 @@
+"""
+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)
+
+ 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,10 @@
#include "Plugins/Process/Linux/NativeRegisterContextLinux.h"
#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
+#include <asm/ptrace.h>
+
+#include "Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h"
+
namespace lldb_private {
namespace process_linux {
@@ -97,11 +101,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 +135,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 +164,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 &
@@ -107,30 +117,101 @@
? reg_info->name
: "<unknown register>");
+ // Update SVE registers in case there is change in configuration
+ ConfigureRegisterContext();
+
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");
@@ -155,39 +236,130 @@
? reg_info->name
: "<unknown register>");
+ // Update SVE registers in case there is change in configuration.
+ ConfigureRegisterContext();
+
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();
+ 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));
+ }
+
+ 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 +367,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 +441,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 +939,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 +955,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 +987,119 @@
}
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;
+}
+
+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 +1107,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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits