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 auto register_info_up =
68 std::make_unique<RegisterInfoPOSIX_arm64>(arch, opt_regsets);
69 return std::unique_ptr<RegisterContextCorePOSIX_arm64>(
70 new RegisterContextCorePOSIX_arm64(thread, std::move(register_info_up),
71 gpregset, notes));
72}
73
75 Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info,
76 const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
77 : RegisterContextPOSIX_arm64(thread, std::move(register_info)) {
78 ::memset(&m_sme_pseudo_regs, 0, sizeof(m_sme_pseudo_regs));
79
80 ProcessElfCore *process =
81 static_cast<ProcessElfCore *>(thread.GetProcess().get());
82 llvm::Triple::OSType os = process->GetArchitecture().GetTriple().getOS();
83 if ((os == llvm::Triple::Linux) || (os == llvm::Triple::FreeBSD)) {
84 AuxVector aux_vec(process->GetAuxvData());
85 std::optional<uint64_t> auxv_at_hwcap = aux_vec.GetAuxValue(
86 os == llvm::Triple::FreeBSD ? AuxVector::AUXV_FREEBSD_AT_HWCAP
88 std::optional<uint64_t> auxv_at_hwcap2 =
90
91 m_register_flags_detector.DetectFields(auxv_at_hwcap.value_or(0),
92 auxv_at_hwcap2.value_or(0));
95 }
96
97 m_gpr_data.SetData(std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
98 gpregset.GetByteSize()));
100
101 const llvm::Triple &target_triple =
102 m_register_info_up->GetTargetArchitecture().GetTriple();
103 m_fpr_data = getRegset(notes, target_triple, FPR_Desc);
104
105 if (m_register_info_up->IsSSVEPresent()) {
106 m_sve_data = getRegset(notes, target_triple, AARCH64_SSVE_Desc);
107 lldb::offset_t flags_offset = 12;
108 uint16_t flags = m_sve_data.GetU32(&flags_offset);
110 m_sve_state = SVEState::Streaming;
111 }
112
113 if (m_sve_state != SVEState::Streaming && m_register_info_up->IsSVEPresent())
114 m_sve_data = getRegset(notes, target_triple, AARCH64_SVE_Desc);
115
116 if (m_register_info_up->IsPAuthPresent())
117 m_pac_data = getRegset(notes, target_triple, AARCH64_PAC_Desc);
118
119 if (m_register_info_up->IsTLSPresent())
120 m_tls_data = getRegset(notes, target_triple, AARCH64_TLS_Desc);
121
122 if (m_register_info_up->IsZAPresent())
123 m_za_data = getRegset(notes, target_triple, AARCH64_ZA_Desc);
124
125 if (m_register_info_up->IsMTEPresent())
126 m_mte_data = getRegset(notes, target_triple, AARCH64_MTE_Desc);
127
128 if (m_register_info_up->IsZTPresent())
129 m_zt_data = getRegset(notes, target_triple, AARCH64_ZT_Desc);
130
132}
133
135
137
139
141 assert(0);
142 return false;
143}
144
146 assert(0);
147 return false;
148}
149
150const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) {
151 return m_sve_data.GetDataStart() + offset;
152}
153
156 uint64_t sve_header_field_offset = 8;
157 m_sve_vector_length = m_sve_data.GetU16(&sve_header_field_offset);
158
159 if (m_sve_state != SVEState::Streaming) {
160 sve_header_field_offset = 12;
161 uint16_t sve_header_flags_field =
162 m_sve_data.GetU16(&sve_header_field_offset);
163 if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
165 m_sve_state = SVEState::FPSIMD;
166 else if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
168 m_sve_state = SVEState::Full;
169 }
170
172 m_sve_state = SVEState::Disabled;
174 }
175 } else
176 m_sve_state = SVEState::Disabled;
177
178 if (m_sve_state != SVEState::Disabled)
179 m_register_info_up->ConfigureVectorLengthSVE(
181
182 if (m_sve_state == SVEState::Streaming)
183 m_sme_pseudo_regs.ctrl_reg |= 1;
184
185 if (m_za_data.GetByteSize() >= sizeof(sve::user_za_header)) {
186 lldb::offset_t vlen_offset = 8;
187 uint16_t svl = m_za_data.GetU16(&vlen_offset);
188 m_sme_pseudo_regs.svg_reg = svl / 8;
189 m_register_info_up->ConfigureVectorLengthZA(svl / 16);
190
191 // If there is register data then ZA is active. The size of the note may be
192 // misleading here so we use the size field of the embedded header.
193 lldb::offset_t size_offset = 0;
194 uint32_t size = m_za_data.GetU32(&size_offset);
195 if (size > sizeof(sve::user_za_header))
196 m_sme_pseudo_regs.ctrl_reg |= 1 << 1;
197 }
198}
199
201 const RegisterInfo *reg_info) {
202 // Start of Z0 data is after GPRs plus 8 bytes of vg register
203 uint32_t sve_reg_offset = LLDB_INVALID_INDEX32;
204 if (m_sve_state == SVEState::FPSIMD) {
205 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
206 sve_reg_offset = sve::ptrace_fpsimd_offset + (reg - GetRegNumSVEZ0()) * 16;
207 } else if (m_sve_state == SVEState::Full ||
208 m_sve_state == SVEState::Streaming) {
209 uint32_t sve_z0_offset = GetGPRSize() + 16;
210 sve_reg_offset =
211 sve::SigRegsOffset() + reg_info->byte_offset - sve_z0_offset;
212 }
213
214 return sve_reg_offset;
215}
216
218 RegisterValue &value) {
220 lldb::offset_t offset;
221
222 offset = reg_info->byte_offset;
223 if (offset + reg_info->byte_size <= GetGPRSize()) {
224 value.SetFromMemoryData(*reg_info, m_gpr_data.GetDataStart() + offset,
226 return error.Success();
227 }
228
229 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
230 if (reg == LLDB_INVALID_REGNUM)
231 return false;
232
233 if (IsFPR(reg)) {
234 if (m_sve_state == SVEState::Disabled) {
235 // SVE is disabled take legacy route for FPU register access
236 offset -= GetGPRSize();
237 if (offset < m_fpr_data.GetByteSize()) {
238 value.SetFromMemoryData(*reg_info, m_fpr_data.GetDataStart() + offset,
240 error);
241 return error.Success();
242 }
243 } else {
244 // FPSR and FPCR will be located right after Z registers in
245 // SVEState::FPSIMD while in SVEState::Full/SVEState::Streaming they will
246 // be located at the end of register data after an alignment correction
247 // based on currently selected vector length.
248 uint32_t sve_reg_num = LLDB_INVALID_REGNUM;
249 if (reg == GetRegNumFPSR()) {
250 sve_reg_num = reg;
251 if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming)
253 else if (m_sve_state == SVEState::FPSIMD)
254 offset = sve::ptrace_fpsimd_offset + (32 * 16);
255 } else if (reg == GetRegNumFPCR()) {
256 sve_reg_num = reg;
257 if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming)
259 else if (m_sve_state == SVEState::FPSIMD)
260 offset = sve::ptrace_fpsimd_offset + (32 * 16) + 4;
261 } else {
262 // Extract SVE Z register value register number for this reg_info
263 if (reg_info->value_regs &&
264 reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
265 sve_reg_num = reg_info->value_regs[0];
266 offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num));
267 }
268
269 assert(sve_reg_num != LLDB_INVALID_REGNUM);
270 assert(offset < m_sve_data.GetByteSize());
271 value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset),
273 error);
274 }
275 } else if (IsSVE(reg)) {
276 if (IsSVEVG(reg)) {
277 value = GetSVERegVG();
278 return true;
279 }
280
281 switch (m_sve_state) {
282 case SVEState::FPSIMD: {
283 // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just
284 // copy 16 bytes of v register to the start of z register. All other
285 // SVE register will be set to zero.
286 uint64_t byte_size = 1;
287 uint8_t zeros = 0;
288 const uint8_t *src = &zeros;
289 if (IsSVEZ(reg)) {
290 byte_size = 16;
291 offset = CalculateSVEOffset(reg_info);
292 assert(offset < m_sve_data.GetByteSize());
293 src = GetSVEBuffer(offset);
294 }
295 value.SetFromMemoryData(*reg_info, src, byte_size, lldb::eByteOrderLittle,
296 error);
297 } break;
298 case SVEState::Full:
299 case SVEState::Streaming:
300 offset = CalculateSVEOffset(reg_info);
301 assert(offset < m_sve_data.GetByteSize());
302 value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset),
304 error);
305 break;
306 case SVEState::Disabled:
307 default:
308 return false;
309 }
310 } else if (IsPAuth(reg)) {
311 offset = reg_info->byte_offset - m_register_info_up->GetPAuthOffset();
312 assert(offset < m_pac_data.GetByteSize());
313 value.SetFromMemoryData(*reg_info, m_pac_data.GetDataStart() + offset,
315 } else if (IsTLS(reg)) {
316 offset = reg_info->byte_offset - m_register_info_up->GetTLSOffset();
317 assert(offset < m_tls_data.GetByteSize());
318 value.SetFromMemoryData(*reg_info, m_tls_data.GetDataStart() + offset,
320 } else if (IsMTE(reg)) {
321 offset = reg_info->byte_offset - m_register_info_up->GetMTEOffset();
322 assert(offset < m_mte_data.GetByteSize());
323 value.SetFromMemoryData(*reg_info, m_mte_data.GetDataStart() + offset,
325 } else if (IsSME(reg)) {
326 // If you had SME in the process, active or otherwise, there will at least
327 // be a ZA header. No header, no SME at all.
329 return false;
330
331 if (m_register_info_up->IsSMERegZA(reg)) {
332 // Don't use the size of the note to tell whether ZA is enabled. There may
333 // be non-register padding data after the header. Use the embedded
334 // header's size field instead.
335 lldb::offset_t size_offset = 0;
336 uint32_t size = m_za_data.GetU32(&size_offset);
337 bool za_enabled = size > sizeof(sve::user_za_header);
338
339 size_t za_note_size = m_za_data.GetByteSize();
340 // For a disabled ZA we fake a value of all 0s.
341 if (!za_enabled) {
342 uint64_t svl = m_sme_pseudo_regs.svg_reg * 8;
343 za_note_size = sizeof(sve::user_za_header) + (svl * svl);
344 }
345
346 const uint8_t *src = nullptr;
347 std::vector<uint8_t> disabled_za_data;
348
349 if (za_enabled)
350 src = m_za_data.GetDataStart();
351 else {
352 disabled_za_data.resize(za_note_size);
353 std::fill(disabled_za_data.begin(), disabled_za_data.end(), 0);
354 src = disabled_za_data.data();
355 }
356
357 value.SetFromMemoryData(*reg_info, src + sizeof(sve::user_za_header),
359 error);
360 } else if (m_register_info_up->IsSMERegZT(reg)) {
361 value.SetFromMemoryData(*reg_info, m_zt_data.GetDataStart(),
363 error);
364 } else {
365 offset = reg_info->byte_offset - m_register_info_up->GetSMEOffset();
366 assert(offset < sizeof(m_sme_pseudo_regs));
367 // Host endian since these values are derived instead of being read from a
368 // core file note.
369 value.SetFromMemoryData(
370 *reg_info, reinterpret_cast<uint8_t *>(&m_sme_pseudo_regs) + offset,
372 }
373 } else
374 return false;
375
376 return error.Success();
377}
378
381 return false;
382}
383
385 const RegisterValue &value) {
386 return false;
387}
388
390 const lldb::DataBufferSP &data_sp) {
391 return false;
392}
393
395 return false;
396}
static llvm::raw_ostream & error(Stream &strm)
@ AUXV_FREEBSD_AT_HWCAP
FreeBSD specific AT_HWCAP value.
Definition: AuxVector.h:71
@ AUXV_AT_HWCAP2
Extension of AT_HWCAP.
Definition: AuxVector.h:59
@ 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()
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
bool IsSVEVG(unsigned reg) const
An architecture specification class.
Definition: ArchSpec.h:31
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:450
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...
void DetectFields(uint64_t hwcap, uint64_t hwcap2)
For the registers listed in this class, detect which fields are present.
An data extractor class.
Definition: DataExtractor.h:48
void SetByteOrder(lldb::ByteOrder byte_order)
Set the byte_order value.
uint32_t GetU32(lldb::offset_t *offset_ptr) const
Extract a uint32_t value from *offset_ptr.
uint64_t GetByteSize() const
Get the number of bytes contained in this object.
uint16_t GetU16(lldb::offset_t *offset_ptr) const
Extract a uint16_t value from *offset_ptr.
const uint8_t * GetDataStart() const
Get the data start pointer.
lldb::offset_t SetData(const void *bytes, lldb::offset_t length, lldb::ByteOrder byte_order)
Set data with a buffer that is caller owned.
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:44
lldb::ProcessSP GetProcess() const
Definition: Thread.h:155
#define LLDB_INVALID_INDEX32
Definition: lldb-defines.h:83
#define LLDB_INVALID_REGNUM
Definition: lldb-defines.h:87
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_ZT_Desc[]
constexpr RegsetDesc AARCH64_SSVE_Desc[]
constexpr RegsetDesc FPR_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
@ eByteOrderLittle
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
Definition: lldb-forward.h:332
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
Definition: lldb-forward.h:333
@ 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.