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
21using namespace lldb_private;
22
23std::unique_ptr<RegisterContextCorePOSIX_arm64>
24RegisterContextCorePOSIX_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: notes, Triple: arch.GetTriple(), RegsetDescs: 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: notes, Triple: arch.GetTriple(), RegsetDescs: 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: notes, Triple: arch.GetTriple(), RegsetDescs: 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: notes, Triple: arch.GetTriple(), RegsetDescs: 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: notes, Triple: arch.GetTriple(), RegsetDescs: 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: notes, Triple: arch.GetTriple(), RegsetDescs: 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: notes, Triple: arch.GetTriple(), RegsetDescs: 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: notes, Triple: arch.GetTriple(), RegsetDescs: 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: notes, Triple: arch.GetTriple(), RegsetDescs: 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>(args: arch, args&: opt_regsets);
83 return std::unique_ptr<RegisterContextCorePOSIX_arm64>(
84 new RegisterContextCorePOSIX_arm64(thread, std::move(register_info_up),
85 gpregset, notes));
86}
87
88RegisterContextCorePOSIX_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(s: &m_sme_pseudo_regs, c: 0, n: 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 std::optional<uint64_t> auxv_at_hwcap = aux_vec.GetAuxValue(
100 entry_type: os == llvm::Triple::FreeBSD ? AuxVector::AUXV_FREEBSD_AT_HWCAP
101 : AuxVector::AUXV_AT_HWCAP);
102 std::optional<uint64_t> auxv_at_hwcap2 =
103 aux_vec.GetAuxValue(entry_type: AuxVector::AUXV_AT_HWCAP2);
104
105 m_register_flags_detector.DetectFields(hwcap: auxv_at_hwcap.value_or(u: 0),
106 hwcap2: auxv_at_hwcap2.value_or(u: 0));
107 m_register_flags_detector.UpdateRegisterInfo(reg_info: GetRegisterInfo(),
108 num_regs: GetRegisterCount());
109 }
110
111 m_gpr_data.SetData(data_sp: std::make_shared<DataBufferHeap>(args: gpregset.GetDataStart(),
112 args: gpregset.GetByteSize()));
113 m_gpr_data.SetByteOrder(gpregset.GetByteOrder());
114
115 const llvm::Triple &target_triple =
116 m_register_info_up->GetTargetArchitecture().GetTriple();
117 m_fpr_data = getRegset(Notes: notes, Triple: target_triple, RegsetDescs: FPR_Desc);
118
119 if (m_register_info_up->IsSSVEPresent()) {
120 m_sve_data = getRegset(Notes: notes, Triple: target_triple, RegsetDescs: AARCH64_SSVE_Desc);
121 lldb::offset_t flags_offset = 12;
122 uint16_t flags = m_sve_data.GetU32(offset_ptr: &flags_offset);
123 if ((flags & sve::ptrace_regs_mask) == sve::ptrace_regs_sve)
124 m_sve_state = SVEState::Streaming;
125 }
126
127 if (m_sve_state != SVEState::Streaming && m_register_info_up->IsSVEPresent())
128 m_sve_data = getRegset(Notes: notes, Triple: target_triple, RegsetDescs: AARCH64_SVE_Desc);
129
130 if (m_register_info_up->IsPAuthPresent())
131 m_pac_data = getRegset(Notes: notes, Triple: target_triple, RegsetDescs: AARCH64_PAC_Desc);
132
133 if (m_register_info_up->IsTLSPresent())
134 m_tls_data = getRegset(Notes: notes, Triple: target_triple, RegsetDescs: AARCH64_TLS_Desc);
135
136 if (m_register_info_up->IsZAPresent())
137 m_za_data = getRegset(Notes: notes, Triple: target_triple, RegsetDescs: AARCH64_ZA_Desc);
138
139 if (m_register_info_up->IsMTEPresent())
140 m_mte_data = getRegset(Notes: notes, Triple: target_triple, RegsetDescs: AARCH64_MTE_Desc);
141
142 if (m_register_info_up->IsZTPresent())
143 m_zt_data = getRegset(Notes: notes, Triple: target_triple, RegsetDescs: AARCH64_ZT_Desc);
144
145 if (m_register_info_up->IsFPMRPresent())
146 m_fpmr_data = getRegset(Notes: notes, Triple: target_triple, RegsetDescs: AARCH64_FPMR_Desc);
147
148 if (m_register_info_up->IsGCSPresent())
149 m_gcs_data = getRegset(Notes: notes, Triple: target_triple, RegsetDescs: AARCH64_GCS_Desc);
150
151 ConfigureRegisterContext();
152}
153
154RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() = default;
155
156bool RegisterContextCorePOSIX_arm64::ReadGPR() { return true; }
157
158bool RegisterContextCorePOSIX_arm64::ReadFPR() { return false; }
159
160bool RegisterContextCorePOSIX_arm64::WriteGPR() {
161 assert(0);
162 return false;
163}
164
165bool RegisterContextCorePOSIX_arm64::WriteFPR() {
166 assert(0);
167 return false;
168}
169
170const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) {
171 return m_sve_data.GetDataStart() + offset;
172}
173
174void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() {
175 if (m_sve_data.GetByteSize() > sizeof(sve::user_sve_header)) {
176 uint64_t sve_header_field_offset = 8;
177 m_sve_vector_length = m_sve_data.GetU16(offset_ptr: &sve_header_field_offset);
178
179 if (m_sve_state != SVEState::Streaming) {
180 sve_header_field_offset = 12;
181 uint16_t sve_header_flags_field =
182 m_sve_data.GetU16(offset_ptr: &sve_header_field_offset);
183 if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
184 sve::ptrace_regs_fpsimd)
185 m_sve_state = SVEState::FPSIMD;
186 else if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
187 sve::ptrace_regs_sve)
188 m_sve_state = SVEState::Full;
189 }
190
191 if (!sve::vl_valid(vl: m_sve_vector_length)) {
192 m_sve_state = SVEState::Disabled;
193 m_sve_vector_length = 0;
194 }
195 } else
196 m_sve_state = SVEState::Disabled;
197
198 if (m_sve_state != SVEState::Disabled)
199 m_register_info_up->ConfigureVectorLengthSVE(
200 sve_vq: sve::vq_from_vl(vl: m_sve_vector_length));
201
202 if (m_sve_state == SVEState::Streaming)
203 m_sme_pseudo_regs.ctrl_reg |= 1;
204
205 if (m_za_data.GetByteSize() >= sizeof(sve::user_za_header)) {
206 lldb::offset_t vlen_offset = 8;
207 uint16_t svl = m_za_data.GetU16(offset_ptr: &vlen_offset);
208 m_sme_pseudo_regs.svg_reg = svl / 8;
209 m_register_info_up->ConfigureVectorLengthZA(za_vq: svl / 16);
210
211 // If there is register data then ZA is active. The size of the note may be
212 // misleading here so we use the size field of the embedded header.
213 lldb::offset_t size_offset = 0;
214 uint32_t size = m_za_data.GetU32(offset_ptr: &size_offset);
215 if (size > sizeof(sve::user_za_header))
216 m_sme_pseudo_regs.ctrl_reg |= 1 << 1;
217 }
218}
219
220uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset(
221 const RegisterInfo *reg_info) {
222 // Start of Z0 data is after GPRs plus 8 bytes of vg register
223 uint32_t sve_reg_offset = LLDB_INVALID_INDEX32;
224 if (m_sve_state == SVEState::FPSIMD) {
225 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
226 sve_reg_offset = sve::ptrace_fpsimd_offset + (reg - GetRegNumSVEZ0()) * 16;
227 } else if (m_sve_state == SVEState::Full ||
228 m_sve_state == SVEState::Streaming) {
229 uint32_t sve_z0_offset = GetGPRSize() + 16;
230 sve_reg_offset =
231 sve::SigRegsOffset() + reg_info->byte_offset - sve_z0_offset;
232 }
233
234 return sve_reg_offset;
235}
236
237bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info,
238 RegisterValue &value) {
239 Status error;
240 lldb::offset_t offset;
241
242 offset = reg_info->byte_offset;
243 if (offset + reg_info->byte_size <= GetGPRSize()) {
244 value.SetFromMemoryData(reg_info: *reg_info, src: m_gpr_data.GetDataStart() + offset,
245 src_len: reg_info->byte_size, src_byte_order: lldb::eByteOrderLittle, error);
246 return error.Success();
247 }
248
249 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
250 if (reg == LLDB_INVALID_REGNUM)
251 return false;
252
253 if (IsFPR(reg)) {
254 if (m_sve_state == SVEState::Disabled) {
255 // SVE is disabled take legacy route for FPU register access
256 offset -= GetGPRSize();
257 if (offset < m_fpr_data.GetByteSize()) {
258 value.SetFromMemoryData(reg_info: *reg_info, src: m_fpr_data.GetDataStart() + offset,
259 src_len: reg_info->byte_size, src_byte_order: lldb::eByteOrderLittle,
260 error);
261 return error.Success();
262 }
263 } else {
264 // FPSR and FPCR will be located right after Z registers in
265 // SVEState::FPSIMD while in SVEState::Full/SVEState::Streaming they will
266 // be located at the end of register data after an alignment correction
267 // based on currently selected vector length.
268 uint32_t sve_reg_num = LLDB_INVALID_REGNUM;
269 if (reg == GetRegNumFPSR()) {
270 sve_reg_num = reg;
271 if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming)
272 offset = sve::PTraceFPSROffset(vq: sve::vq_from_vl(vl: m_sve_vector_length));
273 else if (m_sve_state == SVEState::FPSIMD)
274 offset = sve::ptrace_fpsimd_offset + (32 * 16);
275 } else if (reg == GetRegNumFPCR()) {
276 sve_reg_num = reg;
277 if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming)
278 offset = sve::PTraceFPCROffset(vq: sve::vq_from_vl(vl: m_sve_vector_length));
279 else if (m_sve_state == SVEState::FPSIMD)
280 offset = sve::ptrace_fpsimd_offset + (32 * 16) + 4;
281 } else {
282 // Extract SVE Z register value register number for this reg_info
283 if (reg_info->value_regs &&
284 reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
285 sve_reg_num = reg_info->value_regs[0];
286 offset = CalculateSVEOffset(reg_info: GetRegisterInfoAtIndex(reg: sve_reg_num));
287 }
288
289 assert(sve_reg_num != LLDB_INVALID_REGNUM);
290 assert(offset < m_sve_data.GetByteSize());
291 value.SetFromMemoryData(reg_info: *reg_info, src: GetSVEBuffer(offset),
292 src_len: reg_info->byte_size, src_byte_order: lldb::eByteOrderLittle,
293 error);
294 }
295 } else if (IsSVE(reg)) {
296 if (IsSVEVG(reg)) {
297 value = GetSVERegVG();
298 return true;
299 }
300
301 switch (m_sve_state) {
302 case SVEState::FPSIMD: {
303 // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just
304 // copy 16 bytes of v register to the start of z register. All other
305 // SVE register will be set to zero.
306 uint64_t byte_size = 1;
307 uint8_t zeros = 0;
308 const uint8_t *src = &zeros;
309 if (IsSVEZ(reg)) {
310 byte_size = 16;
311 offset = CalculateSVEOffset(reg_info);
312 assert(offset < m_sve_data.GetByteSize());
313 src = GetSVEBuffer(offset);
314 }
315 value.SetFromMemoryData(reg_info: *reg_info, src, src_len: byte_size, src_byte_order: lldb::eByteOrderLittle,
316 error);
317 } break;
318 case SVEState::Full:
319 case SVEState::Streaming:
320 offset = CalculateSVEOffset(reg_info);
321 assert(offset < m_sve_data.GetByteSize());
322 value.SetFromMemoryData(reg_info: *reg_info, src: GetSVEBuffer(offset),
323 src_len: reg_info->byte_size, src_byte_order: lldb::eByteOrderLittle,
324 error);
325 break;
326 case SVEState::Disabled:
327 default:
328 return false;
329 }
330 } else if (IsPAuth(reg)) {
331 offset = reg_info->byte_offset - m_register_info_up->GetPAuthOffset();
332 assert(offset < m_pac_data.GetByteSize());
333 value.SetFromMemoryData(reg_info: *reg_info, src: m_pac_data.GetDataStart() + offset,
334 src_len: reg_info->byte_size, src_byte_order: lldb::eByteOrderLittle, error);
335 } else if (IsTLS(reg)) {
336 offset = reg_info->byte_offset - m_register_info_up->GetTLSOffset();
337 assert(offset < m_tls_data.GetByteSize());
338 value.SetFromMemoryData(reg_info: *reg_info, src: m_tls_data.GetDataStart() + offset,
339 src_len: reg_info->byte_size, src_byte_order: lldb::eByteOrderLittle, error);
340 } else if (IsMTE(reg)) {
341 offset = reg_info->byte_offset - m_register_info_up->GetMTEOffset();
342 assert(offset < m_mte_data.GetByteSize());
343 value.SetFromMemoryData(reg_info: *reg_info, src: m_mte_data.GetDataStart() + offset,
344 src_len: reg_info->byte_size, src_byte_order: lldb::eByteOrderLittle, error);
345 } else if (IsGCS(reg)) {
346 offset = reg_info->byte_offset - m_register_info_up->GetGCSOffset();
347 assert(offset < m_gcs_data.GetByteSize());
348 value.SetFromMemoryData(reg_info: *reg_info, src: m_gcs_data.GetDataStart() + offset,
349 src_len: reg_info->byte_size, src_byte_order: lldb::eByteOrderLittle, error);
350 } else if (IsSME(reg)) {
351 // If you had SME in the process, active or otherwise, there will at least
352 // be a ZA header. No header, no SME at all.
353 if (m_za_data.GetByteSize() < sizeof(sve::user_za_header))
354 return false;
355
356 if (m_register_info_up->IsSMERegZA(reg)) {
357 // Don't use the size of the note to tell whether ZA is enabled. There may
358 // be non-register padding data after the header. Use the embedded
359 // header's size field instead.
360 lldb::offset_t size_offset = 0;
361 uint32_t size = m_za_data.GetU32(offset_ptr: &size_offset);
362 bool za_enabled = size > sizeof(sve::user_za_header);
363
364 size_t za_note_size = m_za_data.GetByteSize();
365 // For a disabled ZA we fake a value of all 0s.
366 if (!za_enabled) {
367 uint64_t svl = m_sme_pseudo_regs.svg_reg * 8;
368 za_note_size = sizeof(sve::user_za_header) + (svl * svl);
369 }
370
371 const uint8_t *src = nullptr;
372 std::vector<uint8_t> disabled_za_data;
373
374 if (za_enabled)
375 src = m_za_data.GetDataStart();
376 else {
377 disabled_za_data.resize(new_size: za_note_size);
378 std::fill(first: disabled_za_data.begin(), last: disabled_za_data.end(), value: 0);
379 src = disabled_za_data.data();
380 }
381
382 value.SetFromMemoryData(reg_info: *reg_info, src: src + sizeof(sve::user_za_header),
383 src_len: reg_info->byte_size, src_byte_order: lldb::eByteOrderLittle,
384 error);
385 } else if (m_register_info_up->IsSMERegZT(reg)) {
386 value.SetFromMemoryData(reg_info: *reg_info, src: m_zt_data.GetDataStart(),
387 src_len: reg_info->byte_size, src_byte_order: lldb::eByteOrderLittle,
388 error);
389 } else {
390 offset = reg_info->byte_offset - m_register_info_up->GetSMEOffset();
391 assert(offset < sizeof(m_sme_pseudo_regs));
392 // Host endian since these values are derived instead of being read from a
393 // core file note.
394 value.SetFromMemoryData(
395 reg_info: *reg_info, src: reinterpret_cast<uint8_t *>(&m_sme_pseudo_regs) + offset,
396 src_len: reg_info->byte_size, src_byte_order: lldb_private::endian::InlHostByteOrder(), error);
397 }
398 } else if (IsFPMR(reg)) {
399 offset = reg_info->byte_offset - m_register_info_up->GetFPMROffset();
400 assert(offset < m_fpmr_data.GetByteSize());
401 value.SetFromMemoryData(reg_info: *reg_info, src: m_fpmr_data.GetDataStart() + offset,
402 src_len: reg_info->byte_size, src_byte_order: lldb::eByteOrderLittle, error);
403 } else
404 return false;
405
406 return error.Success();
407}
408
409bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues(
410 lldb::WritableDataBufferSP &data_sp) {
411 return false;
412}
413
414bool RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo *reg_info,
415 const RegisterValue &value) {
416 return false;
417}
418
419bool RegisterContextCorePOSIX_arm64::WriteAllRegisterValues(
420 const lldb::DataBufferSP &data_sp) {
421 return false;
422}
423
424bool RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable) {
425 return false;
426}
427

source code of lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp