omjavaid created this revision. omjavaid added a reviewer: labath. Herald added a subscriber: kristof.beyls. omjavaid requested review of this revision.
This patch adds two new register sets for MTE and Pointer Authentication feature registers. These register sets are dynamic and will only be available if underlying hardware support either of these features. LLDB will pull in Aux vector information and create register infos based on that information. A follow up patch will add a test case to test these feature registers. https://reviews.llvm.org/D96460 Files: lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h
Index: lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h =================================================================== --- lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h +++ lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h @@ -61,7 +61,7 @@ sve_p14, sve_p15, - sve_ffr, + sve_ffr }; #ifndef SVE_OFFSET_VG Index: lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h =================================================================== --- lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h +++ lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h @@ -470,6 +470,13 @@ LLDB_INVALID_REGNUM, lldb_kind \ } +// Generates register kinds array for registers with only lldb kind +#define KIND_ALL_INVALID \ + { \ + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM \ + } + // Generates register kinds array for vector registers #define GPR64_KIND(reg, generic_kind) MISC_KIND(reg, gpr, generic_kind) #define VREG_KIND(reg) MISC_KIND(reg, fpu, LLDB_INVALID_REGNUM) @@ -526,6 +533,13 @@ nullptr, 0 \ } +// Defines pointer authentication mask registers +#define DEFINE_PAUTH_REGS(reg) \ + { \ + #reg, nullptr, 8, 0, lldb::eEncodingUint, lldb::eFormatHex, \ + KIND_ALL_INVALID, nullptr, nullptr, nullptr, 0 \ + } + static lldb_private::RegisterInfo g_register_infos_arm64_le[] = { // DEFINE_GPR64(name, GENERIC KIND) DEFINE_GPR64(x0, LLDB_REGNUM_GENERIC_ARG1), @@ -772,7 +786,12 @@ {DEFINE_DBG(wcr, 13)}, {DEFINE_DBG(wcr, 14)}, {DEFINE_DBG(wcr, 15)} - // clang-format on }; +// clang-format on +static lldb_private::RegisterInfo g_register_infos_pauth[] = { + DEFINE_PAUTH_REGS(data_mask), DEFINE_PAUTH_REGS(code_mask)}; + +static lldb_private::RegisterInfo g_register_infos_mte[] = { + DEFINE_PAUTH_REGS(mte_ctrl)}; #endif // DECLARE_REGISTER_INFOS_ARM64_STRUCT Index: lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h =================================================================== --- lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h +++ lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h @@ -19,10 +19,15 @@ enum class SVEState { Unknown, Disabled, FPSIMD, Full }; +#define ARM64_REGS_CONFIG_DEFAULT 0x00 +#define ARM64_REGS_CONFIG_SVE 0x01 +#define ARM64_REGS_CONFIG_PAUTH 0x02 +#define ARM64_REGS_CONFIG_MTE 0x04 + class RegisterInfoPOSIX_arm64 : public lldb_private::RegisterInfoAndSetInterface { public: - enum { GPRegSet = 0, FPRegSet, SVERegSet }; + enum { GPRegSet = 0, FPRegSet }; // AArch64 Register set FP/SIMD feature configuration enum { @@ -90,6 +95,10 @@ void ConfigureRegisterInfos(uint32_t opt_regsets); + void AddRegSetPAuth(); + + void AddRegSetMTE(); + uint32_t ConfigureVectorLength(uint32_t mode); bool VectorSizeIsValid(uint32_t vq) { @@ -104,12 +113,16 @@ bool IsSVEZReg(unsigned reg) const; bool IsSVEPReg(unsigned reg) const; bool IsSVERegVG(unsigned reg) const; + bool IsPAuthReg(unsigned reg) const; + bool IsMTEReg(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 GetPAuthOffset() const; + uint32_t GetMTEOffset() const; private: typedef std::map<uint32_t, std::vector<lldb_private::RegisterInfo>> @@ -127,10 +140,15 @@ std::map<uint32_t, std::pair<uint32_t, uint32_t>> m_per_regset_regnum_range; + bool m_mte_regset_enabled = false; + bool m_pauth_regset_enabled = false; bool m_reg_infos_is_dynamic = false; std::vector<lldb_private::RegisterInfo> m_dynamic_reg_infos; std::vector<lldb_private::RegisterSet> m_dynamic_reg_sets; + + std::vector<uint32_t> pauth_regnum_collection; + std::vector<uint32_t> m_mte_regnum_collection; }; #endif Index: lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp =================================================================== --- lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp +++ lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp @@ -89,6 +89,8 @@ 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_mte_register = 1, + k_num_pauth_register = 2, k_num_register_sets = 3 }; @@ -186,6 +188,12 @@ {"Scalable Vector Extension Registers", "sve", k_num_sve_registers, g_sve_regnums_arm64}}; +static const lldb_private::RegisterSet g_reg_set_pauth_arm64 = { + "Pointer Authentication Registers", "pauth", k_num_pauth_register, NULL}; + +static const lldb_private::RegisterSet g_reg_set_mte_arm64 = { + "MTE Control Register", "mte", k_num_mte_register, NULL}; + static uint32_t GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { @@ -258,6 +266,11 @@ // TODO: Comment Here if (opt_regsets > ARM64_REGS_CONFIG_SVE) { m_reg_infos_is_dynamic = true; + if (opt_regsets & ARM64_REGS_CONFIG_PAUTH) + m_pauth_regset_enabled = true; + + if (opt_regsets & ARM64_REGS_CONFIG_MTE) + m_mte_regset_enabled = true; } if (m_reg_infos_is_dynamic) { @@ -279,6 +292,12 @@ std::copy(regset_start, regset_start + m_register_set_count, std::back_inserter(m_dynamic_reg_sets)); + if (m_pauth_regset_enabled) + AddRegSetPAuth(); + + if (m_mte_regset_enabled) + AddRegSetMTE(); + 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(); @@ -296,6 +315,38 @@ } } +void RegisterInfoPOSIX_arm64::AddRegSetPAuth() { + uint32_t pa_regnum = m_dynamic_reg_infos.size(); + for (uint32_t i = 0; i < 2; i++) { + pauth_regnum_collection.push_back(pa_regnum + i); + m_dynamic_reg_infos.push_back(g_register_infos_pauth[i]); + m_dynamic_reg_infos[pa_regnum + i].byte_offset = + m_dynamic_reg_infos[pa_regnum + i - 1].byte_offset + + m_dynamic_reg_infos[pa_regnum + i - 1].byte_size; + m_dynamic_reg_infos[pa_regnum + i].kinds[4] = pa_regnum + i; + } + + m_dynamic_reg_sets.push_back(g_reg_set_pauth_arm64); + m_dynamic_reg_sets[m_dynamic_reg_sets.size() - 1].registers = + pauth_regnum_collection.data(); +} + +void RegisterInfoPOSIX_arm64::AddRegSetMTE() { + uint32_t mte_regnum = m_dynamic_reg_infos.size(); + for (uint32_t i = 0; i < 1; i++) { + m_mte_regnum_collection.push_back(mte_regnum + i); + m_dynamic_reg_infos.push_back(g_register_infos_mte[i]); + m_dynamic_reg_infos[mte_regnum + i].byte_offset = + m_dynamic_reg_infos[mte_regnum + i - 1].byte_offset + + m_dynamic_reg_infos[mte_regnum + i - 1].byte_size; + m_dynamic_reg_infos[mte_regnum + i].kinds[4] = mte_regnum + i; + } + + m_dynamic_reg_sets.push_back(g_reg_set_mte_arm64); + m_dynamic_reg_sets[m_dynamic_reg_sets.size() - 1].registers = + m_mte_regnum_collection.data(); +} + 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. @@ -379,6 +430,20 @@ return sve_vg == reg; } +bool RegisterInfoPOSIX_arm64::IsPAuthReg(unsigned reg) const { + if (std::find(pauth_regnum_collection.begin(), pauth_regnum_collection.end(), + reg) != pauth_regnum_collection.end()) + return true; + return false; +} + +bool RegisterInfoPOSIX_arm64::IsMTEReg(unsigned reg) const { + if (std::find(m_mte_regnum_collection.begin(), m_mte_regnum_collection.end(), + reg) != m_mte_regnum_collection.end()) + return true; + return false; +} + uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEZ0() const { return sve_z0; } uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEFFR() const { return sve_ffr; } @@ -388,3 +453,11 @@ uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPSR() const { return fpu_fpsr; } uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEVG() const { return sve_vg; } + +uint32_t RegisterInfoPOSIX_arm64::GetPAuthOffset() const { + return m_register_info_p[pauth_regnum_collection[0]].byte_offset; +} + +uint32_t RegisterInfoPOSIX_arm64::GetMTEOffset() const { + return m_register_info_p[m_mte_regnum_collection[0]].byte_offset; +} Index: lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h =================================================================== --- lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h +++ lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h @@ -109,8 +109,10 @@ bool m_gpr_is_valid; bool m_fpu_is_valid; bool m_sve_buffer_is_valid; + bool m_mte_ctrl_is_valid; bool m_sve_header_is_valid; + bool m_pac_mask_is_valid; struct user_pt_regs m_gpr_arm64; // 64-bit general purpose registers. @@ -138,6 +140,15 @@ uint32_t m_max_hbp_supported; bool m_refresh_hwdebug_info; + struct user_pac_mask { + uint64_t data_mask; + uint64_t insn_mask; + }; + + struct user_pac_mask m_pac_mask; + + uint64_t m_mte_ctrl_reg; + bool IsGPR(unsigned reg) const; bool IsFPR(unsigned reg) const; @@ -150,7 +161,15 @@ Status WriteSVEHeader(); + Status ReadPAuthMask(); + + Status ReadMTEControl(); + + Status WriteMTEControl(); + bool IsSVE(unsigned reg) const; + bool IsPAuth(unsigned reg) const; + bool IsMTE(unsigned reg) const; uint64_t GetSVERegVG() { return m_sve_header.vl / 8; } @@ -158,12 +177,20 @@ void *GetSVEHeader() { return &m_sve_header; } + void *GetPACMask() { return &m_pac_mask; } + + void *GetMTEControl() { return &m_pac_mask; } + void *GetSVEBuffer(); size_t GetSVEHeaderSize() { return sizeof(m_sve_header); } + size_t GetPACMaskSize() { return sizeof(m_pac_mask); } + size_t GetSVEBufferSize() { return m_sve_ptrace_payload.size(); } + size_t GetMTEControlSize() { return sizeof(m_mte_ctrl_reg); } + Status ReadHardwareDebugInfo(); uint32_t QueryAuxvForOptionalRegset(); Index: lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp =================================================================== --- lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -34,6 +34,17 @@ #define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension */ #endif +#ifndef NT_ARM_PAC_MASK +#define NT_ARM_PAC_MASK 0x406 /* AArch pointer authentication code masks */ +#endif + +#ifndef NT_ARM_TAGGED_ADDR_CTRL +#define NT_ARM_TAGGED_ADDR_CTRL 0x409 /* arm64 tagged address control */ +#endif + +#define HWCAP_PACA (1 << 30) +#define HWCAP2_MTE (1 << 18) + #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize()) using namespace lldb; @@ -65,6 +76,8 @@ ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs)); ::memset(&m_sve_header, 0, sizeof(m_sve_header)); + m_mte_ctrl_reg = 0; + // 16 is just a maximum value, query hardware for actual watchpoint count m_max_hwp_supported = 16; m_max_hbp_supported = 16; @@ -75,6 +88,8 @@ m_fpu_is_valid = false; m_sve_buffer_is_valid = false; m_sve_header_is_valid = false; + m_pac_mask_is_valid = false; + m_mte_ctrl_is_valid = false; // SVE is not enabled until we query user_sve_header m_sve_state = SVEState::Unknown; @@ -101,7 +116,17 @@ llvm::Optional<uint64_t> auxv_at_hwcap = aux_vector->GetAuxValue(AuxVector::AUXV_AT_HWCAP); - return 0; + uint32_t result = 0; + if (*auxv_at_hwcap & HWCAP_PACA) + result |= ARM64_REGS_CONFIG_PAUTH; + + llvm::Optional<uint64_t> auxv_at_hwcap2 = + aux_vector->GetAuxValue(AuxVector::AUXV_AT_HWCAP2); + + if (*auxv_at_hwcap2 & HWCAP2_MTE) + result |= ARM64_REGS_CONFIG_MTE; + + return result; } uint32_t NativeRegisterContextLinux_arm64::GetRegisterSetCount() const { @@ -228,6 +253,22 @@ src = (uint8_t *)GetSVEBuffer() + offset; } } + } else if (IsPAuth(reg)) { + error = ReadPAuthMask(); + if (error.Fail()) + return error; + + offset = reg_info->byte_offset - GetRegisterInfo().GetPAuthOffset(); + assert(offset < GetPACMaskSize()); + src = (uint8_t *)GetPACMask() + offset; + } else if (IsMTE(reg)) { + error = ReadMTEControl(); + if (error.Fail()) + return error; + + offset = reg_info->byte_offset - GetRegisterInfo().GetMTEOffset(); + assert(offset < GetMTEControlSize()); + src = (uint8_t *)GetMTEControl() + offset; } else return Status("failed - register wasn't recognized to be a GPR or an FPR, " "write strategy unknown"); @@ -386,6 +427,17 @@ return WriteAllSVE(); } } + } else if (IsMTE(reg)) { + error = ReadMTEControl(); + if (error.Fail()) + return error; + + offset = reg_info->byte_offset - GetRegisterInfo().GetMTEOffset(); + assert(offset < GetMTEControlSize()); + dst = (uint8_t *)GetMTEControl() + offset; + ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); + + return WriteMTEControl(); } return Status("Failed to write register value"); @@ -476,6 +528,18 @@ return false; } +bool NativeRegisterContextLinux_arm64::IsPAuth(unsigned reg) const { + if (GetRegisterInfo().IsPAuthReg(reg)) + return true; + return false; +} + +bool NativeRegisterContextLinux_arm64::IsMTE(unsigned reg) const { + if (GetRegisterInfo().IsMTEReg(reg)) + return true; + return false; +} + uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareBreakpoints() { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); @@ -1033,6 +1097,7 @@ m_fpu_is_valid = false; m_sve_buffer_is_valid = false; m_sve_header_is_valid = false; + m_pac_mask_is_valid = false; // Update SVE registers in case there is change in configuration. ConfigureRegisterContext(); @@ -1055,6 +1120,23 @@ return error; } +Status NativeRegisterContextLinux_arm64::ReadPAuthMask() { + Status error; + + if (m_pac_mask_is_valid) + return error; + + struct iovec ioVec; + ioVec.iov_base = GetPACMask(); + ioVec.iov_len = GetPACMaskSize(); + + error = ReadRegisterSet(&ioVec, GetSVEHeaderSize(), NT_ARM_PAC_MASK); + + m_pac_mask_is_valid = true; + + return error; +} + Status NativeRegisterContextLinux_arm64::WriteSVEHeader() { Status error; @@ -1110,6 +1192,40 @@ return WriteRegisterSet(&ioVec, GetSVEBufferSize(), NT_ARM_SVE); } +Status NativeRegisterContextLinux_arm64::ReadMTEControl() { + Status error; + + if (m_mte_ctrl_is_valid) + return error; + + struct iovec ioVec; + ioVec.iov_base = GetMTEControl(); + ioVec.iov_len = GetMTEControlSize(); + + error = ReadRegisterSet(&ioVec, GetMTEControlSize(), NT_ARM_TAGGED_ADDR_CTRL); + + if (error.Success()) + m_mte_ctrl_is_valid = true; + + return error; +} + +Status NativeRegisterContextLinux_arm64::WriteMTEControl() { + Status error; + + error = ReadMTEControl(); + if (error.Fail()) + return error; + + struct iovec ioVec; + ioVec.iov_base = GetMTEControl(); + ioVec.iov_len = GetMTEControlSize(); + + m_mte_ctrl_is_valid = false; + + return WriteRegisterSet(&ioVec, GetMTEControlSize(), NT_ARM_TAGGED_ADDR_CTRL); +} + void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() { // Read SVE configuration data and configure register infos. if (!m_sve_header_is_valid && m_sve_state != SVEState::Disabled) {
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits