LLDB mainline
RegisterTypeDetector_arm64.cpp
Go to the documentation of this file.
1//===-- RegisterTypeDetector_arm64.cpp ------------------------------------===//
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
11
12#include <functional>
13
14// This file is built on all systems because it is used by native processes and
15// core files, so we manually define the needed HWCAP values here.
16// These values are the same for Linux and FreeBSD.
17
18#define HWCAP_FPHP (1ULL << 9)
19#define HWCAP_ASIMDHP (1ULL << 10)
20#define HWCAP_DIT (1ULL << 24)
21#define HWCAP_SSBS (1ULL << 28)
22#define HWCAP_GCS (1ULL << 32)
23
24#define HWCAP2_BTI (1ULL << 17)
25#define HWCAP2_MTE (1ULL << 18)
26#define HWCAP2_AFP (1ULL << 20)
27#define HWCAP2_SME (1ULL << 23)
28#define HWCAP2_EBF16 (1ULL << 32)
29#define HWCAP2_FPMR (1ULL << 48)
30#define HWCAP2_POE (1ULL << 63)
31
32#define HWCAP3_MTE_STORE_ONLY (1ULL << 1)
33
34using namespace lldb_private;
35
36const RegisterType *
37Arm64RegisterTypeDetector::DetectPOREL0Type(uint64_t hwcap, uint64_t hwcap2,
38 uint64_t hwcap3) {
39 (void)hwcap;
40 (void)hwcap3;
41
42 if (!(hwcap2 & HWCAP2_POE))
43 return nullptr;
44
45 const RegisterTypeEnum *por_el0_perm_enum = MakeType<RegisterTypeEnum>(
46 "por_el0_perm_enum", RegisterTypeEnum::Enumerators{
47 {0b0000, "No Access"},
48 {0b0001, "Read"},
49 {0b0010, "Execute"},
50 {0b0011, "Read, Execute"},
51 {0b0100, "Write"},
52 {0b0101, "Write, Read"},
53 {0b0110, "Write, Execute"},
54 {0b0111, "Read, Write, Execute"},
55 });
56
57 return MakeType<RegisterTypeFlags>("por_el0_flags", 8,
58 std::vector<RegisterTypeFlags::Field>{
59 {"Perm15", 60, 63, por_el0_perm_enum},
60 {"Perm14", 56, 59, por_el0_perm_enum},
61 {"Perm13", 52, 55, por_el0_perm_enum},
62 {"Perm12", 48, 51, por_el0_perm_enum},
63 {"Perm11", 44, 47, por_el0_perm_enum},
64 {"Perm10", 40, 43, por_el0_perm_enum},
65 {"Perm9", 36, 39, por_el0_perm_enum},
66 {"Perm8", 32, 35, por_el0_perm_enum},
67 {"Perm7", 28, 31, por_el0_perm_enum},
68 {"Perm6", 24, 27, por_el0_perm_enum},
69 {"Perm5", 20, 23, por_el0_perm_enum},
70 {"Perm4", 16, 19, por_el0_perm_enum},
71 {"Perm3", 12, 15, por_el0_perm_enum},
72 {"Perm2", 8, 11, por_el0_perm_enum},
73 {"Perm1", 4, 7, por_el0_perm_enum},
74 {"Perm0", 0, 3, por_el0_perm_enum},
75 });
76}
77
79 uint64_t hwcap2,
80 uint64_t hwcap3) {
81 (void)hwcap;
82 (void)hwcap3;
83
84 if (!(hwcap2 & HWCAP2_FPMR))
85 return nullptr;
86
87 const RegisterTypeEnum *fp8_format_enum = MakeType<RegisterTypeEnum>(
88 "fp8_format_enum", RegisterTypeEnum::Enumerators{
89 {0, "FP8_E5M2"},
90 {1, "FP8_E4M3"},
91 });
92
94 "fpmr_flags", 8,
95 std::vector<RegisterTypeFlags::Field>{{"LSCALE2", 32, 37},
96 {"NSCALE", 24, 31},
97 {"LSCALE", 16, 22},
98 {"OSC", 15},
99 {"OSM", 14},
100 {"F8D", 6, 8, fp8_format_enum},
101 {"F8S2", 3, 5, fp8_format_enum},
102 {"F8S1", 0, 2, fp8_format_enum}});
103}
104
106 uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3) {
107 (void)hwcap2;
108 (void)hwcap3;
109
110 if (!(hwcap & HWCAP_GCS))
111 return nullptr;
112
114 "gcs_features_flags", 8,
115 std::vector<RegisterTypeFlags::Field>{
116 {"PUSH", 2}, {"WRITE", 1}, {"ENABLE", 0}});
117}
118
120 uint64_t hwcap2,
121 uint64_t hwcap3) {
122 (void)hwcap;
123 (void)hwcap3;
124
125 if (!(hwcap2 & HWCAP2_SME))
126 return nullptr;
127
128 // Represents the pseudo register that lldb-server builds, which itself
129 // matches the architectural register SCVR. The fields match SVCR in the Arm
130 // manual.
132 "svcr_flags", 8,
133 std::vector<RegisterTypeFlags::Field>{{"ZA", 1}, {"SM", 0}});
134}
135
136const RegisterType *
137Arm64RegisterTypeDetector::DetectMTECtrlType(uint64_t hwcap, uint64_t hwcap2,
138 uint64_t hwcap3) {
139 (void)hwcap;
140
141 if (!(hwcap2 & HWCAP2_MTE))
142 return nullptr;
143
144 // Represents the contents of NT_ARM_TAGGED_ADDR_CTRL and the value passed
145 // to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the defines
146 // used to build the value.
147
148 std::vector<RegisterTypeFlags::Field> fields;
149 fields.reserve(4);
150 if (hwcap3 & HWCAP3_MTE_STORE_ONLY)
151 fields.push_back({"STORE_ONLY", 19});
152
154 "tcf_enum", RegisterTypeEnum::Enumerators{{0, "TCF_NONE"},
155 {1, "TCF_SYNC"},
156 {2, "TCF_ASYNC"},
157 {3, "TCF_ASYMM"}});
158
159 fields.insert(
160 std::end(fields),
161 {{"TAGS", 3, 18}, // 16 bit bitfield shifted up by PR_MTE_TAG_SHIFT.
162 {"TCF", 1, 2, tcf_enum},
163 {"TAGGED_ADDR_ENABLE", 0}});
164
165 return MakeType<RegisterTypeFlags>("mte_ctrl_flags", 8, fields);
166}
167
169 uint64_t hwcap2,
170 uint64_t hwcap3) {
171 (void)hwcap3;
172
174 "rmode_enum", RegisterTypeEnum::Enumerators{
175 {0, "RN"}, {1, "RP"}, {2, "RM"}, {3, "RZ"}});
176
177 std::vector<RegisterTypeFlags::Field> fpcr_fields{
178 {"AHP", 26},
179 {"DN", 25},
180 {"FZ", 24},
181 {"RMode", 22, 23, rmode_enum},
182 // Bits 21-20 are "Stride" which is unused in AArch64 state.
183 };
184
185 // FEAT_FP16 is indicated by the presence of FPHP (floating point half
186 // precision) and ASIMDHP (Advanced SIMD half precision) features.
187 if ((hwcap & HWCAP_FPHP) && (hwcap & HWCAP_ASIMDHP))
188 fpcr_fields.push_back({"FZ16", 19});
189
190 // Bits 18-16 are "Len" which is unused in AArch64 state.
191
192 fpcr_fields.push_back({"IDE", 15});
193
194 // Bit 14 is unused.
195 if (hwcap2 & HWCAP2_EBF16)
196 fpcr_fields.push_back({"EBF", 13});
197
198 fpcr_fields.push_back({"IXE", 12});
199 fpcr_fields.push_back({"UFE", 11});
200 fpcr_fields.push_back({"OFE", 10});
201 fpcr_fields.push_back({"DZE", 9});
202 fpcr_fields.push_back({"IOE", 8});
203 // Bits 7-3 reserved.
204
205 if (hwcap2 & HWCAP2_AFP) {
206 fpcr_fields.push_back({"NEP", 2});
207 fpcr_fields.push_back({"AH", 1});
208 fpcr_fields.push_back({"FIZ", 0});
209 }
210
211 return MakeType<RegisterTypeFlags>("fpcr_flags", 4, fpcr_fields);
212}
213
215 uint64_t hwcap2,
216 uint64_t hwcap3) {
217 // fpsr's contents are constant.
218 (void)hwcap;
219 (void)hwcap2;
220 (void)hwcap3;
221
223 "fpsr_flags", 4,
224 std::vector<RegisterTypeFlags::Field>{
225 // Bits 31-28 are N/Z/C/V, only used by AArch32.
226 {"QC", 27},
227 // Bits 26-8 reserved.
228 {"IDC", 7},
229 // Bits 6-5 reserved.
230 {"IXC", 4},
231 {"UFC", 3},
232 {"OFC", 2},
233 {"DZC", 1},
234 {"IOC", 0},
235 });
236}
237
239 uint64_t hwcap2,
240 uint64_t hwcap3) {
241 (void)hwcap3;
242
243 // The fields here are a combination of the Arm manual's SPSR_EL1,
244 // plus a few changes where Linux has decided not to make use of them at all,
245 // or at least not from userspace.
246
247 // Status bits that are always present.
248 std::vector<RegisterTypeFlags::Field> cpsr_fields{
249 {"N", 31},
250 {"Z", 30},
251 {"C", 29},
252 {"V", 28},
253 // Bits 27-26 reserved.
254 };
255
256 if (hwcap2 & HWCAP2_MTE)
257 cpsr_fields.push_back({"TCO", 25});
258 if (hwcap & HWCAP_DIT)
259 cpsr_fields.push_back({"DIT", 24});
260
261 // UAO and PAN are bits 23 and 22 and have no meaning for userspace so
262 // are treated as reserved by the kernels.
263
264 cpsr_fields.push_back({"SS", 21});
265 cpsr_fields.push_back({"IL", 20});
266 // Bits 19-14 reserved.
267
268 // Bit 13, ALLINT, requires FEAT_NMI that isn't relevant to userspace, and we
269 // can't detect either, don't show this field.
270 if (hwcap & HWCAP_SSBS)
271 cpsr_fields.push_back({"SSBS", 12});
272 if (hwcap2 & HWCAP2_BTI)
273 cpsr_fields.push_back({"BTYPE", 10, 11});
274
275 cpsr_fields.push_back({"D", 9});
276 cpsr_fields.push_back({"A", 8});
277 cpsr_fields.push_back({"I", 7});
278 cpsr_fields.push_back({"F", 6});
279 // Bit 5 reserved
280 // Called "M" in the ARMARM.
281 cpsr_fields.push_back({"nRW", 4});
282 // This is a 4 bit field M[3:0] in the ARMARM, we split it into parts.
283 cpsr_fields.push_back({"EL", 2, 3});
284 // Bit 1 is unused and expected to be 0.
285 cpsr_fields.push_back({"SP", 0});
286
287 return MakeType<RegisterTypeFlags>("cpsr_flags", 4, cpsr_fields);
288}
289
290void Arm64RegisterTypeDetector::DetectTypes(uint64_t hwcap, uint64_t hwcap2,
291 uint64_t hwcap3) {
292 for (auto &reg : m_registers)
293 reg.m_type = std::invoke(reg.m_detector, this, hwcap, hwcap2, hwcap3);
294 m_has_detected = true;
295}
296
298 uint32_t num_regs) {
299 assert(m_has_detected &&
300 "Must call DetectTypes before updating register info.");
301
302 // Register names will not be duplicated, so we do not want to compare against
303 // one if it has already been found. Each time we find one, we erase it from
304 // this list.
305 std::vector<std::pair<llvm::StringRef, const RegisterType *>>
306 search_registers;
307 for (const auto &reg : m_registers) {
308 // It is possible that a register is all extension dependent fields, and
309 // none of them are present.
310 if (reg.m_type)
311 for (auto reg_name : reg.m_names)
312 search_registers.push_back({reg_name, reg.m_type});
313 }
314
315 // Walk register information while there are registers we know need
316 // to be updated. Example:
317 // Register information: [a, b, c, d]
318 // To be patched: [b, c]
319 // * a != b, a != c, do nothing and move on.
320 // * b == b, patch b, new patch list is [c], move on.
321 // * c == c, patch c, patch list is empty, exit early without looking at d.
322 for (uint32_t idx = 0; idx < num_regs && search_registers.size();
323 ++idx, ++reg_info) {
324 auto reg_it = std::find_if(
325 search_registers.cbegin(), search_registers.cend(),
326 [reg_info](auto reg) { return reg.first == reg_info->name; });
327
328 if (reg_it != search_registers.end()) {
329 // Attach the field information.
330 reg_info->register_type = reg_it->second;
331 // We do not expect to see this name again so don't look for it again.
332 search_registers.erase(reg_it);
333 }
334 }
335
336 // We do not assert that search_registers is empty here, because it may
337 // contain registers from optional extensions that are not present on the
338 // current target.
339}
#define HWCAP2_MTE
#define HWCAP3_MTE_STORE_ONLY
#define HWCAP_ASIMDHP
#define HWCAP2_BTI
#define HWCAP2_SME
#define HWCAP2_FPMR
#define HWCAP2_AFP
#define HWCAP2_EBF16
#define HWCAP_GCS
#define HWCAP2_POE
#define HWCAP_FPHP
#define HWCAP_SSBS
#define HWCAP_DIT
const RegisterType * DetectPOREL0Type(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
const RegisterType * DetectFPCRType(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
const RegisterType * DetectFPMRType(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
const RegisterType * DetectMTECtrlType(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
const RegisterType * DetectGCSFeaturesType(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
const RegisterType * DetectCPSRType(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
void UpdateRegisterInfo(const RegisterInfo *reg_info, uint32_t num_regs)
Add the type information of any registers named in this class, to the relevant RegisterInfo instances...
const RegisterType * DetectFPSRType(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
struct lldb_private::Arm64RegisterTypeDetector::RegisterEntry m_registers[8]
void DetectTypes(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
For the registers listed in this class, detect which fields are present and build types for those.
const RegisterType * DetectSVCRType(uint64_t hwcap, uint64_t hwcap2, uint64_t hwcap3)
std::vector< Enumerator > Enumerators
A class that represents a running process on the host machine.
Every register is described in detail including its name, alternate name (optional),...
const RegisterType * register_type
If not nullptr, a type defined by XML descriptions.