diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h @@ -114,6 +114,12 @@ uint64_t m_mte_ctrl_reg; + struct sme_regs { + uint64_t svg_reg; + }; + + struct sme_regs m_sme_regs; + struct tls_regs { uint64_t tpidr_reg; // Only valid when SME is present. @@ -144,6 +150,8 @@ Status WriteTLS(); + Status ReadSMESVG(); + Status ReadZAHeader(); Status ReadZA(); @@ -176,6 +184,8 @@ void *GetTLSBuffer() { return &m_tls_regs; } + void *GetSMEBuffer() { return &m_sme_regs; } + void *GetSVEBuffer() { return m_sve_ptrace_payload.data(); } size_t GetSVEHeaderSize() { return sizeof(m_sve_header); } @@ -194,6 +204,8 @@ size_t GetTLSBufferSize() { return m_tls_size; } + size_t GetSMEBufferSize() { return sizeof(m_sme_regs); } + llvm::Error ReadHardwareDebugInfo() override; llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override; diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -147,6 +147,7 @@ ::memset(&m_sve_header, 0, sizeof(m_sve_header)); ::memset(&m_pac_mask, 0, sizeof(m_pac_mask)); ::memset(&m_tls_regs, 0, sizeof(m_tls_regs)); + ::memset(&m_sme_regs, 0, sizeof(m_sme_regs)); m_mte_ctrl_reg = 0; @@ -329,30 +330,40 @@ assert(offset < GetMTEControlSize()); src = (uint8_t *)GetMTEControl() + offset; } else if (IsSME(reg)) { - error = ReadZAHeader(); - if (error.Fail()) - return error; + if (GetRegisterInfo().IsSMERegZA(reg)) { + error = ReadZAHeader(); + if (error.Fail()) + return error; - // If there is only a header and no registers, ZA is inactive. Read as 0 - // in this case. - if (m_za_header.size == sizeof(m_za_header)) { - // This will get reconfigured/reset later, so we are safe to use it. - // ZA is a square of VL * VL and the ptrace buffer also includes the - // header itself. - m_za_ptrace_payload.resize(((m_za_header.vl) * (m_za_header.vl)) + - GetZAHeaderSize()); - std::fill(m_za_ptrace_payload.begin(), m_za_ptrace_payload.end(), 0); + // If there is only a header and no registers, ZA is inactive. Read as 0 + // in this case. + if (m_za_header.size == sizeof(m_za_header)) { + // This will get reconfigured/reset later, so we are safe to use it. + // ZA is a square of VL * VL and the ptrace buffer also includes the + // header itself. + m_za_ptrace_payload.resize(((m_za_header.vl) * (m_za_header.vl)) + + GetZAHeaderSize()); + std::fill(m_za_ptrace_payload.begin(), m_za_ptrace_payload.end(), 0); + } else { + // ZA is active, read the real register. + error = ReadZA(); + if (error.Fail()) + return error; + } + + // ZA is part of the SME set but uses a seperate member buffer for storage. + // Therefore its effective byte offset is always 0 even if it isn't 0 within + // the SME register set. + src = (uint8_t *)GetZABuffer() + GetZAHeaderSize(); } else { - // ZA is active, read the real register. - error = ReadZA(); + error = ReadSMESVG(); if (error.Fail()) return error; - } - // ZA is part of the SME set but uses a seperate member buffer for storage. - // Therefore its effective byte offset is always 0 even if it isn't 0 within - // the SME register set. - src = (uint8_t *)GetZABuffer() + GetZAHeaderSize(); + offset = reg_info->byte_offset - GetRegisterInfo().GetSMEOffset(); + assert(offset < GetSMEBufferSize()); + src = (uint8_t *)GetSMEBuffer() + offset; + } } else return Status("failed - register wasn't recognized to be a GPR or an FPR, " "write strategy unknown"); @@ -538,6 +549,9 @@ return WriteTLS(); } else if (IsSME(reg)) { + if (!GetRegisterInfo().IsSMERegZA(reg)) + return Status("Writing to SVG is not supported."); + error = ReadZA(); if (error.Fail()) return error; @@ -1357,6 +1371,16 @@ return sve_reg_offset; } +Status NativeRegisterContextLinux_arm64::ReadSMESVG() { + // This register is the streaming vector length, so we will get it from + // NT_ARM_ZA regardless of the current streaming mode. + Status error = ReadZAHeader(); + if (error.Success()) + m_sme_regs.svg_reg = m_za_header.vl / 8; + + return error; +} + std::vector NativeRegisterContextLinux_arm64::GetExpeditedRegisters( ExpeditedRegs expType) const { std::vector expedited_reg_nums = @@ -1364,6 +1388,10 @@ // SVE, non-streaming vector length. if (m_sve_state == SVEState::FPSIMD || m_sve_state == SVEState::Full) expedited_reg_nums.push_back(GetRegisterInfo().GetRegNumSVEVG()); + // SME, streaming vector length. This is used by the ZA register which is + // present even when streaming mode is not enabled. + if (GetRegisterInfo().IsSSVEEnabled()) + expedited_reg_nums.push_back(GetRegisterInfo().GetRegNumSMESVG()); return expedited_reg_nums; } diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h @@ -135,12 +135,14 @@ bool IsMTEReg(unsigned reg) const; bool IsTLSReg(unsigned reg) const; bool IsSMEReg(unsigned reg) const; + bool IsSMERegZA(unsigned reg) const; uint32_t GetRegNumSVEZ0() const; uint32_t GetRegNumSVEFFR() const; uint32_t GetRegNumFPCR() const; uint32_t GetRegNumFPSR() const; uint32_t GetRegNumSVEVG() const; + uint32_t GetRegNumSMESVG() const; uint32_t GetPAuthOffset() const; uint32_t GetMTEOffset() const; uint32_t GetTLSOffset() const; diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp @@ -83,10 +83,11 @@ // Only present when SME is present DEFINE_EXTENSION_REG(tpidr2)}; -static lldb_private::RegisterInfo g_register_infos_sme[] = +static lldb_private::RegisterInfo g_register_infos_sme[] = { + DEFINE_EXTENSION_REG(svg), // 16 is a default size we will change later. - {{"za", nullptr, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, - KIND_ALL_INVALID, nullptr, nullptr, nullptr}}; + {"za", nullptr, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, + KIND_ALL_INVALID, nullptr, nullptr, nullptr}}; // Number of register sets provided by this context. enum { @@ -96,7 +97,7 @@ k_num_mte_register = 1, // Number of TLS registers is dynamic so it is not listed here. k_num_pauth_register = 2, - k_num_sme_register = 1, + k_num_sme_register = 2, k_num_register_sets_default = 2, k_num_register_sets = 3 }; @@ -448,7 +449,7 @@ // dynamic set and is just 1 register so we make an exception to const here. lldb_private::RegisterInfo *non_const_reginfo = const_cast(m_register_info_p); - non_const_reginfo[m_sme_regnum_collection[0]].byte_size = + non_const_reginfo[m_sme_regnum_collection[1]].byte_size = (za_vq * 16) * (za_vq * 16); } @@ -471,6 +472,10 @@ return sve_vg == reg; } +bool RegisterInfoPOSIX_arm64::IsSMERegZA(unsigned reg) const { + return reg == m_sme_regnum_collection[1]; +} + bool RegisterInfoPOSIX_arm64::IsPAuthReg(unsigned reg) const { return llvm::is_contained(pauth_regnum_collection, reg); } @@ -497,6 +502,10 @@ uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEVG() const { return sve_vg; } +uint32_t RegisterInfoPOSIX_arm64::GetRegNumSMESVG() const { + return m_sme_regnum_collection[0]; +} + uint32_t RegisterInfoPOSIX_arm64::GetPAuthOffset() const { return m_register_info_p[pauth_regnum_collection[0]].byte_offset; }