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 @@ -139,7 +139,7 @@ void *GetMTEControl() { return &m_mte_ctrl_reg; } - void *GetSVEBuffer(); + void *GetSVEBuffer() { return m_sve_ptrace_payload.data(); }; size_t GetSVEHeaderSize() { return sizeof(m_sve_header); } 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 @@ -46,8 +46,6 @@ #define HWCAP_PACA (1 << 30) #define HWCAP2_MTE (1 << 18) -#define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize()) - using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_linux; @@ -454,20 +452,49 @@ lldb::DataBufferSP &data_sp) { Status error; - data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); - + // Read all register values if not done already and calculate total size of + // register set data. We store all register values in data_sp by copying full + // PTrace data that corresponds to register sets enabled by current register + // context. + uint32_t reg_data_byte_size = GetGPRBufferSize(); error = ReadGPR(); if (error.Fail()) return error; - error = ReadFPR(); + // If SVE is enabled we need not copy FPR separately. + if (GetRegisterInfo().IsSVEEnabled()) { + reg_data_byte_size += GetSVEBufferSize(); + error = ReadAllSVE(); + } else { + reg_data_byte_size += GetFPRSize(); + error = ReadFPR(); + } if (error.Fail()) return error; + if (GetRegisterInfo().IsMTEEnabled()) { + reg_data_byte_size += GetMTEControlSize(); + error = ReadMTEControl(); + if (error.Fail()) + return error; + } + + data_sp.reset(new DataBufferHeap(reg_data_byte_size, 0)); uint8_t *dst = data_sp->GetBytes(); - ::memcpy(dst, GetGPRBuffer(), GetGPRSize()); - dst += GetGPRSize(); - ::memcpy(dst, GetFPRBuffer(), GetFPRSize()); + + ::memcpy(dst, GetGPRBuffer(), GetGPRBufferSize()); + dst += GetGPRBufferSize(); + + if (GetRegisterInfo().IsSVEEnabled()) { + ::memcpy(dst, GetSVEBuffer(), GetSVEBufferSize()); + dst += GetSVEBufferSize(); + } else { + ::memcpy(dst, GetFPRBuffer(), GetFPRSize()); + dst += GetFPRSize(); + } + + if (GetRegisterInfo().IsMTEEnabled()) + ::memcpy(dst, GetMTEControl(), GetMTEControlSize()); return error; } @@ -483,14 +510,6 @@ return error; } - if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_arm64::%s data_sp contained mismatched " - "data size, expected %" PRIu64 ", actual %" PRIu64, - __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); - return error; - } - uint8_t *src = data_sp->GetBytes(); if (src == nullptr) { error.SetErrorStringWithFormat("NativeRegisterContextLinux_arm64::%s " @@ -499,19 +518,78 @@ __FUNCTION__); return error; } - ::memcpy(GetGPRBuffer(), src, GetRegisterInfoInterface().GetGPRSize()); + + uint64_t reg_data_min_size = GetGPRBufferSize() + GetFPRSize(); + if (data_sp->GetByteSize() < reg_data_min_size) { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_arm64::%s data_sp contained insufficient " + "register data bytes, expected at least %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, reg_data_min_size, data_sp->GetByteSize()); + return error; + } + + // Register data starts with GPRs + ::memcpy(GetGPRBuffer(), src, GetGPRBufferSize()); + m_gpr_is_valid = true; error = WriteGPR(); if (error.Fail()) return error; - src += GetRegisterInfoInterface().GetGPRSize(); - ::memcpy(GetFPRBuffer(), src, GetFPRSize()); + src += GetGPRBufferSize(); + + // Verify if register data may contain SVE register values. + bool contains_sve_reg_data = + (data_sp->GetByteSize() > (reg_data_min_size + GetSVEHeaderSize())); + + if (contains_sve_reg_data) { + // We have SVE register data first write SVE header. + ::memcpy(GetSVEHeader(), src, GetSVEHeaderSize()); + if (!sve_vl_valid(m_sve_header.vl)) { + m_sve_header_is_valid = false; + error.SetErrorStringWithFormat("NativeRegisterContextLinux_arm64::%s " + "Invalid SVE header in data_sp", + __FUNCTION__); + return error; + } + m_sve_header_is_valid = true; + error = WriteSVEHeader(); + if (error.Fail()) + return error; + + // SVE header has been written configure SVE vector length if needed. + ConfigureRegisterContext(); + + // Make sure data_sp contains sufficient data to write all SVE registers. + reg_data_min_size = GetGPRBufferSize() + GetSVEBufferSize(); + if (data_sp->GetByteSize() < reg_data_min_size) { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_arm64::%s data_sp contained insufficient " + "register data bytes, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, reg_data_min_size, data_sp->GetByteSize()); + return error; + } + + ::memcpy(GetSVEBuffer(), src, GetSVEBufferSize()); + m_sve_buffer_is_valid = true; + error = WriteAllSVE(); + src += GetSVEBufferSize(); + } else { + ::memcpy(GetFPRBuffer(), src, GetFPRSize()); + m_fpu_is_valid = true; + error = WriteFPR(); + src += GetFPRSize(); + } - error = WriteFPR(); if (error.Fail()) return error; + if (GetRegisterInfo().IsMTEEnabled() && data_sp->GetByteSize() > reg_data_min_size) { + ::memcpy(GetMTEControl(), src, GetMTEControlSize()); + m_mte_ctrl_is_valid = true; + error = WriteMTEControl(); + } + return error; } @@ -864,13 +942,6 @@ return sve_reg_offset; } -void *NativeRegisterContextLinux_arm64::GetSVEBuffer() { - if (m_sve_state == SVEState::FPSIMD) - return m_sve_ptrace_payload.data() + sve::ptrace_fpsimd_offset; - - return m_sve_ptrace_payload.data(); -} - std::vector NativeRegisterContextLinux_arm64::GetExpeditedRegisters( ExpeditedRegs expType) const { std::vector expedited_reg_nums = 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 @@ -110,6 +110,7 @@ bool IsSVEEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskSVE); } bool IsPAuthEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskPAuth); } + bool IsMTEEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskMTE); } bool IsSVEReg(unsigned reg) const; bool IsSVEZReg(unsigned reg) const; Index: 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/TestSVERegisters.py +++ lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/TestSVERegisters.py @@ -17,6 +17,51 @@ self.assertEqual(reg_value.GetByteSize(), expected, 'Verify "%s" == %i' % (name, expected)) + def check_sve_regs_read(self, z_reg_size): + 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]) + + def check_sve_regs_read_after_write(self, z_reg_size): + 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]) + mydir = TestBase.compute_mydir(__file__) @no_debug_info_test @@ -117,43 +162,17 @@ 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]) + self.check_sve_regs_read(z_reg_size) - 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]) + # Evaluate simple expression and print function expr_eval_func address. + self.expect("p expr_eval_func", substrs=["= 0x"]) - self.expect("register read ffr", substrs=[p_regs_value]) + # Evaluate expression call function expr_eval_func. + self.expect_expr("expr_eval_func()", + result_type="int", result_value="1") - z_regs_value = '{' + \ - ' '.join(('0x9d' for _ in range(z_reg_size))) + '}' + # We called a jitted function above which must not have changed SVE + # vector length or regiter values. + self.check_sve_regs_read(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]) + self.check_sve_regs_read_after_write(z_reg_size) Index: lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/main.c =================================================================== --- lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/main.c +++ lldb/test/API/commands/register/register/aarch64_sve_registers/rw_access_static_config/main.c @@ -1,4 +1,6 @@ -int main() { +#include + +void write_sve_regs () { asm volatile("setffr\n\t"); asm volatile("ptrue p0.b\n\t"); asm volatile("ptrue p1.h\n\t"); @@ -49,5 +51,20 @@ 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"); +} + +// This function will be called using jitted expression call. We change vector +// length and write SVE registers. Our program context should restore to +// orignal vector length and register values after expression evaluation. +int expr_eval_func() { + prctl(PR_SVE_SET_VL, 8 * 2); + write_sve_regs(); + prctl(PR_SVE_SET_VL, 8 * 4); + write_sve_regs(); + return 1; +} + +int main() { + write_sve_regs(); return 0; // Set a break point here. }