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

source code of lldb/source/Plugins/Process/Utility/RegisterFlagsLinux_arm64.cpp