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