diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp --- a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp @@ -788,6 +788,31 @@ return (pc & pac_sign_extension) ? pc | mask : pc & (~mask); } +// Reads code or data address mask for the current Linux process. +static lldb::addr_t ReadFreeBSDProcessAddressMask(lldb::ProcessSP process_sp, + llvm::StringRef reg_name) { + uint64_t address_mask = 0; + + // If Pointer Authentication feature is enabled then FreeBSD exposes + // PAC data and code mask register. Try reading relevant register + // below and merge it with default address mask calculated above. + lldb::ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread(); + if (thread_sp) { + lldb::RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext(); + if (reg_ctx_sp) { + const RegisterInfo *reg_info = + reg_ctx_sp->GetRegisterInfoByName(reg_name, 0); + if (reg_info) { + lldb::addr_t mask_reg_val = reg_ctx_sp->ReadRegisterAsUnsigned( + reg_info->kinds[eRegisterKindLLDB], LLDB_INVALID_ADDRESS); + if (mask_reg_val != LLDB_INVALID_ADDRESS) + address_mask |= mask_reg_val; + } + } + } + return address_mask; +} + // Reads code or data address mask for the current Linux process. static lldb::addr_t ReadLinuxProcessAddressMask(lldb::ProcessSP process_sp, llvm::StringRef reg_name) { @@ -820,6 +845,10 @@ !process_sp->GetCodeAddressMask()) process_sp->SetCodeAddressMask( ReadLinuxProcessAddressMask(process_sp, "code_mask")); + else if (process_sp->GetTarget().GetArchitecture().GetTriple().isOSFreeBSD() && + !process_sp->GetCodeAddressMask()) + process_sp->SetCodeAddressMask( + ReadFreeBSDProcessAddressMask(process_sp, "code_mask")); return FixAddress(pc, process_sp->GetCodeAddressMask()); } @@ -832,6 +861,10 @@ !process_sp->GetDataAddressMask()) process_sp->SetDataAddressMask( ReadLinuxProcessAddressMask(process_sp, "data_mask")); + else if (process_sp->GetTarget().GetArchitecture().GetTriple().isOSFreeBSD() && + !process_sp->GetDataAddressMask()) + process_sp->SetDataAddressMask( + ReadFreeBSDProcessAddressMask(process_sp, "data_mask")); return FixAddress(pc, process_sp->GetDataAddressMask()); } diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h --- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h +++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h @@ -36,8 +36,10 @@ : public NativeRegisterContextFreeBSD, public NativeRegisterContextDBReg_arm64 { public: - NativeRegisterContextFreeBSD_arm64(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread); + NativeRegisterContextFreeBSD_arm64( + const ArchSpec &target_arch, + NativeThreadProtocol &native_thread, + std::unique_ptr register_info_up); uint32_t GetRegisterSetCount() const override; @@ -65,6 +67,15 @@ // a unittest to assert that). std::array m_reg_data; std::array m_fpreg_data; + + struct arm64_addr_mask { + uint64_t data_mask; + uint64_t insn_mask; + }; + + bool m_addr_mask_is_valid; + struct arm64_addr_mask m_addr_mask; + #ifdef LLDB_HAS_FREEBSD_WATCHPOINT dbreg m_dbreg; bool m_read_dbreg; @@ -76,16 +87,22 @@ void *GetFPRBuffer() { return &m_fpreg_data; } size_t GetFPRSize() { return sizeof(m_fpreg_data); } + void *GetAddrMaskBuffer() { return &m_addr_mask; } + size_t GetAddrMaskBufferSize() { return sizeof(m_addr_mask); } + bool IsGPR(unsigned reg) const; bool IsFPR(unsigned reg) const; + bool IsAddrMask(unsigned reg) const; Status ReadGPR(); Status WriteGPR(); + Status ReadAddrMask(); Status ReadFPR(); Status WriteFPR(); uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const; + uint32_t CalculateAddrMaskOffset(const RegisterInfo *reg_info) const; llvm::Error ReadHardwareDebugInfo() override; llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override; diff --git a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp --- a/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp @@ -19,9 +19,11 @@ #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" // clang-format off +#include #include #include #include +#include // clang-format on #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize()) @@ -33,13 +35,19 @@ NativeRegisterContextFreeBSD * NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { - return new NativeRegisterContextFreeBSD_arm64(target_arch, native_thread); + Flags opt_regsets; + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskPAuth); + auto register_info_up = + std::make_unique(target_arch, opt_regsets); + return new NativeRegisterContextFreeBSD_arm64(target_arch, native_thread, + std::move(register_info_up)); } NativeRegisterContextFreeBSD_arm64::NativeRegisterContextFreeBSD_arm64( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextRegisterInfo( - native_thread, new RegisterInfoPOSIX_arm64(target_arch, 0)) + const ArchSpec &target_arch, NativeThreadProtocol &native_thread, + std::unique_ptr register_info_up) + : NativeRegisterContextRegisterInfo(native_thread, + register_info_up.release()) #ifdef LLDB_HAS_FREEBSD_WATCHPOINT , m_read_dbreg(false) @@ -47,6 +55,9 @@ { ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs)); + ::memset(&m_addr_mask, 0, sizeof(m_addr_mask)); + + m_addr_mask_is_valid = false; } RegisterInfoPOSIX_arm64 & @@ -84,6 +95,13 @@ return false; } +bool NativeRegisterContextFreeBSD_arm64::IsAddrMask(unsigned reg) const { + // Reuse the Linux PAuth mask register for now. On FreeBSD it can be + // used when PAC isn't available, e.g. with TBI. + return GetRegisterInfo().IsPAuthReg(reg); +} + + Status NativeRegisterContextFreeBSD_arm64::ReadGPR() { return NativeProcessFreeBSD::PtraceWrapper( PT_GETREGS, m_thread.GetID(), m_reg_data.data()); @@ -104,11 +122,37 @@ PT_SETFPREGS, m_thread.GetID(), m_fpreg_data.data()); } +Status NativeRegisterContextFreeBSD_arm64::ReadAddrMask() { + Status error; + +#ifdef NT_ARM_ADDR_MASK + if (m_addr_mask_is_valid) + return error; + + struct iovec ioVec; + ioVec.iov_base = GetAddrMaskBuffer(); + ioVec.iov_len = GetAddrMaskBufferSize(); + + error = NativeProcessFreeBSD::PtraceWrapper( + PT_GETREGSET, m_thread.GetID(), &ioVec, NT_ARM_ADDR_MASK); + + if (error.Success()) + m_addr_mask_is_valid = true; +#endif + + return error; +} + uint32_t NativeRegisterContextFreeBSD_arm64::CalculateFprOffset( const RegisterInfo *reg_info) const { return reg_info->byte_offset - GetGPRSize(); } +uint32_t NativeRegisterContextFreeBSD_arm64::CalculateAddrMaskOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - GetRegisterInfo().GetPAuthOffset(); +} + Status NativeRegisterContextFreeBSD_arm64::ReadRegister(const RegisterInfo *reg_info, RegisterValue ®_value) { @@ -145,6 +189,14 @@ offset = CalculateFprOffset(reg_info); assert(offset < GetFPRSize()); src = (uint8_t *)GetFPRBuffer() + offset; + } else if (IsAddrMask(reg)) { + error = ReadAddrMask(); + if (error.Fail()) + return error; + + offset = CalculateAddrMaskOffset(reg_info); + assert(offset < GetAddrMaskBufferSize()); + src = (uint8_t *)GetAddrMaskBuffer() + offset; } else return Status("Failed to read register value"); 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 @@ -120,6 +120,7 @@ }; constexpr RegsetDesc AARCH64_PAC_Desc[] = { + {llvm::Triple::FreeBSD, llvm::Triple::aarch64, llvm::ELF::NT_ARM_PAC_MASK}, {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_PAC_MASK}, };