diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h @@ -54,6 +54,7 @@ size_t GetFPUSize() { return sizeof(RegisterInfoPOSIX_arm64::FPU); } bool IsSVE(unsigned reg) const; + bool IsPAuth(unsigned reg) const; bool IsSVEZ(unsigned reg) const { return m_register_info_up->IsSVEZReg(reg); } bool IsSVEP(unsigned reg) const { return m_register_info_up->IsSVEPReg(reg); } diff --git a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp --- a/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp +++ b/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp @@ -43,6 +43,10 @@ return m_register_info_up->IsSVEReg(reg); } +bool RegisterContextPOSIX_arm64::IsPAuth(unsigned reg) const { + return m_register_info_up->IsPAuthReg(reg); +} + RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64( lldb_private::Thread &thread, std::unique_ptr register_info) 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 @@ -109,6 +109,7 @@ } bool IsSVEEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskSVE); } + bool IsPAuthEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskPAuth); } bool IsSVEReg(unsigned reg) const; bool IsSVEZReg(unsigned reg) const; diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h @@ -42,7 +42,6 @@ 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; @@ -54,10 +53,10 @@ bool WriteFPR() override; private: - lldb::DataBufferSP m_gpr_buffer; - lldb_private::DataExtractor m_gpr; - lldb_private::DataExtractor m_fpregset; - lldb_private::DataExtractor m_sveregset; + lldb_private::DataExtractor m_gpr_data; + lldb_private::DataExtractor m_fpr_data; + lldb_private::DataExtractor m_sve_data; + lldb_private::DataExtractor m_pac_data; SVEState m_sve_state; uint16_t m_sve_vector_length = 0; diff --git a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp --- a/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp +++ b/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp @@ -21,32 +21,43 @@ 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)) + + DataExtractor sve_data = getRegset(notes, arch.GetTriple(), AARCH64_SVE_Desc); + if (sve_data.GetByteSize() > sizeof(sve::user_sve_header)) opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE); + + // Pointer Authentication register set data is based on struct + // user_pac_mask declared in ptrace.h. See reference implementation + // in Linux kernel source at arch/arm64/include/uapi/asm/ptrace.h. + DataExtractor pac_data = getRegset(notes, arch.GetTriple(), AARCH64_PAC_Desc); + if (pac_data.GetByteSize() >= sizeof(uint64_t) * 2) + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskPAuth); + 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)); + gpregset, notes)); } RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64( Thread &thread, std::unique_ptr 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); - m_gpr.SetByteOrder(gpregset.GetByteOrder()); - - m_fpregset = getRegset( - notes, m_register_info_up->GetTargetArchitecture().GetTriple(), FPR_Desc); + const DataExtractor &gpregset, llvm::ArrayRef notes) + : RegisterContextPOSIX_arm64(thread, std::move(register_info)) { + m_gpr_data.SetData(std::make_shared(gpregset.GetDataStart(), + gpregset.GetByteSize())); + m_gpr_data.SetByteOrder(gpregset.GetByteOrder()); + + const llvm::Triple &target_triple = + m_register_info_up->GetTargetArchitecture().GetTriple(); + m_fpr_data = getRegset(notes, target_triple, FPR_Desc); + + if (m_register_info_up->IsSVEEnabled()) + m_sve_data = getRegset(notes, target_triple, AARCH64_SVE_Desc); + + if (m_register_info_up->IsPAuthEnabled()) + m_pac_data = getRegset(notes, target_triple, AARCH64_PAC_Desc); ConfigureRegisterContext(); } @@ -68,16 +79,16 @@ } const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) { - return m_sveregset.GetDataStart() + offset; + return m_sve_data.GetDataStart() + offset; } void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() { - if (m_sveregset.GetByteSize() > sizeof(sve::user_sve_header)) { + if (m_sve_data.GetByteSize() > sizeof(sve::user_sve_header)) { uint64_t sve_header_field_offset = 8; - m_sve_vector_length = m_sveregset.GetU16(&sve_header_field_offset); + m_sve_vector_length = m_sve_data.GetU16(&sve_header_field_offset); sve_header_field_offset = 12; uint16_t sve_header_flags_field = - m_sveregset.GetU16(&sve_header_field_offset); + m_sve_data.GetU16(&sve_header_field_offset); if ((sve_header_flags_field & sve::ptrace_regs_mask) == sve::ptrace_regs_fpsimd) m_sve_state = SVEState::FPSIMD; @@ -120,7 +131,7 @@ offset = reg_info->byte_offset; if (offset + reg_info->byte_size <= GetGPRSize()) { - uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + uint64_t v = m_gpr_data.GetMaxU64(&offset, reg_info->byte_size); if (offset == reg_info->byte_offset + reg_info->byte_size) { value = v; return true; @@ -135,8 +146,8 @@ if (m_sve_state == SVEState::Disabled) { // SVE is disabled take legacy route for FPU register access offset -= GetGPRSize(); - if (offset < m_fpregset.GetByteSize()) { - value.SetFromMemoryData(reg_info, m_fpregset.GetDataStart() + offset, + if (offset < m_fpr_data.GetByteSize()) { + value.SetFromMemoryData(reg_info, m_fpr_data.GetDataStart() + offset, reg_info->byte_size, lldb::eByteOrderLittle, error); return error.Success(); @@ -168,7 +179,7 @@ } assert(sve_reg_num != LLDB_INVALID_REGNUM); - assert(offset < m_sveregset.GetByteSize()); + assert(offset < m_sve_data.GetByteSize()); value.SetFromMemoryData(reg_info, GetSVEBuffer(offset), reg_info->byte_size, lldb::eByteOrderLittle, error); @@ -190,7 +201,7 @@ if (IsSVEZ(reg)) { byte_size = 16; offset = CalculateSVEOffset(reg_info); - assert(offset < m_sveregset.GetByteSize()); + assert(offset < m_sve_data.GetByteSize()); src = GetSVEBuffer(offset); } value.SetFromMemoryData(reg_info, src, byte_size, lldb::eByteOrderLittle, @@ -198,7 +209,7 @@ } break; case SVEState::Full: offset = CalculateSVEOffset(reg_info); - assert(offset < m_sveregset.GetByteSize()); + assert(offset < m_sve_data.GetByteSize()); value.SetFromMemoryData(reg_info, GetSVEBuffer(offset), reg_info->byte_size, lldb::eByteOrderLittle, error); @@ -207,6 +218,11 @@ default: return false; } + } else if (IsPAuth(reg)) { + offset = reg_info->byte_offset - m_register_info_up->GetPAuthOffset(); + assert(offset < m_pac_data.GetByteSize()); + value.SetFromMemoryData(reg_info, m_pac_data.GetDataStart() + offset, + reg_info->byte_size, lldb::eByteOrderLittle, error); } else return false; diff --git a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h --- a/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h +++ b/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h @@ -111,6 +111,10 @@ {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_SVE}, }; +constexpr RegsetDesc AARCH64_PAC_Desc[] = { + {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_PAC_MASK}, +}; + constexpr RegsetDesc PPC_VMX_Desc[] = { {llvm::Triple::FreeBSD, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX}, {llvm::Triple::Linux, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX}, diff --git a/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py b/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py --- a/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py +++ b/lldb/test/API/functionalities/postmortem/elf-core/TestLinuxCore.py @@ -443,6 +443,21 @@ self.expect("register read --all") + @skipIfLLVMTargetMissing("AArch64") + def test_aarch64_pac_regs(self): + # Test AArch64/Linux Pointer Authenication register read + target = self.dbg.CreateTarget(None) + self.assertTrue(target, VALID_TARGET) + process = target.LoadCore("linux-aarch64-pac.core") + + values = {"data_mask": "0x007f00000000000", "code_mask": "0x007f00000000000"} + + for regname, value in values.items(): + self.expect("register read {}".format(regname), + substrs=["{} = {}".format(regname, value)]) + + self.expect("register read --all") + @skipIfLLVMTargetMissing("ARM") def test_arm_core(self): # check 32 bit ARM core file diff --git a/lldb/test/API/functionalities/postmortem/elf-core/linux-aarch64-pac.core b/lldb/test/API/functionalities/postmortem/elf-core/linux-aarch64-pac.core new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@