246 lines · cpp
1//===-- AArch66.h ---------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/lldb-types.h"10 11#include "ABIAArch64.h"12#include "ABIMacOSX_arm64.h"13#include "ABISysV_arm64.h"14#include "Utility/ARM64_DWARF_Registers.h"15#include "Utility/ARM64_ehframe_Registers.h"16#include "lldb/Core/PluginManager.h"17#include "lldb/Target/Process.h"18 19#include <bitset>20#include <optional>21 22using namespace lldb;23using namespace lldb_private;24 25LLDB_PLUGIN_DEFINE(ABIAArch64)26 27void ABIAArch64::Initialize() {28 ABISysV_arm64::Initialize();29 ABIMacOSX_arm64::Initialize();30}31 32void ABIAArch64::Terminate() {33 ABISysV_arm64::Terminate();34 ABIMacOSX_arm64::Terminate();35}36 37lldb::addr_t ABIAArch64::FixCodeAddress(lldb::addr_t pc) {38 if (lldb::ProcessSP process_sp = GetProcessSP()) {39 // b55 is the highest bit outside TBI (if it's enabled), use40 // it to determine if the high bits are set to 0 or 1.41 const addr_t pac_sign_extension = 0x0080000000000000ULL;42 addr_t mask = process_sp->GetCodeAddressMask();43 // Test if the high memory mask has been overriden separately44 if (pc & pac_sign_extension &&45 process_sp->GetHighmemCodeAddressMask() != LLDB_INVALID_ADDRESS_MASK)46 mask = process_sp->GetHighmemCodeAddressMask();47 48 if (mask != LLDB_INVALID_ADDRESS_MASK)49 return FixAddress(pc, mask);50 }51 return pc;52}53 54lldb::addr_t ABIAArch64::FixDataAddress(lldb::addr_t pc) {55 if (lldb::ProcessSP process_sp = GetProcessSP()) {56 // b55 is the highest bit outside TBI (if it's enabled), use57 // it to determine if the high bits are set to 0 or 1.58 const addr_t pac_sign_extension = 0x0080000000000000ULL;59 addr_t mask = process_sp->GetDataAddressMask();60 // Test if the high memory mask has been overriden separately61 if (pc & pac_sign_extension &&62 process_sp->GetHighmemDataAddressMask() != LLDB_INVALID_ADDRESS_MASK)63 mask = process_sp->GetHighmemDataAddressMask();64 if (mask != LLDB_INVALID_ADDRESS_MASK)65 return FixAddress(pc, mask);66 }67 return pc;68}69 70std::pair<uint32_t, uint32_t>71ABIAArch64::GetEHAndDWARFNums(llvm::StringRef name) {72 if (name == "pc")73 return {arm64_ehframe::pc, arm64_dwarf::pc};74 if (name == "cpsr")75 return {arm64_ehframe::cpsr, arm64_dwarf::cpsr};76 return MCBasedABI::GetEHAndDWARFNums(name);77}78 79std::string ABIAArch64::GetMCName(std::string reg) {80 MapRegisterName(reg, "v", "q");81 MapRegisterName(reg, "x29", "fp");82 MapRegisterName(reg, "x30", "lr");83 return reg;84}85 86uint32_t ABIAArch64::GetGenericNum(llvm::StringRef name) {87 return llvm::StringSwitch<uint32_t>(name)88 .Case("pc", LLDB_REGNUM_GENERIC_PC)89 .Cases({"lr", "x30"}, LLDB_REGNUM_GENERIC_RA)90 .Cases({"sp", "x31"}, LLDB_REGNUM_GENERIC_SP)91 .Cases({"fp", "x29"}, LLDB_REGNUM_GENERIC_FP)92 .Case("cpsr", LLDB_REGNUM_GENERIC_FLAGS)93 .Case("x0", LLDB_REGNUM_GENERIC_ARG1)94 .Case("x1", LLDB_REGNUM_GENERIC_ARG2)95 .Case("x2", LLDB_REGNUM_GENERIC_ARG3)96 .Case("x3", LLDB_REGNUM_GENERIC_ARG4)97 .Case("x4", LLDB_REGNUM_GENERIC_ARG5)98 .Case("x5", LLDB_REGNUM_GENERIC_ARG6)99 .Case("x6", LLDB_REGNUM_GENERIC_ARG7)100 .Case("x7", LLDB_REGNUM_GENERIC_ARG8)101 .Default(LLDB_INVALID_REGNUM);102}103 104static void addPartialRegisters(105 std::vector<lldb_private::DynamicRegisterInfo::Register> ®s,106 llvm::ArrayRef<std::optional<uint32_t>> full_reg_indices,107 uint32_t full_reg_size, const char *partial_reg_format,108 uint32_t partial_reg_size, lldb::Encoding encoding, lldb::Format format) {109 for (auto it : llvm::enumerate(full_reg_indices)) {110 std::optional<uint32_t> full_reg_index = it.value();111 if (!full_reg_index || regs[*full_reg_index].byte_size != full_reg_size)112 return;113 114 lldb_private::DynamicRegisterInfo::Register partial_reg{115 lldb_private::ConstString(116 llvm::formatv(partial_reg_format, it.index()).str()),117 lldb_private::ConstString(),118 lldb_private::ConstString("supplementary registers"),119 partial_reg_size,120 LLDB_INVALID_INDEX32,121 encoding,122 format,123 LLDB_INVALID_REGNUM,124 LLDB_INVALID_REGNUM,125 LLDB_INVALID_REGNUM,126 LLDB_INVALID_REGNUM,127 {*full_reg_index},128 {}};129 addSupplementaryRegister(regs, partial_reg);130 }131}132 133void ABIAArch64::AugmentRegisterInfo(134 std::vector<lldb_private::DynamicRegisterInfo::Register> ®s) {135 lldb_private::MCBasedABI::AugmentRegisterInfo(regs);136 137 lldb_private::ConstString sp_string{"sp"};138 139 std::array<std::optional<uint32_t>, 32> x_regs;140 std::array<std::optional<uint32_t>, 32> v_regs;141 std::array<std::optional<uint32_t>, 32> z_regs;142 std::optional<uint32_t> z_byte_size;143 144 for (auto it : llvm::enumerate(regs)) {145 lldb_private::DynamicRegisterInfo::Register &info = it.value();146 // GDB sends x31 as "sp". Add the "x31" alt_name for convenience.147 if (info.name == sp_string && !info.alt_name)148 info.alt_name.SetCString("x31");149 150 unsigned int reg_num;151 auto get_reg = [&info, ®_num](const char *prefix) {152 llvm::StringRef reg_name = info.name.GetStringRef();153 llvm::StringRef alt_name = info.alt_name.GetStringRef();154 return (reg_name.consume_front(prefix) &&155 llvm::to_integer(reg_name, reg_num, 10) && reg_num < 32) ||156 (alt_name.consume_front(prefix) &&157 llvm::to_integer(alt_name, reg_num, 10) && reg_num < 32);158 };159 160 if (get_reg("x"))161 x_regs[reg_num] = it.index();162 else if (get_reg("v"))163 v_regs[reg_num] = it.index();164 else if (get_reg("z")) {165 z_regs[reg_num] = it.index();166 if (!z_byte_size)167 z_byte_size = info.byte_size;168 }169 // if we have at least one subregister, abort170 else if (get_reg("w") || get_reg("s") || get_reg("d"))171 return;172 }173 174 // Create aliases for partial registers.175 176 // Wn for Xn.177 addPartialRegisters(regs, x_regs, 8, "w{0}", 4, lldb::eEncodingUint,178 lldb::eFormatHex);179 180 auto bool_predicate = [](const auto ®_num) { return bool(reg_num); };181 bool saw_v_regs = llvm::any_of(v_regs, bool_predicate);182 bool saw_z_regs = llvm::any_of(z_regs, bool_predicate);183 184 // Sn/Dn for Vn.185 if (saw_v_regs) {186 addPartialRegisters(regs, v_regs, 16, "s{0}", 4, lldb::eEncodingIEEE754,187 lldb::eFormatFloat);188 addPartialRegisters(regs, v_regs, 16, "d{0}", 8, lldb::eEncodingIEEE754,189 lldb::eFormatFloat);190 } else if (saw_z_regs && z_byte_size) {191 // When SVE is enabled, some debug stubs will not describe the Neon V192 // registers because they can be read from the bottom 128 bits of the SVE193 // registers.194 195 // The size used here is the one sent by the debug server. This only needs196 // to be correct right now. Later we will rely on the value of vg instead.197 addPartialRegisters(regs, z_regs, *z_byte_size, "v{0}", 16,198 lldb::eEncodingVector, lldb::eFormatVectorOfUInt8);199 addPartialRegisters(regs, z_regs, *z_byte_size, "s{0}", 4,200 lldb::eEncodingIEEE754, lldb::eFormatFloat);201 addPartialRegisters(regs, z_regs, *z_byte_size, "d{0}", 8,202 lldb::eEncodingIEEE754, lldb::eFormatFloat);203 }204}205 206UnwindPlanSP ABIAArch64::CreateFunctionEntryUnwindPlan() {207 UnwindPlan::Row row;208 209 // Our previous Call Frame Address is the stack pointer210 row.GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_SP, 0);211 212 // Our previous PC is in the LR, all other registers are the same.213 row.SetRegisterLocationToRegister(LLDB_REGNUM_GENERIC_PC,214 LLDB_REGNUM_GENERIC_RA, true);215 216 auto plan_sp = std::make_shared<UnwindPlan>(eRegisterKindGeneric);217 plan_sp->AppendRow(std::move(row));218 plan_sp->SetSourceName("arm64 at-func-entry default");219 plan_sp->SetSourcedFromCompiler(eLazyBoolNo);220 plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);221 plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);222 return plan_sp;223}224 225UnwindPlanSP ABIAArch64::CreateDefaultUnwindPlan() {226 UnwindPlan::Row row;227 const int32_t ptr_size = 8;228 229 row.GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_FP,230 2 * ptr_size);231 row.SetUnspecifiedRegistersAreUndefined(true);232 233 row.SetRegisterLocationToAtCFAPlusOffset(LLDB_REGNUM_GENERIC_FP,234 ptr_size * -2, true);235 row.SetRegisterLocationToAtCFAPlusOffset(LLDB_REGNUM_GENERIC_PC,236 ptr_size * -1, true);237 238 auto plan_sp = std::make_shared<UnwindPlan>(eRegisterKindGeneric);239 plan_sp->AppendRow(std::move(row));240 plan_sp->SetSourceName("arm64 default unwind plan");241 plan_sp->SetSourcedFromCompiler(eLazyBoolNo);242 plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);243 plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);244 return plan_sp;245}246