case llvm::Triple::arm:
return std::make_unique<NativeRegisterContextLinux_arm>(target_arch,
native_thread);
- case llvm::Triple::aarch64:
- return std::make_unique<NativeRegisterContextLinux_arm64>(target_arch,
- native_thread);
+ case llvm::Triple::aarch64: {
+ // Configure register sets supported by this AArch64 target.
+ // Read SVE header to check for SVE support.
+ struct user_sve_header sve_header;
+ struct iovec ioVec;
+ ioVec.iov_base = &sve_header;
+ ioVec.iov_len = sizeof(sve_header);
+ unsigned int regset = NT_ARM_SVE;
+
+ Flags opt_regsets;
+ if (NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET,
+ native_thread.GetID(), ®set,
+ &ioVec, sizeof(sve_header))
+ .Success())
+ opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE);
+
+ auto register_info_up =
+ std::make_unique<RegisterInfoPOSIX_arm64>(target_arch, opt_regsets);
+ return std::make_unique<NativeRegisterContextLinux_arm64>(
+ target_arch, native_thread, std::move(register_info_up));
+ }
default:
llvm_unreachable("have no register context for architecture");
}
}
NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64(
- const ArchSpec &target_arch, NativeThreadProtocol &native_thread)
- : NativeRegisterContextRegisterInfo(
- native_thread, new RegisterInfoPOSIX_arm64(target_arch)) {
+ const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
+ std::unique_ptr<RegisterInfoPOSIX_arm64> register_info_up)
+ : NativeRegisterContextRegisterInfo(native_thread,
+ register_info_up.release()) {
::memset(&m_fpr, 0, sizeof(m_fpr));
::memset(&m_gpr_arm64, 0, sizeof(m_gpr_arm64));
::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs));
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;
+ if (GetRegisterInfo().IsSVEEnabled())
+ m_sve_state = SVEState::Unknown;
+ else
+ m_sve_state = SVEState::Disabled;
}
RegisterInfoPOSIX_arm64 &
}
bool NativeRegisterContextLinux_arm64::IsSVE(unsigned reg) const {
- if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) ==
- RegisterInfoPOSIX_arm64::SVERegSet)
- return true;
- return false;
+ return GetRegisterInfo().IsSVEReg(reg);
}
llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() {
}
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));
}
}
: public NativeRegisterContextLinux,
public NativeRegisterContextDBReg_arm64 {
public:
- NativeRegisterContextLinux_arm64(const ArchSpec &target_arch,
- NativeThreadProtocol &native_thread);
+ NativeRegisterContextLinux_arm64(
+ const ArchSpec &target_arch, NativeThreadProtocol &native_thread,
+ std::unique_ptr<RegisterInfoPOSIX_arm64> register_info_up);
uint32_t GetRegisterSetCount() const override;
}
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(
#include "RegisterInfos_arm64_sve.h"
#undef DECLARE_REGISTER_INFOS_ARM64_STRUCT
-static const lldb_private::RegisterInfo *
-GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
- switch (target_arch.GetMachine()) {
- case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_32:
- return g_register_infos_arm64_le;
- default:
- assert(false && "Unhandled target architecture.");
- return nullptr;
- }
-}
-
// Number of register sets provided by this context.
enum {
k_num_gpr_registers = gpr_w28 - gpr_x0 + 1,
k_num_fpr_registers = fpu_fpcr - fpu_v0 + 1,
k_num_sve_registers = sve_ffr - sve_vg + 1,
+ k_num_register_sets_default = 2,
k_num_register_sets = 3
};
{"Scalable Vector Extension Registers", "sve", k_num_sve_registers,
g_sve_regnums_arm64}};
-static uint32_t
-GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) {
+RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64(
+ const lldb_private::ArchSpec &target_arch, lldb_private::Flags opt_regsets)
+ : lldb_private::RegisterInfoAndSetInterface(target_arch),
+ m_opt_regsets(opt_regsets) {
switch (target_arch.GetMachine()) {
case llvm::Triple::aarch64:
- case llvm::Triple::aarch64_32:
- return static_cast<uint32_t>(sizeof(g_register_infos_arm64_le) /
- sizeof(g_register_infos_arm64_le[0]));
+ case llvm::Triple::aarch64_32: {
+ m_register_set_p = g_reg_sets_arm64;
+ m_register_set_count = k_num_register_sets_default;
+ m_per_regset_regnum_range[GPRegSet] = std::make_pair(gpr_x0, gpr_w28 + 1);
+ m_per_regset_regnum_range[FPRegSet] = std::make_pair(fpu_v0, fpu_fpcr + 1);
+
+ // Now configure register sets supported by current target. If we have a
+ // dynamic register set like MTE, Pointer Authentication regset then we need
+ // to create dynamic register infos and regset array. Push back all optional
+ // register infos and regset and calculate register offsets accordingly.
+ if (m_opt_regsets.AllSet(eRegsetMaskSVE)) {
+ m_register_info_p = g_register_infos_arm64_sve_le;
+ m_register_info_count = sve_ffr + 1;
+ m_per_regset_regnum_range[m_register_set_count++] =
+ std::make_pair(sve_vg, sve_ffr + 1);
+ } else {
+ m_register_info_p = g_register_infos_arm64_le;
+ m_register_info_count = fpu_fpcr + 1;
+ }
+
+ if (m_opt_regsets.AnySet(eRegsetMaskDynamic)) {
+ llvm::ArrayRef<lldb_private::RegisterInfo> reg_infos_ref =
+ llvm::makeArrayRef(m_register_info_p, m_register_info_count);
+ llvm::ArrayRef<lldb_private::RegisterSet> reg_sets_ref =
+ llvm::makeArrayRef(m_register_set_p, m_register_set_count);
+ llvm::copy(reg_infos_ref, std::back_inserter(m_dynamic_reg_infos));
+ llvm::copy(reg_sets_ref, 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();
+ }
+ break;
+ }
default:
assert(false && "Unhandled target architecture.");
- return 0;
}
}
-RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64(
- 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)) {
-}
-
uint32_t RegisterInfoPOSIX_arm64::GetRegisterCount() const {
- if (IsSVEEnabled())
- return k_num_gpr_registers + k_num_fpr_registers + k_num_sve_registers;
-
- return k_num_gpr_registers + k_num_fpr_registers;
+ return m_register_info_count;
}
size_t RegisterInfoPOSIX_arm64::GetGPRSize() const {
}
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) {
+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
m_vector_reg_vq = sve_vq;
- if (sve_vq == eVectorQuadwordAArch64) {
- m_register_info_count =
- static_cast<uint32_t>(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<uint32_t>(sizeof(g_register_infos_arm64_sve_le) /
- sizeof(g_register_infos_arm64_sve_le[0]));
-
std::vector<lldb_private::RegisterInfo> ®_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;
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);
}
#include "RegisterInfoAndSetInterface.h"
#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/Flags.h"
#include "lldb/lldb-private.h"
#include <map>
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,
+ eRegsetMaskDynamic = ~1,
+ };
// AArch64 Register set FP/SIMD feature configuration
enum {
uint64_t mdscr_el1;
};
- RegisterInfoPOSIX_arm64(const lldb_private::ArchSpec &target_arch);
+ RegisterInfoPOSIX_arm64(const lldb_private::ArchSpec &target_arch,
+ lldb_private::Flags opt_regsets);
size_t GetGPRSize() const override;
size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override;
- uint32_t ConfigureVectorRegisterInfos(uint32_t sve_vq);
+ uint32_t ConfigureVectorLength(uint32_t sve_vq);
bool VectorSizeIsValid(uint32_t vq) {
if (vq >= eVectorQuadwordAArch64 && vq <= eVectorQuadwordAArch64SVEMax)
return false;
}
- bool IsSVEEnabled() const { return m_vector_reg_vq > eVectorQuadwordAArch64; }
+ bool IsSVEEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskSVE); }
+ bool IsSVEReg(unsigned reg) const;
bool IsSVEZReg(unsigned reg) const;
bool IsSVEPReg(unsigned reg) const;
bool IsSVERegVG(unsigned reg) const;
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<uint32_t, std::pair<uint32_t, uint32_t>> m_per_regset_regnum_range;
+
+ lldb_private::Flags m_opt_regsets;
+
+ std::vector<lldb_private::RegisterInfo> m_dynamic_reg_infos;
+ std::vector<lldb_private::RegisterSet> m_dynamic_reg_sets;
};
#endif
using namespace lldb_private;
+std::unique_ptr<RegisterContextCorePOSIX_arm64>
+RegisterContextCorePOSIX_arm64::Create(Thread &thread, const ArchSpec &arch,
+ const DataExtractor &gpregset,
+ llvm::ArrayRef<CoreNote> notes) {
+ DataExtractor sveregset =
+ getRegset(notes, arch.GetTriple(), AARCH64_SVE_Desc);
+
+ Flags opt_regsets = RegisterInfoPOSIX_arm64::eRegsetMaskDefault;
+ if (sveregset.GetByteSize() > sizeof(sve::user_sve_header))
+ opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE);
+ auto register_info_up =
+ std::make_unique<RegisterInfoPOSIX_arm64>(arch, opt_regsets);
+ return std::unique_ptr<RegisterContextCorePOSIX_arm64>(
+ new RegisterContextCorePOSIX_arm64(thread, std::move(register_info_up),
+ gpregset, sveregset, notes));
+}
+
RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info,
- const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
- : RegisterContextPOSIX_arm64(thread, std::move(register_info)) {
+ const DataExtractor &gpregset, const DataExtractor &sveregset,
+ llvm::ArrayRef<CoreNote> notes)
+ : RegisterContextPOSIX_arm64(thread, std::move(register_info)),
+ m_sveregset(sveregset) {
m_gpr_buffer = std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
gpregset.GetByteSize());
m_gpr.SetData(m_gpr_buffer);
m_fpregset = getRegset(
notes, m_register_info_up->GetTargetArchitecture().GetTriple(), FPR_Desc);
- m_sveregset =
- getRegset(notes, m_register_info_up->GetTargetArchitecture().GetTriple(),
- AARCH64_SVE_Desc);
-
ConfigureRegisterContext();
}
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;
}
} else
m_sve_state = SVEState::Disabled;
+
+ if (m_sve_state != SVEState::Disabled)
+ m_register_info_up->ConfigureVectorLength(
+ sve::vq_from_vl(m_sve_vector_length));
}
uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset(
class RegisterContextCorePOSIX_arm64 : public RegisterContextPOSIX_arm64 {
public:
- RegisterContextCorePOSIX_arm64(
- lldb_private::Thread &thread,
- std::unique_ptr<RegisterInfoPOSIX_arm64> register_info,
- const lldb_private::DataExtractor &gpregset,
- llvm::ArrayRef<lldb_private::CoreNote> notes);
+ static std::unique_ptr<RegisterContextCorePOSIX_arm64>
+ Create(lldb_private::Thread &thread, const lldb_private::ArchSpec &arch,
+ const lldb_private::DataExtractor &gpregset,
+ llvm::ArrayRef<lldb_private::CoreNote> notes);
~RegisterContextCorePOSIX_arm64() override;
bool HardwareSingleStep(bool enable) override;
protected:
+ RegisterContextCorePOSIX_arm64(
+ lldb_private::Thread &thread,
+ std::unique_ptr<RegisterInfoPOSIX_arm64> register_info,
+ const lldb_private::DataExtractor &gpregset,
+ const lldb_private::DataExtractor &sveregset,
+ llvm::ArrayRef<lldb_private::CoreNote> notes);
+
bool ReadGPR() override;
bool ReadFPR() override;
switch (arch.GetMachine()) {
case llvm::Triple::aarch64:
- m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_arm64>(
- *this, std::make_unique<RegisterInfoPOSIX_arm64>(arch),
- m_gpregset_data, m_notes);
+ m_thread_reg_ctx_sp = RegisterContextCorePOSIX_arm64::Create(
+ *this, arch, m_gpregset_data, m_notes);
break;
case llvm::Triple::arm:
m_thread_reg_ctx_sp = std::make_shared<RegisterContextCorePOSIX_arm>(