LLDB mainline
RegisterContextPOSIXCore_arm64.cpp
Go to the documentation of this file.
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
11
16#include "lldb/Target/Thread.h"
18
19#include <memory>
20
21using namespace lldb_private;
22
23std::unique_ptr<RegisterContextCorePOSIX_arm64>
25 const DataExtractor &gpregset,
26 llvm::ArrayRef<CoreNote> notes) {
28
29 DataExtractor ssve_data =
31 if (ssve_data.GetByteSize() >= sizeof(sve::user_sve_header))
33
34 DataExtractor sve_data = getRegset(notes, arch.GetTriple(), AARCH64_SVE_Desc);
35 if (sve_data.GetByteSize() >= sizeof(sve::user_sve_header))
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)
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))
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))
55
56 DataExtractor mte_data = getRegset(notes, arch.GetTriple(), AARCH64_MTE_Desc);
57 if (mte_data.GetByteSize() >= sizeof(uint64_t))
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)
66
67 DataExtractor fpmr_data =
69 if (fpmr_data.GetByteSize() >= sizeof(uint64_t))
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))
80
81 DataExtractor poe_data = getRegset(notes, arch.GetTriple(), AARCH64_POE_Desc);
82 struct poe_regs {
83 uint64_t por_reg;
84 };
85 if (poe_data.GetByteSize() >= sizeof(poe_regs))
87
88 auto register_info_up =
89 std::make_unique<RegisterInfoPOSIX_arm64>(arch, opt_regsets);
90 return std::unique_ptr<RegisterContextCorePOSIX_arm64>(
91 new RegisterContextCorePOSIX_arm64(thread, std::move(register_info_up),
92 gpregset, notes));
93}
94
96 Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info,
97 const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
98 : RegisterContextPOSIX_arm64(thread, std::move(register_info)) {
99 ::memset(&m_sme_pseudo_regs, 0, sizeof(m_sme_pseudo_regs));
100
101 ProcessElfCore *process =
102 static_cast<ProcessElfCore *>(thread.GetProcess().get());
103 llvm::Triple::OSType os = process->GetArchitecture().GetTriple().getOS();
104 if ((os == llvm::Triple::Linux) || (os == llvm::Triple::FreeBSD)) {
105 AuxVector aux_vec(process->GetAuxvData());
106 bool is_freebsd = os == llvm::Triple::FreeBSD;
107 std::optional<uint64_t> auxv_at_hwcap =
110 std::optional<uint64_t> auxv_at_hwcap2 =
112 std::optional<uint64_t> auxv_at_hwcap3 =
113 is_freebsd ? std::nullopt
115
116 m_register_flags_detector.DetectFields(auxv_at_hwcap.value_or(0),
117 auxv_at_hwcap2.value_or(0),
118 auxv_at_hwcap3.value_or(0));
119 m_register_flags_detector.UpdateRegisterInfo(GetRegisterInfo(),
121 }
122
123 m_gpr_data.SetData(std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
124 gpregset.GetByteSize()));
125 m_gpr_data.SetByteOrder(gpregset.GetByteOrder());
126
127 const llvm::Triple &target_triple =
128 m_register_info_up->GetTargetArchitecture().GetTriple();
129 m_fpr_data = getRegset(notes, target_triple, FPR_Desc);
130
131 if (m_register_info_up->IsSSVEPresent()) {
132 m_sve_data = getRegset(notes, target_triple, AARCH64_SSVE_Desc);
133 lldb::offset_t flags_offset = 12;
134 uint16_t flags = m_sve_data.GetU32(&flags_offset);
137 }
138
139 if (m_sve_state != SVEState::Streaming && m_register_info_up->IsSVEPresent())
140 m_sve_data = getRegset(notes, target_triple, AARCH64_SVE_Desc);
141
142 if (m_register_info_up->IsPAuthPresent())
143 m_pac_data = getRegset(notes, target_triple, AARCH64_PAC_Desc);
144
145 if (m_register_info_up->IsTLSPresent())
146 m_tls_data = getRegset(notes, target_triple, AARCH64_TLS_Desc);
147
148 if (m_register_info_up->IsZAPresent())
149 m_za_data = getRegset(notes, target_triple, AARCH64_ZA_Desc);
150
151 if (m_register_info_up->IsMTEPresent())
152 m_mte_data = getRegset(notes, target_triple, AARCH64_MTE_Desc);
153
154 if (m_register_info_up->IsZTPresent())
155 m_zt_data = getRegset(notes, target_triple, AARCH64_ZT_Desc);
156
157 if (m_register_info_up->IsFPMRPresent())
158 m_fpmr_data = getRegset(notes, target_triple, AARCH64_FPMR_Desc);
159
160 if (m_register_info_up->IsGCSPresent())
161 m_gcs_data = getRegset(notes, target_triple, AARCH64_GCS_Desc);
162
163 if (m_register_info_up->IsPOEPresent())
164 m_poe_data = getRegset(notes, target_triple, AARCH64_POE_Desc);
165
167}
168
170
172
174
176 assert(0);
177 return false;
178}
179
181 assert(0);
182 return false;
183}
184
185const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) {
186 return m_sve_data.GetDataStart() + offset;
187}
188
190 if (m_sve_data.GetByteSize() > sizeof(sve::user_sve_header)) {
191 uint64_t sve_header_field_offset = 8;
192 m_sve_vector_length = m_sve_data.GetU16(&sve_header_field_offset);
193
195 sve_header_field_offset = 12;
196 uint16_t sve_header_flags_field =
197 m_sve_data.GetU16(&sve_header_field_offset);
198 if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
201 else if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
204 }
205
209 }
210 } else
212
214 m_register_info_up->ConfigureVectorLengthSVE(
216
218 m_sme_pseudo_regs.ctrl_reg |= 1;
219
220 if (m_za_data.GetByteSize() >= sizeof(sve::user_za_header)) {
221 lldb::offset_t vlen_offset = 8;
222 uint16_t svl = m_za_data.GetU16(&vlen_offset);
223 m_sme_pseudo_regs.svg_reg = svl / 8;
224 m_register_info_up->ConfigureVectorLengthZA(svl / 16);
225
226 // If there is register data then ZA is active. The size of the note may be
227 // misleading here so we use the size field of the embedded header.
228 lldb::offset_t size_offset = 0;
229 uint32_t size = m_za_data.GetU32(&size_offset);
230 if (size > sizeof(sve::user_za_header))
231 m_sme_pseudo_regs.ctrl_reg |= 1 << 1;
232 }
233}
234
236 const RegisterInfo *reg_info) {
237 // Start of Z0 data is after GPRs plus 8 bytes of vg register
238 uint32_t sve_reg_offset = LLDB_INVALID_INDEX32;
240 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
241 sve_reg_offset = sve::ptrace_fpsimd_offset + (reg - GetRegNumSVEZ0()) * 16;
242 } else if (m_sve_state == SVEState::Full ||
244 uint32_t sve_z0_offset = GetGPRSize() + 16;
245 sve_reg_offset =
246 sve::SigRegsOffset() + reg_info->byte_offset - sve_z0_offset;
247 }
248
249 return sve_reg_offset;
250}
251
253 RegisterValue &value) {
255 lldb::offset_t offset;
256
257 offset = reg_info->byte_offset;
258 if (offset + reg_info->byte_size <= GetGPRSize()) {
259 value.SetFromMemoryData(*reg_info, m_gpr_data.GetDataStart() + offset,
261 return error.Success();
262 }
263
264 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
265 if (reg == LLDB_INVALID_REGNUM)
266 return false;
267
268 if (IsFPR(reg)) {
270 // SVE is disabled take legacy route for FPU register access
271 offset -= GetGPRSize();
272 if (offset < m_fpr_data.GetByteSize()) {
273 value.SetFromMemoryData(*reg_info, m_fpr_data.GetDataStart() + offset,
275 error);
276 return error.Success();
277 }
278 } else {
279 // FPSR and FPCR will be located right after Z registers in
280 // SVEState::FPSIMD while in SVEState::Full/SVEState::Streaming they will
281 // be located at the end of register data after an alignment correction
282 // based on currently selected vector length.
283 uint32_t sve_reg_num = LLDB_INVALID_REGNUM;
284 if (reg == GetRegNumFPSR()) {
285 sve_reg_num = reg;
288 else if (m_sve_state == SVEState::FPSIMD)
289 offset = sve::ptrace_fpsimd_offset + (32 * 16);
290 } else if (reg == GetRegNumFPCR()) {
291 sve_reg_num = reg;
294 else if (m_sve_state == SVEState::FPSIMD)
295 offset = sve::ptrace_fpsimd_offset + (32 * 16) + 4;
296 } else {
297 // Extract SVE Z register value register number for this reg_info
298 if (reg_info->value_regs &&
299 reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
300 sve_reg_num = reg_info->value_regs[0];
301 offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num));
302 }
303
304 assert(sve_reg_num != LLDB_INVALID_REGNUM);
305 assert(offset < m_sve_data.GetByteSize());
306 value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset),
308 error);
309 }
310 } else if (IsSVE(reg)) {
311 if (IsSVEVG(reg)) {
312 value = GetSVERegVG();
313 return true;
314 }
315
316 switch (m_sve_state) {
317 case SVEState::FPSIMD: {
318 // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just
319 // copy 16 bytes of v register to the start of z register. All other
320 // SVE register will be set to zero.
321 uint64_t byte_size = 1;
322 uint8_t zeros = 0;
323 const uint8_t *src = &zeros;
324 if (IsSVEZ(reg)) {
325 byte_size = 16;
326 offset = CalculateSVEOffset(reg_info);
327 assert(offset < m_sve_data.GetByteSize());
328 src = GetSVEBuffer(offset);
329 }
330 value.SetFromMemoryData(*reg_info, src, byte_size, lldb::eByteOrderLittle,
331 error);
332 } break;
333 case SVEState::Full:
335 offset = CalculateSVEOffset(reg_info);
336 assert(offset < m_sve_data.GetByteSize());
337 value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset),
339 error);
340 break;
342 default:
343 return false;
344 }
345 } else if (IsPAuth(reg)) {
346 offset = reg_info->byte_offset - m_register_info_up->GetPAuthOffset();
347 assert(offset < m_pac_data.GetByteSize());
348 value.SetFromMemoryData(*reg_info, m_pac_data.GetDataStart() + offset,
350 } else if (IsTLS(reg)) {
351 offset = reg_info->byte_offset - m_register_info_up->GetTLSOffset();
352 assert(offset < m_tls_data.GetByteSize());
353 value.SetFromMemoryData(*reg_info, m_tls_data.GetDataStart() + offset,
355 } else if (IsMTE(reg)) {
356 offset = reg_info->byte_offset - m_register_info_up->GetMTEOffset();
357 assert(offset < m_mte_data.GetByteSize());
358 value.SetFromMemoryData(*reg_info, m_mte_data.GetDataStart() + offset,
360 } else if (IsGCS(reg)) {
361 offset = reg_info->byte_offset - m_register_info_up->GetGCSOffset();
362 assert(offset < m_gcs_data.GetByteSize());
363 value.SetFromMemoryData(*reg_info, m_gcs_data.GetDataStart() + offset,
365 } else if (IsSME(reg)) {
366 // If you had SME in the process, active or otherwise, there will at least
367 // be a ZA header. No header, no SME at all.
368 if (m_za_data.GetByteSize() < sizeof(sve::user_za_header))
369 return false;
370
371 if (m_register_info_up->IsSMERegZA(reg)) {
372 // Don't use the size of the note to tell whether ZA is enabled. There may
373 // be non-register padding data after the header. Use the embedded
374 // header's size field instead.
375 lldb::offset_t size_offset = 0;
376 uint32_t size = m_za_data.GetU32(&size_offset);
377 bool za_enabled = size > sizeof(sve::user_za_header);
378
379 size_t za_note_size = m_za_data.GetByteSize();
380 // For a disabled ZA we fake a value of all 0s.
381 if (!za_enabled) {
382 uint64_t svl = m_sme_pseudo_regs.svg_reg * 8;
383 za_note_size = sizeof(sve::user_za_header) + (svl * svl);
384 }
385
386 const uint8_t *src = nullptr;
387 std::vector<uint8_t> disabled_za_data;
388
389 if (za_enabled)
390 src = m_za_data.GetDataStart();
391 else {
392 disabled_za_data.resize(za_note_size);
393 std::fill(disabled_za_data.begin(), disabled_za_data.end(), 0);
394 src = disabled_za_data.data();
395 }
396
397 value.SetFromMemoryData(*reg_info, src + sizeof(sve::user_za_header),
399 error);
400 } else if (m_register_info_up->IsSMERegZT(reg)) {
401 value.SetFromMemoryData(*reg_info, m_zt_data.GetDataStart(),
403 error);
404 } else {
405 offset = reg_info->byte_offset - m_register_info_up->GetSMEOffset();
406 assert(offset < sizeof(m_sme_pseudo_regs));
407 // Host endian since these values are derived instead of being read from a
408 // core file note.
409 value.SetFromMemoryData(
410 *reg_info, reinterpret_cast<uint8_t *>(&m_sme_pseudo_regs) + offset,
412 }
413 } else if (IsFPMR(reg)) {
414 offset = reg_info->byte_offset - m_register_info_up->GetFPMROffset();
415 assert(offset < m_fpmr_data.GetByteSize());
416 value.SetFromMemoryData(*reg_info, m_fpmr_data.GetDataStart() + offset,
418 } else if (IsPOE(reg)) {
419 offset = reg_info->byte_offset - m_register_info_up->GetPOEOffset();
420 assert(offset < m_poe_data.GetByteSize());
421 value.SetFromMemoryData(*reg_info, m_poe_data.GetDataStart() + offset,
423 } else
424 return false;
425
426 return error.Success();
427}
428
433
435 const RegisterValue &value) {
436 return false;
437}
438
440 const lldb::DataBufferSP &data_sp) {
441 return false;
442}
443
445 return false;
446}
static llvm::raw_ostream & error(Stream &strm)
@ AUXV_FREEBSD_AT_HWCAP
FreeBSD specific AT_HWCAP value.
Definition AuxVector.h:72
@ AUXV_AT_HWCAP2
Extension of AT_HWCAP.
Definition AuxVector.h:59
@ AUXV_AT_HWCAP3
Extension of AT_HWCAP.
Definition AuxVector.h:60
@ AUXV_AT_HWCAP
Machine dependent hints about processor capabilities.
Definition AuxVector.h:49
std::optional< uint64_t > GetAuxValue(enum EntryType entry_type) const
Definition AuxVector.cpp:34
lldb_private::DataExtractor GetAuxvData() override
lldb_private::ArchSpec GetArchitecture()
struct __attribute__((packed)) sme_pseudo_regs
static std::unique_ptr< RegisterContextCorePOSIX_arm64 > Create(lldb_private::Thread &thread, const lldb_private::ArchSpec &arch, const lldb_private::DataExtractor &gpregset, llvm::ArrayRef< lldb_private::CoreNote > notes)
~RegisterContextCorePOSIX_arm64() override
RegisterContextCorePOSIX_arm64(lldb_private::Thread &thread, std::unique_ptr< RegisterInfoPOSIX_arm64 > register_info, const lldb_private::DataExtractor &gpregset, llvm::ArrayRef< lldb_private::CoreNote > notes)
uint32_t CalculateSVEOffset(const lldb_private::RegisterInfo *reg_info)
lldb_private::Arm64RegisterFlagsDetector m_register_flags_detector
bool ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override
const uint8_t * GetSVEBuffer(uint64_t offset=0)
bool WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override
bool WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value) override
bool ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value) override
virtual const lldb_private::RegisterInfo * GetRegisterInfo()
const lldb_private::RegisterInfo * GetRegisterInfoAtIndex(size_t reg) override
std::unique_ptr< RegisterInfoPOSIX_arm64 > m_register_info_up
RegisterContextPOSIX_arm64(lldb_private::Thread &thread, std::unique_ptr< RegisterInfoPOSIX_arm64 > register_info)
An architecture specification class.
Definition ArchSpec.h:32
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition ArchSpec.h:457
An data extractor class.
virtual uint64_t GetByteSize() const
Get the number of bytes contained in this object.
const uint8_t * GetDataStart() const
Get the data start pointer.
lldb::ByteOrder GetByteOrder() const
Get the current byte order value.
A class to manage flags.
Definition Flags.h:22
ValueType Set(ValueType mask)
Set one or more flags by logical OR'ing mask with the current flags.
Definition Flags.h:73
uint32_t SetFromMemoryData(const RegisterInfo &reg_info, const void *src, uint32_t src_len, lldb::ByteOrder src_byte_order, Status &error)
An error handling class.
Definition Status.h:118
#define LLDB_INVALID_INDEX32
#define LLDB_INVALID_REGNUM
lldb::ByteOrder InlHostByteOrder()
Definition Endian.h:25
uint16_t vq_from_vl(uint16_t vl)
uint32_t PTraceFPSROffset(uint16_t vq)
uint32_t PTraceFPCROffset(uint16_t vq)
uint16_t vl_valid(uint16_t vl)
A class that represents a running process on the host machine.
DataExtractor getRegset(llvm::ArrayRef< CoreNote > Notes, const llvm::Triple &Triple, llvm::ArrayRef< RegsetDesc > RegsetDescs)
constexpr RegsetDesc AARCH64_TLS_Desc[]
constexpr RegsetDesc AARCH64_FPMR_Desc[]
constexpr RegsetDesc AARCH64_ZT_Desc[]
constexpr RegsetDesc AARCH64_SSVE_Desc[]
constexpr RegsetDesc FPR_Desc[]
constexpr RegsetDesc AARCH64_GCS_Desc[]
constexpr RegsetDesc AARCH64_POE_Desc[]
constexpr RegsetDesc AARCH64_MTE_Desc[]
constexpr RegsetDesc AARCH64_SVE_Desc[]
constexpr RegsetDesc AARCH64_PAC_Desc[]
constexpr RegsetDesc AARCH64_ZA_Desc[]
uint64_t offset_t
Definition lldb-types.h:85
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
@ eRegisterKindLLDB
lldb's internal register numbers
Every register is described in detail including its name, alternate name (optional),...
uint32_t * value_regs
List of registers (terminated with LLDB_INVALID_REGNUM).
uint32_t byte_offset
The byte offset in the register context data where this register's value is found.
uint32_t byte_size
Size in bytes of the register.
uint32_t kinds[lldb::kNumRegisterKinds]
Holds all of the various register numbers for all register kinds.