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
21#define HWCAP2_BTI (1ULL << 17)
22#define HWCAP2_MTE (1ULL << 18)
23#define HWCAP2_AFP (1ULL << 20)
24#define HWCAP2_SME (1ULL << 23)
25#define HWCAP2_EBF16 (1ULL << 32)
26
27using namespace lldb_private;
28
30Arm64RegisterFlagsDetector::DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2) {
31 (void)hwcap;
32
33 if (!(hwcap2 & HWCAP2_SME))
34 return {};
35
36 // Represents the pseudo register that lldb-server builds, which itself
37 // matches the architectural register SCVR. The fields match SVCR in the Arm
38 // manual.
39 return {
40 {"ZA", 1},
41 {"SM", 0},
42 };
43}
44
47 uint64_t hwcap2) {
48 (void)hwcap;
49
50 if (!(hwcap2 & HWCAP2_MTE))
51 return {};
52
53 // Represents the contents of NT_ARM_TAGGED_ADDR_CTRL and the value passed
54 // to prctl(PR_TAGGED_ADDR_CTRL...). Fields are derived from the defines
55 // used to build the value.
56
57 static const FieldEnum tcf_enum(
58 "tcf_enum",
59 {{0, "TCF_NONE"}, {1, "TCF_SYNC"}, {2, "TCF_ASYNC"}, {3, "TCF_ASYMM"}});
60 return {{"TAGS", 3, 18}, // 16 bit bitfield shifted up by PR_MTE_TAG_SHIFT.
61 {"TCF", 1, 2, &tcf_enum},
62 {"TAGGED_ADDR_ENABLE", 0}};
63}
64
66Arm64RegisterFlagsDetector::DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2) {
67 static const FieldEnum rmode_enum(
68 "rmode_enum", {{0, "RN"}, {1, "RP"}, {2, "RM"}, {3, "RZ"}});
69
70 std::vector<RegisterFlags::Field> fpcr_fields{
71 {"AHP", 26}, {"DN", 25}, {"FZ", 24}, {"RMode", 22, 23, &rmode_enum},
72 // Bits 21-20 are "Stride" which is unused in AArch64 state.
73 };
74
75 // FEAT_FP16 is indicated by the presence of FPHP (floating point half
76 // precision) and ASIMDHP (Advanced SIMD half precision) features.
77 if ((hwcap & HWCAP_FPHP) && (hwcap & HWCAP_ASIMDHP))
78 fpcr_fields.push_back({"FZ16", 19});
79
80 // Bits 18-16 are "Len" which is unused in AArch64 state.
81
82 fpcr_fields.push_back({"IDE", 15});
83
84 // Bit 14 is unused.
85 if (hwcap2 & HWCAP2_EBF16)
86 fpcr_fields.push_back({"EBF", 13});
87
88 fpcr_fields.push_back({"IXE", 12});
89 fpcr_fields.push_back({"UFE", 11});
90 fpcr_fields.push_back({"OFE", 10});
91 fpcr_fields.push_back({"DZE", 9});
92 fpcr_fields.push_back({"IOE", 8});
93 // Bits 7-3 reserved.
94
95 if (hwcap2 & HWCAP2_AFP) {
96 fpcr_fields.push_back({"NEP", 2});
97 fpcr_fields.push_back({"AH", 1});
98 fpcr_fields.push_back({"FIZ", 0});
99 }
100
101 return fpcr_fields;
102}
103
105Arm64RegisterFlagsDetector::DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2) {
106 // fpsr's contents are constant.
107 (void)hwcap;
108 (void)hwcap2;
109
110 return {
111 // Bits 31-28 are N/Z/C/V, only used by AArch32.
112 {"QC", 27},
113 // Bits 26-8 reserved.
114 {"IDC", 7},
115 // Bits 6-5 reserved.
116 {"IXC", 4},
117 {"UFC", 3},
118 {"OFC", 2},
119 {"DZC", 1},
120 {"IOC", 0},
121 };
122}
123
125Arm64RegisterFlagsDetector::DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2) {
126 // The fields here are a combination of the Arm manual's SPSR_EL1,
127 // plus a few changes where Linux has decided not to make use of them at all,
128 // or at least not from userspace.
129
130 // Status bits that are always present.
131 std::vector<RegisterFlags::Field> cpsr_fields{
132 {"N", 31}, {"Z", 30}, {"C", 29}, {"V", 28},
133 // Bits 27-26 reserved.
134 };
135
136 if (hwcap2 & HWCAP2_MTE)
137 cpsr_fields.push_back({"TCO", 25});
138 if (hwcap & HWCAP_DIT)
139 cpsr_fields.push_back({"DIT", 24});
140
141 // UAO and PAN are bits 23 and 22 and have no meaning for userspace so
142 // are treated as reserved by the kernels.
143
144 cpsr_fields.push_back({"SS", 21});
145 cpsr_fields.push_back({"IL", 20});
146 // Bits 19-14 reserved.
147
148 // Bit 13, ALLINT, requires FEAT_NMI that isn't relevant to userspace, and we
149 // can't detect either, don't show this field.
150 if (hwcap & HWCAP_SSBS)
151 cpsr_fields.push_back({"SSBS", 12});
152 if (hwcap2 & HWCAP2_BTI)
153 cpsr_fields.push_back({"BTYPE", 10, 11});
154
155 cpsr_fields.push_back({"D", 9});
156 cpsr_fields.push_back({"A", 8});
157 cpsr_fields.push_back({"I", 7});
158 cpsr_fields.push_back({"F", 6});
159 // Bit 5 reserved
160 // Called "M" in the ARMARM.
161 cpsr_fields.push_back({"nRW", 4});
162 // This is a 4 bit field M[3:0] in the ARMARM, we split it into parts.
163 cpsr_fields.push_back({"EL", 2, 3});
164 // Bit 1 is unused and expected to be 0.
165 cpsr_fields.push_back({"SP", 0});
166
167 return cpsr_fields;
168}
169
170void Arm64RegisterFlagsDetector::DetectFields(uint64_t hwcap, uint64_t hwcap2) {
171 for (auto &reg : m_registers)
172 reg.m_flags.SetFields(reg.m_detector(hwcap, hwcap2));
173 m_has_detected = true;
174}
175
177 const RegisterInfo *reg_info, uint32_t num_regs) {
178 assert(m_has_detected &&
179 "Must call DetectFields before updating register info.");
180
181 // Register names will not be duplicated, so we do not want to compare against
182 // one if it has already been found. Each time we find one, we erase it from
183 // this list.
184 std::vector<std::pair<llvm::StringRef, const RegisterFlags *>>
185 search_registers;
186 for (const auto &reg : m_registers) {
187 // It is possible that a register is all extension dependent fields, and
188 // none of them are present.
189 if (reg.m_flags.GetFields().size())
190 search_registers.push_back({reg.m_name, &reg.m_flags});
191 }
192
193 // Walk register information while there are registers we know need
194 // to be updated. Example:
195 // Register information: [a, b, c, d]
196 // To be patched: [b, c]
197 // * a != b, a != c, do nothing and move on.
198 // * b == b, patch b, new patch list is [c], move on.
199 // * c == c, patch c, patch list is empty, exit early without looking at d.
200 for (uint32_t idx = 0; idx < num_regs && search_registers.size();
201 ++idx, ++reg_info) {
202 auto reg_it = std::find_if(
203 search_registers.cbegin(), search_registers.cend(),
204 [reg_info](auto reg) { return reg.first == reg_info->name; });
205
206 if (reg_it != search_registers.end()) {
207 // Attach the field information.
208 reg_info->flags_type = reg_it->second;
209 // We do not expect to see this name again so don't look for it again.
210 search_registers.erase(reg_it);
211 }
212 }
213
214 // We do not assert that search_registers is empty here, because it may
215 // contain registers from optional extensions that are not present on the
216 // current target.
217}
#define HWCAP2_MTE
#define HWCAP_ASIMDHP
#define HWCAP2_BTI
#define HWCAP2_SME
#define HWCAP2_AFP
#define HWCAP2_EBF16
#define HWCAP_FPHP
#define HWCAP_SSBS
#define HWCAP_DIT
std::vector< RegisterFlags::Field > Fields
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...
static Fields DetectFPSRFields(uint64_t hwcap, uint64_t hwcap2)
struct lldb_private::Arm64RegisterFlagsDetector::RegisterEntry m_registers[5]
static Fields DetectSVCRFields(uint64_t hwcap, uint64_t hwcap2)
static Fields DetectCPSRFields(uint64_t hwcap, uint64_t hwcap2)
static Fields DetectMTECtrlFields(uint64_t hwcap, uint64_t hwcap2)
void DetectFields(uint64_t hwcap, uint64_t hwcap2)
For the registers listed in this class, detect which fields are present.
static Fields DetectFPCRFields(uint64_t hwcap, uint64_t hwcap2)
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.