From d6d3d21cd1cb1567eaf7ff8c0867b07227a19d99 Mon Sep 17 00:00:00 2001 From: Muhammad Omair Javaid Date: Tue, 30 Mar 2021 15:39:32 +0500 Subject: [PATCH] [LLDB] Add support for Arm64/Linux dynamic register sets This is patch adds support for adding dynamic register sets for AArch64 dynamic features in LLDB. AArch64 has optional features like SVE, Pointer Authentication and MTE which means LLDB needs to decide at run time which registers it needs to pull in for the current executable based on underlying support for a certain feature. This patch makes necessary adjustments to make way for dynamic register infos and dynamic register sets. Reviewed By: labath Differential Revision: https://reviews.llvm.org/D96458 --- .../NativeRegisterContextLinux_arm64.cpp | 60 ++++++--- .../Linux/NativeRegisterContextLinux_arm64.h | 5 +- .../Utility/RegisterContextPOSIX_arm64.cpp | 5 +- .../Utility/RegisterInfoPOSIX_arm64.cpp | 121 +++++++++--------- .../Process/Utility/RegisterInfoPOSIX_arm64.h | 30 ++++- .../RegisterContextPOSIXCore_arm64.cpp | 36 ++++-- .../elf-core/RegisterContextPOSIXCore_arm64.h | 16 ++- .../Process/elf-core/ThreadElfCore.cpp | 5 +- 8 files changed, 174 insertions(+), 104 deletions(-) diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp index 5c025c0ecb43..09cf72c04482 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -46,18 +46,37 @@ NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( case llvm::Triple::arm: return std::make_unique(target_arch, native_thread); - case llvm::Triple::aarch64: - return std::make_unique(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(target_arch, opt_regsets); + return std::make_unique( + 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 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)); @@ -75,8 +94,10 @@ NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64( 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 & @@ -451,10 +472,7 @@ bool NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const { } 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() { @@ -676,23 +694,27 @@ Status NativeRegisterContextLinux_arm64::WriteAllSVE() { } 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)); } } diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h index 47105a5d0a83..f0dd6383cf85 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h @@ -26,8 +26,9 @@ class NativeRegisterContextLinux_arm64 : 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 register_info_up); uint32_t GetRegisterSetCount() const override; diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp index 3f52501c35f3..06b200e19f1e 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp @@ -40,10 +40,7 @@ bool RegisterContextPOSIX_arm64::IsFPR(unsigned reg) { } 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( diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp index 515c9f44e1e2..f651a8a0017a 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp @@ -72,23 +72,12 @@ #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 }; @@ -186,31 +175,54 @@ static const lldb_private::RegisterSet g_reg_sets_arm64[k_num_register_sets] = { {"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(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 reg_infos_ref = + llvm::makeArrayRef(m_register_info_p, m_register_info_count); + llvm::ArrayRef 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 { @@ -227,31 +239,27 @@ RegisterInfoPOSIX_arm64::GetRegisterInfo() 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 @@ -266,28 +274,15 @@ RegisterInfoPOSIX_arm64::ConfigureVectorRegisterInfos(uint32_t sve_vq) { 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 +311,25 @@ RegisterInfoPOSIX_arm64::ConfigureVectorRegisterInfos(uint32_t sve_vq) { 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); } diff --git a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h index 2929f2009dd9..955bc6197cca 100644 --- a/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h @@ -11,6 +11,7 @@ #include "RegisterInfoAndSetInterface.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Utility/Flags.h" #include "lldb/lldb-private.h" #include @@ -19,7 +20,14 @@ enum class SVEState { Unknown, Disabled, FPSIMD, Full }; 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 { @@ -68,7 +76,8 @@ public: 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; @@ -85,7 +94,7 @@ public: 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) @@ -93,8 +102,9 @@ public: 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; @@ -115,6 +125,18 @@ private: 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; + + lldb_private::Flags m_opt_regsets; + + std::vector m_dynamic_reg_infos; + std::vector m_dynamic_reg_sets; }; #endif diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp index 129a887a550c..9379316d1042 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp @@ -17,10 +17,29 @@ using namespace lldb_private; +std::unique_ptr +RegisterContextCorePOSIX_arm64::Create(Thread &thread, const ArchSpec &arch, + const DataExtractor &gpregset, + llvm::ArrayRef 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(arch, opt_regsets); + return std::unique_ptr( + new RegisterContextCorePOSIX_arm64(thread, std::move(register_info_up), + gpregset, sveregset, notes)); +} + RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64( Thread &thread, std::unique_ptr register_info, - const DataExtractor &gpregset, llvm::ArrayRef notes) - : RegisterContextPOSIX_arm64(thread, std::move(register_info)) { + const DataExtractor &gpregset, const DataExtractor &sveregset, + llvm::ArrayRef notes) + : RegisterContextPOSIX_arm64(thread, std::move(register_info)), + m_sveregset(sveregset) { m_gpr_buffer = std::make_shared(gpregset.GetDataStart(), gpregset.GetByteSize()); m_gpr.SetData(m_gpr_buffer); @@ -29,10 +48,6 @@ RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64( 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(); } @@ -70,15 +85,16 @@ void RegisterContextCorePOSIX_arm64::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( diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h index a4fdc4f14328..ec63eaa86111 100644 --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h @@ -18,11 +18,10 @@ class RegisterContextCorePOSIX_arm64 : public RegisterContextPOSIX_arm64 { public: - RegisterContextCorePOSIX_arm64( - lldb_private::Thread &thread, - std::unique_ptr register_info, - const lldb_private::DataExtractor &gpregset, - llvm::ArrayRef notes); + static std::unique_ptr + Create(lldb_private::Thread &thread, const lldb_private::ArchSpec &arch, + const lldb_private::DataExtractor &gpregset, + llvm::ArrayRef notes); ~RegisterContextCorePOSIX_arm64() override; @@ -39,6 +38,13 @@ public: bool HardwareSingleStep(bool enable) override; protected: + RegisterContextCorePOSIX_arm64( + lldb_private::Thread &thread, + std::unique_ptr register_info, + const lldb_private::DataExtractor &gpregset, + const lldb_private::DataExtractor &sveregset, + llvm::ArrayRef notes); + bool ReadGPR() override; bool ReadFPR() override; diff --git a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index fe646b508343..28483cf5f5a0 100644 --- a/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -167,9 +167,8 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { switch (arch.GetMachine()) { case llvm::Triple::aarch64: - m_thread_reg_ctx_sp = std::make_shared( - *this, std::make_unique(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(