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 @@ -75,8 +75,22 @@ 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; + // At this stage we configure register sets supported by this AArch64 target. + // ReadSVEHeader is called to check for SVE support. + Flags opt_regsets; + Status error = ReadSVEHeader(); + if (error.Success()) { + // SVE is supported, enable its register set. + // Setting m_sve_state to SVEState::Unknown it will be updated by + // ConfigureRegisterContext. + m_sve_state = SVEState::Unknown; + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE); + GetRegisterInfo().ConfigureRegisterInfos(opt_regsets); + } else { + // SVE is not supported by this target. + m_sve_state = SVEState::Disabled; + GetRegisterInfo().ConfigureRegisterInfos(opt_regsets); + } } RegisterInfoPOSIX_arm64 & @@ -451,10 +465,7 @@ } bool NativeRegisterContextLinux_arm64::IsSVE(unsigned reg) const { - if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) == - RegisterInfoPOSIX_arm64::SVERegSet) - return true; - return false; + return GetRegisterInfo().IsSVEReg(reg); } uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareBreakpoints() { @@ -1092,23 +1103,27 @@ } void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() { - // Read SVE configuration data and configure register infos. + // ConfigureRegisterContext gets called from InvalidateAllRegisters + // on every stop and configures SVE vector length. + // If m_sve_state is set to SVEState::Disabled on first stop, code below will + // be deemed non operational for the lifetime of current process. 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 (error.Success()) { + // If SVE is enabled thread can switch between SVEState::FPSIMD and + // SVEState::Full on every stop. 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; + // On every stop we configure SVE vector length by calling + // ConfigureVectorLength regardless of current SVEState of this thread. 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); + + GetRegisterInfo().ConfigureVectorLength(vq); m_sve_ptrace_payload.resize(SVE_PT_SIZE(vq, SVE_PT_REGS_SVE)); } } Index: lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp =================================================================== --- lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp +++ lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp @@ -40,10 +40,7 @@ } bool RegisterContextPOSIX_arm64::IsSVE(unsigned reg) const { - if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) == - RegisterInfoPOSIX_arm64::SVERegSet) - return true; - return false; + return m_register_info_up->IsSVEReg(reg); } RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64( 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 @@ -19,7 +19,14 @@ class RegisterInfoPOSIX_arm64 : public lldb_private::RegisterInfoAndSetInterface { public: - enum { GPRegSet = 0, FPRegSet, SVERegSet }; + enum { GPRegSet = 0, FPRegSet }; + + // AArch64 register set mask value + enum { + eRegsetMaskDefault = 0, + eRegsetMaskSVE = (1 << 0), + eRegsetMaskDynamic = (~0u << 2), + }; // AArch64 Register set FP/SIMD feature configuration enum { @@ -85,7 +92,9 @@ size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override; - uint32_t ConfigureVectorRegisterInfos(uint32_t sve_vq); + void ConfigureRegisterInfos(lldb_private::Flags &opt_regsets); + + uint32_t ConfigureVectorLength(uint32_t sve_vq); bool VectorSizeIsValid(uint32_t vq) { if (vq >= eVectorQuadwordAArch64 && vq <= eVectorQuadwordAArch64SVEMax) @@ -95,6 +104,7 @@ bool IsSVEEnabled() const { return m_vector_reg_vq > eVectorQuadwordAArch64; } + bool IsSVEReg(unsigned reg) const; bool IsSVEZReg(unsigned reg) const; bool IsSVEPReg(unsigned reg) const; bool IsSVERegVG(unsigned reg) const; @@ -115,6 +125,18 @@ const lldb_private::RegisterInfo *m_register_info_p; uint32_t m_register_info_count; + + const lldb_private::RegisterSet *m_register_set_p; + uint32_t m_register_set_count; + + // Contains pair of [start, end] register numbers of a register set with start + // and end included. + std::map> m_per_regset_regnum_range; + + bool m_reg_infos_is_dynamic = false; + + std::vector m_dynamic_reg_infos; + std::vector m_dynamic_reg_sets; }; #endif 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 @@ -10,6 +10,7 @@ #include #include +#include "lldb/Utility/Flags.h" #include "lldb/lldb-defines.h" #include "llvm/Support/Compiler.h" @@ -203,10 +204,17 @@ const lldb_private::ArchSpec &target_arch) : lldb_private::RegisterInfoAndSetInterface(target_arch), m_register_info_p(GetRegisterInfoPtr(target_arch)), - m_register_info_count(GetRegisterInfoCount(target_arch)) { + m_register_info_count(GetRegisterInfoCount(target_arch)), + m_register_set_p(g_reg_sets_arm64), + m_register_set_count(k_num_register_sets - 1) { + m_per_regset_regnum_range[GPRegSet] = std::make_pair(gpr_x0, gpr_w28); + m_per_regset_regnum_range[FPRegSet] = std::make_pair(fpu_v0, fpu_fpcr); } uint32_t RegisterInfoPOSIX_arm64::GetRegisterCount() const { + if (m_reg_infos_is_dynamic) + return m_register_info_count; + if (IsSVEEnabled()) return k_num_gpr_registers + k_num_fpr_registers + k_num_sve_registers; @@ -227,31 +235,73 @@ } size_t RegisterInfoPOSIX_arm64::GetRegisterSetCount() const { - if (IsSVEEnabled()) - return k_num_register_sets; - return k_num_register_sets - 1; + return m_register_set_count; } size_t RegisterInfoPOSIX_arm64::GetRegisterSetFromRegisterIndex( uint32_t reg_index) const { - if (reg_index <= gpr_w28) - return GPRegSet; - if (reg_index <= fpu_fpcr) - return FPRegSet; - if (reg_index <= sve_ffr) - return SVERegSet; + for (const auto ®set_range : m_per_regset_regnum_range) { + if (reg_index >= regset_range.second.first && + reg_index <= regset_range.second.second) + return regset_range.first; + } return LLDB_INVALID_REGNUM; } const lldb_private::RegisterSet * RegisterInfoPOSIX_arm64::GetRegisterSet(size_t set_index) const { if (set_index < GetRegisterSetCount()) - return &g_reg_sets_arm64[set_index]; + return &m_register_set_p[set_index]; return nullptr; } -uint32_t -RegisterInfoPOSIX_arm64::ConfigureVectorRegisterInfos(uint32_t sve_vq) { +void RegisterInfoPOSIX_arm64::ConfigureRegisterInfos( + lldb_private::Flags &opt_regsets) { + // Configures register sets supported by current target. If we have a dynamic + // register set like MTE, Pointer Authentication regset then we need to + // create a dynamic register infos and regset array. Push back all optional + // register infos and regset and calculate register offsets accordingly. + if (opt_regsets.AnySet(eRegsetMaskDynamic)) { + m_reg_infos_is_dynamic = true; + } + + if (m_reg_infos_is_dynamic) { + const lldb_private::RegisterInfo *reginfo_start, *reginfo_end; + const lldb_private::RegisterSet *regset_start = g_reg_sets_arm64; + if (opt_regsets.AllSet(eRegsetMaskSVE)) { + reginfo_start = g_register_infos_arm64_sve_le; + reginfo_end = g_register_infos_arm64_sve_le + sve_ffr + 1; + m_per_regset_regnum_range[m_register_set_count] = + std::make_pair(sve_vg, sve_ffr); + m_register_set_count++; + } else { + reginfo_start = g_register_infos_arm64_le; + reginfo_end = g_register_infos_arm64_le + fpu_fpcr + 1; + } + + std::copy(reginfo_start, reginfo_end, + std::back_inserter(m_dynamic_reg_infos)); + std::copy(regset_start, regset_start + m_register_set_count, + std::back_inserter(m_dynamic_reg_sets)); + + m_register_info_count = m_dynamic_reg_infos.size(); + m_register_info_p = m_dynamic_reg_infos.data(); + m_register_set_p = m_dynamic_reg_sets.data(); + m_register_set_count = m_dynamic_reg_sets.size(); + } else { + if (opt_regsets.AllSet(eRegsetMaskSVE)) { + m_register_info_p = g_register_infos_arm64_sve_le; + m_register_info_count = + static_cast(sizeof(g_register_infos_arm64_sve_le) / + sizeof(g_register_infos_arm64_sve_le[0])); + m_per_regset_regnum_range[m_register_set_count] = + std::make_pair(sve_vg, sve_ffr); + m_register_set_count++; + } + } +} + +uint32_t RegisterInfoPOSIX_arm64::ConfigureVectorLength(uint32_t sve_vq) { // sve_vq contains SVE Quad vector length in context of AArch64 SVE. // SVE register infos if enabled cannot be disabled by selecting sve_vq = 0. // Also if an invalid or previously set vector length is passed to this @@ -266,28 +316,15 @@ m_vector_reg_vq = sve_vq; - if (sve_vq == eVectorQuadwordAArch64) { - m_register_info_count = - static_cast(sizeof(g_register_infos_arm64_le) / - sizeof(g_register_infos_arm64_le[0])); - m_register_info_p = g_register_infos_arm64_le; - + if (sve_vq == eVectorQuadwordAArch64) return m_vector_reg_vq; - } - - m_register_info_count = - static_cast(sizeof(g_register_infos_arm64_sve_le) / - sizeof(g_register_infos_arm64_sve_le[0])); - std::vector ®_info_ref = m_per_vq_reg_infos[sve_vq]; if (reg_info_ref.empty()) { - reg_info_ref = llvm::makeArrayRef(g_register_infos_arm64_sve_le, - m_register_info_count); + reg_info_ref = llvm::makeArrayRef(m_register_info_p, m_register_info_count); uint32_t offset = SVE_REGS_DEFAULT_OFFSET_LINUX; - reg_info_ref[fpu_fpsr].byte_offset = offset; reg_info_ref[fpu_fpcr].byte_offset = offset + 4; reg_info_ref[sve_vg].byte_offset = offset + 8; @@ -316,13 +353,25 @@ offset += reg_info_ref[it].byte_size; } + for (uint32_t it = sve_ffr + 1; it < m_register_info_count; it++) { + reg_info_ref[it].byte_offset = offset; + offset += reg_info_ref[it].byte_size; + } + m_per_vq_reg_infos[sve_vq] = reg_info_ref; } - m_register_info_p = reg_info_ref.data(); + m_register_info_p = m_per_vq_reg_infos[sve_vq].data(); return m_vector_reg_vq; } +bool RegisterInfoPOSIX_arm64::IsSVEReg(unsigned reg) const { + if (m_vector_reg_vq > eVectorQuadwordAArch64) + return (sve_vg <= reg && reg <= sve_ffr); + else + return false; +} + bool RegisterInfoPOSIX_arm64::IsSVEZReg(unsigned reg) const { return (sve_z0 <= reg && reg <= sve_z31); } Index: lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp =================================================================== --- lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp +++ lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp @@ -57,6 +57,7 @@ } void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() { + Flags opt_regsets = RegisterInfoPOSIX_arm64::eRegsetMaskDefault; if (m_sveregset.GetByteSize() > sizeof(sve::user_sve_header)) { uint64_t sve_header_field_offset = 8; m_sve_vector_length = m_sveregset.GetU16(&sve_header_field_offset); @@ -70,15 +71,18 @@ sve::ptrace_regs_sve) m_sve_state = SVEState::Full; - if (sve::vl_valid(m_sve_vector_length)) - m_register_info_up->ConfigureVectorRegisterInfos( - sve::vq_from_vl(m_sve_vector_length)); - else { + if (!sve::vl_valid(m_sve_vector_length)) { m_sve_state = SVEState::Disabled; m_sve_vector_length = 0; } + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE); } else m_sve_state = SVEState::Disabled; + + m_register_info_up->ConfigureRegisterInfos(opt_regsets); + if (m_sve_state != SVEState::Disabled) + m_register_info_up->ConfigureVectorLength( + sve::vq_from_vl(m_sve_vector_length)); } uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset(