1 //===-- RegisterContextPOSIXCore_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 "RegisterContextPOSIXCore_arm64.h"
10 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
11
12 #include "Plugins/Process/Utility/AuxVector.h"
13 #include "Plugins/Process/Utility/RegisterFlagsDetector_arm64.h"
14 #include "Plugins/Process/elf-core/ProcessElfCore.h"
15 #include "Plugins/Process/elf-core/RegisterUtilities.h"
16 #include "lldb/Target/Thread.h"
17 #include "lldb/Utility/RegisterValue.h"
18
19 #include <memory>
20
21 using namespace lldb_private;
22
23 std::unique_ptr<RegisterContextCorePOSIX_arm64>
Create(Thread & thread,const ArchSpec & arch,const DataExtractor & gpregset,llvm::ArrayRef<CoreNote> notes)24 RegisterContextCorePOSIX_arm64::Create(Thread &thread, const ArchSpec &arch,
25 const DataExtractor &gpregset,
26 llvm::ArrayRef<CoreNote> notes) {
27 Flags opt_regsets = RegisterInfoPOSIX_arm64::eRegsetMaskDefault;
28
29 DataExtractor ssve_data =
30 getRegset(notes, arch.GetTriple(), AARCH64_SSVE_Desc);
31 if (ssve_data.GetByteSize() >= sizeof(sve::user_sve_header))
32 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSSVE);
33
34 DataExtractor sve_data = getRegset(notes, arch.GetTriple(), AARCH64_SVE_Desc);
35 if (sve_data.GetByteSize() >= sizeof(sve::user_sve_header))
36 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE);
37
38 // Pointer Authentication register set data is based on struct
39 // user_pac_mask declared in ptrace.h. See reference implementation
40 // in Linux kernel source at arch/arm64/include/uapi/asm/ptrace.h.
41 DataExtractor pac_data = getRegset(notes, arch.GetTriple(), AARCH64_PAC_Desc);
42 if (pac_data.GetByteSize() >= sizeof(uint64_t) * 2)
43 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskPAuth);
44
45 DataExtractor tls_data = getRegset(notes, arch.GetTriple(), AARCH64_TLS_Desc);
46 // A valid note will always contain at least one register, "tpidr". It may
47 // expand in future.
48 if (tls_data.GetByteSize() >= sizeof(uint64_t))
49 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskTLS);
50
51 DataExtractor za_data = getRegset(notes, arch.GetTriple(), AARCH64_ZA_Desc);
52 // Nothing if ZA is not present, just the header if it is disabled.
53 if (za_data.GetByteSize() >= sizeof(sve::user_za_header))
54 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskZA);
55
56 DataExtractor mte_data = getRegset(notes, arch.GetTriple(), AARCH64_MTE_Desc);
57 if (mte_data.GetByteSize() >= sizeof(uint64_t))
58 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskMTE);
59
60 DataExtractor zt_data = getRegset(notes, arch.GetTriple(), AARCH64_ZT_Desc);
61 // Although ZT0 can be in a disabled state like ZA can, the kernel reports
62 // its content as 0s in that state. Therefore even a disabled ZT0 will have
63 // a note containing those 0s. ZT0 is a 512 bit / 64 byte register.
64 if (zt_data.GetByteSize() >= 64)
65 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskZT);
66
67 DataExtractor fpmr_data =
68 getRegset(notes, arch.GetTriple(), AARCH64_FPMR_Desc);
69 if (fpmr_data.GetByteSize() >= sizeof(uint64_t))
70 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskFPMR);
71
72 DataExtractor gcs_data = getRegset(notes, arch.GetTriple(), AARCH64_GCS_Desc);
73 struct __attribute__((packed)) gcs_regs {
74 uint64_t features_enabled;
75 uint64_t features_locked;
76 uint64_t gcspr_e0;
77 };
78 if (gcs_data.GetByteSize() >= sizeof(gcs_regs))
79 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskGCS);
80
81 auto register_info_up =
82 std::make_unique<RegisterInfoPOSIX_arm64>(arch, opt_regsets);
83 return std::unique_ptr<RegisterContextCorePOSIX_arm64>(
84 new RegisterContextCorePOSIX_arm64(thread, std::move(register_info_up),
85 gpregset, notes));
86 }
87
RegisterContextCorePOSIX_arm64(Thread & thread,std::unique_ptr<RegisterInfoPOSIX_arm64> register_info,const DataExtractor & gpregset,llvm::ArrayRef<CoreNote> notes)88 RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
89 Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info,
90 const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
91 : RegisterContextPOSIX_arm64(thread, std::move(register_info)) {
92 ::memset(&m_sme_pseudo_regs, 0, sizeof(m_sme_pseudo_regs));
93
94 ProcessElfCore *process =
95 static_cast<ProcessElfCore *>(thread.GetProcess().get());
96 llvm::Triple::OSType os = process->GetArchitecture().GetTriple().getOS();
97 if ((os == llvm::Triple::Linux) || (os == llvm::Triple::FreeBSD)) {
98 AuxVector aux_vec(process->GetAuxvData());
99 bool is_freebsd = os == llvm::Triple::FreeBSD;
100 std::optional<uint64_t> auxv_at_hwcap =
101 aux_vec.GetAuxValue(is_freebsd ? AuxVector::AUXV_FREEBSD_AT_HWCAP
102 : AuxVector::AUXV_AT_HWCAP);
103 std::optional<uint64_t> auxv_at_hwcap2 =
104 aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP2);
105 std::optional<uint64_t> auxv_at_hwcap3 =
106 is_freebsd ? std::nullopt
107 : aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP3);
108
109 m_register_flags_detector.DetectFields(auxv_at_hwcap.value_or(0),
110 auxv_at_hwcap2.value_or(0),
111 auxv_at_hwcap3.value_or(0));
112 m_register_flags_detector.UpdateRegisterInfo(GetRegisterInfo(),
113 GetRegisterCount());
114 }
115
116 m_gpr_data.SetData(std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
117 gpregset.GetByteSize()));
118 m_gpr_data.SetByteOrder(gpregset.GetByteOrder());
119
120 const llvm::Triple &target_triple =
121 m_register_info_up->GetTargetArchitecture().GetTriple();
122 m_fpr_data = getRegset(notes, target_triple, FPR_Desc);
123
124 if (m_register_info_up->IsSSVEPresent()) {
125 m_sve_data = getRegset(notes, target_triple, AARCH64_SSVE_Desc);
126 lldb::offset_t flags_offset = 12;
127 uint16_t flags = m_sve_data.GetU32(&flags_offset);
128 if ((flags & sve::ptrace_regs_mask) == sve::ptrace_regs_sve)
129 m_sve_state = SVEState::Streaming;
130 }
131
132 if (m_sve_state != SVEState::Streaming && m_register_info_up->IsSVEPresent())
133 m_sve_data = getRegset(notes, target_triple, AARCH64_SVE_Desc);
134
135 if (m_register_info_up->IsPAuthPresent())
136 m_pac_data = getRegset(notes, target_triple, AARCH64_PAC_Desc);
137
138 if (m_register_info_up->IsTLSPresent())
139 m_tls_data = getRegset(notes, target_triple, AARCH64_TLS_Desc);
140
141 if (m_register_info_up->IsZAPresent())
142 m_za_data = getRegset(notes, target_triple, AARCH64_ZA_Desc);
143
144 if (m_register_info_up->IsMTEPresent())
145 m_mte_data = getRegset(notes, target_triple, AARCH64_MTE_Desc);
146
147 if (m_register_info_up->IsZTPresent())
148 m_zt_data = getRegset(notes, target_triple, AARCH64_ZT_Desc);
149
150 if (m_register_info_up->IsFPMRPresent())
151 m_fpmr_data = getRegset(notes, target_triple, AARCH64_FPMR_Desc);
152
153 if (m_register_info_up->IsGCSPresent())
154 m_gcs_data = getRegset(notes, target_triple, AARCH64_GCS_Desc);
155
156 ConfigureRegisterContext();
157 }
158
159 RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() = default;
160
ReadGPR()161 bool RegisterContextCorePOSIX_arm64::ReadGPR() { return true; }
162
ReadFPR()163 bool RegisterContextCorePOSIX_arm64::ReadFPR() { return false; }
164
WriteGPR()165 bool RegisterContextCorePOSIX_arm64::WriteGPR() {
166 assert(0);
167 return false;
168 }
169
WriteFPR()170 bool RegisterContextCorePOSIX_arm64::WriteFPR() {
171 assert(0);
172 return false;
173 }
174
GetSVEBuffer(uint64_t offset)175 const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) {
176 return m_sve_data.GetDataStart() + offset;
177 }
178
ConfigureRegisterContext()179 void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() {
180 if (m_sve_data.GetByteSize() > sizeof(sve::user_sve_header)) {
181 uint64_t sve_header_field_offset = 8;
182 m_sve_vector_length = m_sve_data.GetU16(&sve_header_field_offset);
183
184 if (m_sve_state != SVEState::Streaming) {
185 sve_header_field_offset = 12;
186 uint16_t sve_header_flags_field =
187 m_sve_data.GetU16(&sve_header_field_offset);
188 if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
189 sve::ptrace_regs_fpsimd)
190 m_sve_state = SVEState::FPSIMD;
191 else if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
192 sve::ptrace_regs_sve)
193 m_sve_state = SVEState::Full;
194 }
195
196 if (!sve::vl_valid(m_sve_vector_length)) {
197 m_sve_state = SVEState::Disabled;
198 m_sve_vector_length = 0;
199 }
200 } else
201 m_sve_state = SVEState::Disabled;
202
203 if (m_sve_state != SVEState::Disabled)
204 m_register_info_up->ConfigureVectorLengthSVE(
205 sve::vq_from_vl(m_sve_vector_length));
206
207 if (m_sve_state == SVEState::Streaming)
208 m_sme_pseudo_regs.ctrl_reg |= 1;
209
210 if (m_za_data.GetByteSize() >= sizeof(sve::user_za_header)) {
211 lldb::offset_t vlen_offset = 8;
212 uint16_t svl = m_za_data.GetU16(&vlen_offset);
213 m_sme_pseudo_regs.svg_reg = svl / 8;
214 m_register_info_up->ConfigureVectorLengthZA(svl / 16);
215
216 // If there is register data then ZA is active. The size of the note may be
217 // misleading here so we use the size field of the embedded header.
218 lldb::offset_t size_offset = 0;
219 uint32_t size = m_za_data.GetU32(&size_offset);
220 if (size > sizeof(sve::user_za_header))
221 m_sme_pseudo_regs.ctrl_reg |= 1 << 1;
222 }
223 }
224
CalculateSVEOffset(const RegisterInfo * reg_info)225 uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset(
226 const RegisterInfo *reg_info) {
227 // Start of Z0 data is after GPRs plus 8 bytes of vg register
228 uint32_t sve_reg_offset = LLDB_INVALID_INDEX32;
229 if (m_sve_state == SVEState::FPSIMD) {
230 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
231 sve_reg_offset = sve::ptrace_fpsimd_offset + (reg - GetRegNumSVEZ0()) * 16;
232 } else if (m_sve_state == SVEState::Full ||
233 m_sve_state == SVEState::Streaming) {
234 uint32_t sve_z0_offset = GetGPRSize() + 16;
235 sve_reg_offset =
236 sve::SigRegsOffset() + reg_info->byte_offset - sve_z0_offset;
237 }
238
239 return sve_reg_offset;
240 }
241
ReadRegister(const RegisterInfo * reg_info,RegisterValue & value)242 bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info,
243 RegisterValue &value) {
244 Status error;
245 lldb::offset_t offset;
246
247 offset = reg_info->byte_offset;
248 if (offset + reg_info->byte_size <= GetGPRSize()) {
249 value.SetFromMemoryData(*reg_info, m_gpr_data.GetDataStart() + offset,
250 reg_info->byte_size, lldb::eByteOrderLittle, error);
251 return error.Success();
252 }
253
254 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
255 if (reg == LLDB_INVALID_REGNUM)
256 return false;
257
258 if (IsFPR(reg)) {
259 if (m_sve_state == SVEState::Disabled) {
260 // SVE is disabled take legacy route for FPU register access
261 offset -= GetGPRSize();
262 if (offset < m_fpr_data.GetByteSize()) {
263 value.SetFromMemoryData(*reg_info, m_fpr_data.GetDataStart() + offset,
264 reg_info->byte_size, lldb::eByteOrderLittle,
265 error);
266 return error.Success();
267 }
268 } else {
269 // FPSR and FPCR will be located right after Z registers in
270 // SVEState::FPSIMD while in SVEState::Full/SVEState::Streaming they will
271 // be located at the end of register data after an alignment correction
272 // based on currently selected vector length.
273 uint32_t sve_reg_num = LLDB_INVALID_REGNUM;
274 if (reg == GetRegNumFPSR()) {
275 sve_reg_num = reg;
276 if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming)
277 offset = sve::PTraceFPSROffset(sve::vq_from_vl(m_sve_vector_length));
278 else if (m_sve_state == SVEState::FPSIMD)
279 offset = sve::ptrace_fpsimd_offset + (32 * 16);
280 } else if (reg == GetRegNumFPCR()) {
281 sve_reg_num = reg;
282 if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming)
283 offset = sve::PTraceFPCROffset(sve::vq_from_vl(m_sve_vector_length));
284 else if (m_sve_state == SVEState::FPSIMD)
285 offset = sve::ptrace_fpsimd_offset + (32 * 16) + 4;
286 } else {
287 // Extract SVE Z register value register number for this reg_info
288 if (reg_info->value_regs &&
289 reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
290 sve_reg_num = reg_info->value_regs[0];
291 offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num));
292 }
293
294 assert(sve_reg_num != LLDB_INVALID_REGNUM);
295 assert(offset < m_sve_data.GetByteSize());
296 value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset),
297 reg_info->byte_size, lldb::eByteOrderLittle,
298 error);
299 }
300 } else if (IsSVE(reg)) {
301 if (IsSVEVG(reg)) {
302 value = GetSVERegVG();
303 return true;
304 }
305
306 switch (m_sve_state) {
307 case SVEState::FPSIMD: {
308 // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just
309 // copy 16 bytes of v register to the start of z register. All other
310 // SVE register will be set to zero.
311 uint64_t byte_size = 1;
312 uint8_t zeros = 0;
313 const uint8_t *src = &zeros;
314 if (IsSVEZ(reg)) {
315 byte_size = 16;
316 offset = CalculateSVEOffset(reg_info);
317 assert(offset < m_sve_data.GetByteSize());
318 src = GetSVEBuffer(offset);
319 }
320 value.SetFromMemoryData(*reg_info, src, byte_size, lldb::eByteOrderLittle,
321 error);
322 } break;
323 case SVEState::Full:
324 case SVEState::Streaming:
325 offset = CalculateSVEOffset(reg_info);
326 assert(offset < m_sve_data.GetByteSize());
327 value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset),
328 reg_info->byte_size, lldb::eByteOrderLittle,
329 error);
330 break;
331 case SVEState::Disabled:
332 default:
333 return false;
334 }
335 } else if (IsPAuth(reg)) {
336 offset = reg_info->byte_offset - m_register_info_up->GetPAuthOffset();
337 assert(offset < m_pac_data.GetByteSize());
338 value.SetFromMemoryData(*reg_info, m_pac_data.GetDataStart() + offset,
339 reg_info->byte_size, lldb::eByteOrderLittle, error);
340 } else if (IsTLS(reg)) {
341 offset = reg_info->byte_offset - m_register_info_up->GetTLSOffset();
342 assert(offset < m_tls_data.GetByteSize());
343 value.SetFromMemoryData(*reg_info, m_tls_data.GetDataStart() + offset,
344 reg_info->byte_size, lldb::eByteOrderLittle, error);
345 } else if (IsMTE(reg)) {
346 offset = reg_info->byte_offset - m_register_info_up->GetMTEOffset();
347 assert(offset < m_mte_data.GetByteSize());
348 value.SetFromMemoryData(*reg_info, m_mte_data.GetDataStart() + offset,
349 reg_info->byte_size, lldb::eByteOrderLittle, error);
350 } else if (IsGCS(reg)) {
351 offset = reg_info->byte_offset - m_register_info_up->GetGCSOffset();
352 assert(offset < m_gcs_data.GetByteSize());
353 value.SetFromMemoryData(*reg_info, m_gcs_data.GetDataStart() + offset,
354 reg_info->byte_size, lldb::eByteOrderLittle, error);
355 } else if (IsSME(reg)) {
356 // If you had SME in the process, active or otherwise, there will at least
357 // be a ZA header. No header, no SME at all.
358 if (m_za_data.GetByteSize() < sizeof(sve::user_za_header))
359 return false;
360
361 if (m_register_info_up->IsSMERegZA(reg)) {
362 // Don't use the size of the note to tell whether ZA is enabled. There may
363 // be non-register padding data after the header. Use the embedded
364 // header's size field instead.
365 lldb::offset_t size_offset = 0;
366 uint32_t size = m_za_data.GetU32(&size_offset);
367 bool za_enabled = size > sizeof(sve::user_za_header);
368
369 size_t za_note_size = m_za_data.GetByteSize();
370 // For a disabled ZA we fake a value of all 0s.
371 if (!za_enabled) {
372 uint64_t svl = m_sme_pseudo_regs.svg_reg * 8;
373 za_note_size = sizeof(sve::user_za_header) + (svl * svl);
374 }
375
376 const uint8_t *src = nullptr;
377 std::vector<uint8_t> disabled_za_data;
378
379 if (za_enabled)
380 src = m_za_data.GetDataStart();
381 else {
382 disabled_za_data.resize(za_note_size);
383 std::fill(disabled_za_data.begin(), disabled_za_data.end(), 0);
384 src = disabled_za_data.data();
385 }
386
387 value.SetFromMemoryData(*reg_info, src + sizeof(sve::user_za_header),
388 reg_info->byte_size, lldb::eByteOrderLittle,
389 error);
390 } else if (m_register_info_up->IsSMERegZT(reg)) {
391 value.SetFromMemoryData(*reg_info, m_zt_data.GetDataStart(),
392 reg_info->byte_size, lldb::eByteOrderLittle,
393 error);
394 } else {
395 offset = reg_info->byte_offset - m_register_info_up->GetSMEOffset();
396 assert(offset < sizeof(m_sme_pseudo_regs));
397 // Host endian since these values are derived instead of being read from a
398 // core file note.
399 value.SetFromMemoryData(
400 *reg_info, reinterpret_cast<uint8_t *>(&m_sme_pseudo_regs) + offset,
401 reg_info->byte_size, lldb_private::endian::InlHostByteOrder(), error);
402 }
403 } else if (IsFPMR(reg)) {
404 offset = reg_info->byte_offset - m_register_info_up->GetFPMROffset();
405 assert(offset < m_fpmr_data.GetByteSize());
406 value.SetFromMemoryData(*reg_info, m_fpmr_data.GetDataStart() + offset,
407 reg_info->byte_size, lldb::eByteOrderLittle, error);
408 } else
409 return false;
410
411 return error.Success();
412 }
413
ReadAllRegisterValues(lldb::WritableDataBufferSP & data_sp)414 bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues(
415 lldb::WritableDataBufferSP &data_sp) {
416 return false;
417 }
418
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & value)419 bool RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo *reg_info,
420 const RegisterValue &value) {
421 return false;
422 }
423
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)424 bool RegisterContextCorePOSIX_arm64::WriteAllRegisterValues(
425 const lldb::DataBufferSP &data_sp) {
426 return false;
427 }
428
HardwareSingleStep(bool enable)429 bool RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable) {
430 return false;
431 }
432