xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 "lldb/Core/PluginManager.h"
18 #include "lldb/Target/Process.h"
19 
20 #include <bitset>
21 #include <optional>
22 
23 using namespace lldb;
24 
LLDB_PLUGIN_DEFINE(ABIAArch64)25 LLDB_PLUGIN_DEFINE(ABIAArch64)
26 
27 void ABIAArch64::Initialize() {
28   ABISysV_arm64::Initialize();
29 #ifdef LLDB_ENABLE_ALL
30   ABIMacOSX_arm64::Initialize();
31 #endif // LLDB_ENABLE_ALL
32 }
33 
Terminate()34 void ABIAArch64::Terminate() {
35   ABISysV_arm64::Terminate();
36 #ifdef LLDB_ENABLE_ALL
37   ABIMacOSX_arm64::Terminate();
38 #endif // LLDB_ENABLE_ALL
39 }
40 
FixCodeAddress(lldb::addr_t pc)41 lldb::addr_t ABIAArch64::FixCodeAddress(lldb::addr_t pc) {
42   if (lldb::ProcessSP process_sp = GetProcessSP()) {
43     // b55 is the highest bit outside TBI (if it's enabled), use
44     // it to determine if the high bits are set to 0 or 1.
45     const addr_t pac_sign_extension = 0x0080000000000000ULL;
46     addr_t mask = process_sp->GetCodeAddressMask();
47     // Test if the high memory mask has been overriden separately
48     if (pc & pac_sign_extension &&
49         process_sp->GetHighmemCodeAddressMask() != LLDB_INVALID_ADDRESS_MASK)
50       mask = process_sp->GetHighmemCodeAddressMask();
51 
52     if (mask != LLDB_INVALID_ADDRESS_MASK)
53       return FixAddress(pc, mask);
54   }
55   return pc;
56 }
57 
FixDataAddress(lldb::addr_t pc)58 lldb::addr_t ABIAArch64::FixDataAddress(lldb::addr_t pc) {
59   if (lldb::ProcessSP process_sp = GetProcessSP()) {
60     // b55 is the highest bit outside TBI (if it's enabled), use
61     // it to determine if the high bits are set to 0 or 1.
62     const addr_t pac_sign_extension = 0x0080000000000000ULL;
63     addr_t mask = process_sp->GetDataAddressMask();
64     // Test if the high memory mask has been overriden separately
65     if (pc & pac_sign_extension &&
66         process_sp->GetHighmemDataAddressMask() != LLDB_INVALID_ADDRESS_MASK)
67       mask = process_sp->GetHighmemDataAddressMask();
68     if (mask != LLDB_INVALID_ADDRESS_MASK)
69       return FixAddress(pc, mask);
70   }
71   return pc;
72 }
73 
74 std::pair<uint32_t, uint32_t>
GetEHAndDWARFNums(llvm::StringRef name)75 ABIAArch64::GetEHAndDWARFNums(llvm::StringRef name) {
76   if (name == "pc")
77     return {LLDB_INVALID_REGNUM, arm64_dwarf::pc};
78   if (name == "cpsr")
79     return {LLDB_INVALID_REGNUM, arm64_dwarf::cpsr};
80   return MCBasedABI::GetEHAndDWARFNums(name);
81 }
82 
GetMCName(std::string reg)83 std::string ABIAArch64::GetMCName(std::string reg) {
84   MapRegisterName(reg, "v", "q");
85   MapRegisterName(reg, "x29", "fp");
86   MapRegisterName(reg, "x30", "lr");
87   return reg;
88 }
89 
GetGenericNum(llvm::StringRef name)90 uint32_t ABIAArch64::GetGenericNum(llvm::StringRef name) {
91   return llvm::StringSwitch<uint32_t>(name)
92       .Case("pc", LLDB_REGNUM_GENERIC_PC)
93       .Cases("lr", "x30", LLDB_REGNUM_GENERIC_RA)
94       .Cases("sp", "x31", LLDB_REGNUM_GENERIC_SP)
95       .Cases("fp", "x29", LLDB_REGNUM_GENERIC_FP)
96       .Case("cpsr", LLDB_REGNUM_GENERIC_FLAGS)
97       .Case("x0", LLDB_REGNUM_GENERIC_ARG1)
98       .Case("x1", LLDB_REGNUM_GENERIC_ARG2)
99       .Case("x2", LLDB_REGNUM_GENERIC_ARG3)
100       .Case("x3", LLDB_REGNUM_GENERIC_ARG4)
101       .Case("x4", LLDB_REGNUM_GENERIC_ARG5)
102       .Case("x5", LLDB_REGNUM_GENERIC_ARG6)
103       .Case("x6", LLDB_REGNUM_GENERIC_ARG7)
104       .Case("x7", LLDB_REGNUM_GENERIC_ARG8)
105       .Default(LLDB_INVALID_REGNUM);
106 }
107 
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)108 static void addPartialRegisters(
109     std::vector<lldb_private::DynamicRegisterInfo::Register> &regs,
110     llvm::ArrayRef<std::optional<uint32_t>> full_reg_indices,
111     uint32_t full_reg_size, const char *partial_reg_format,
112     uint32_t partial_reg_size, lldb::Encoding encoding, lldb::Format format) {
113   for (auto it : llvm::enumerate(full_reg_indices)) {
114     std::optional<uint32_t> full_reg_index = it.value();
115     if (!full_reg_index || regs[*full_reg_index].byte_size != full_reg_size)
116       return;
117 
118     lldb_private::DynamicRegisterInfo::Register partial_reg{
119         lldb_private::ConstString(
120             llvm::formatv(partial_reg_format, it.index()).str()),
121         lldb_private::ConstString(),
122         lldb_private::ConstString("supplementary registers"),
123         partial_reg_size,
124         LLDB_INVALID_INDEX32,
125         encoding,
126         format,
127         LLDB_INVALID_REGNUM,
128         LLDB_INVALID_REGNUM,
129         LLDB_INVALID_REGNUM,
130         LLDB_INVALID_REGNUM,
131         {*full_reg_index},
132         {}};
133     addSupplementaryRegister(regs, partial_reg);
134   }
135 }
136 
AugmentRegisterInfo(std::vector<lldb_private::DynamicRegisterInfo::Register> & regs)137 void ABIAArch64::AugmentRegisterInfo(
138     std::vector<lldb_private::DynamicRegisterInfo::Register> &regs) {
139   lldb_private::MCBasedABI::AugmentRegisterInfo(regs);
140 
141   lldb_private::ConstString sp_string{"sp"};
142 
143   std::array<std::optional<uint32_t>, 32> x_regs;
144   std::array<std::optional<uint32_t>, 32> v_regs;
145 
146   for (auto it : llvm::enumerate(regs)) {
147     lldb_private::DynamicRegisterInfo::Register &info = it.value();
148     // GDB sends x31 as "sp".  Add the "x31" alt_name for convenience.
149     if (info.name == sp_string && !info.alt_name)
150       info.alt_name.SetCString("x31");
151 
152     unsigned int reg_num;
153     auto get_reg = [&info, &reg_num](const char *prefix) {
154       llvm::StringRef reg_name = info.name.GetStringRef();
155       llvm::StringRef alt_name = info.alt_name.GetStringRef();
156       return (reg_name.consume_front(prefix) &&
157               llvm::to_integer(reg_name, reg_num, 10) && reg_num < 32) ||
158              (alt_name.consume_front(prefix) &&
159               llvm::to_integer(alt_name, reg_num, 10) && reg_num < 32);
160     };
161 
162     if (get_reg("x"))
163       x_regs[reg_num] = it.index();
164     else if (get_reg("v"))
165       v_regs[reg_num] = it.index();
166     // if we have at least one subregister, abort
167     else if (get_reg("w") || get_reg("s") || get_reg("d"))
168       return;
169   }
170 
171   // Create aliases for partial registers: wN for xN, and sN/dN for vN.
172   addPartialRegisters(regs, x_regs, 8, "w{0}", 4, lldb::eEncodingUint,
173                       lldb::eFormatHex);
174   addPartialRegisters(regs, v_regs, 16, "s{0}", 4, lldb::eEncodingIEEE754,
175                       lldb::eFormatFloat);
176   addPartialRegisters(regs, v_regs, 16, "d{0}", 8, lldb::eEncodingIEEE754,
177                       lldb::eFormatFloat);
178 }
179