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