xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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> &regs,
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> &regs) {
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, &reg_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 &reg_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