1 //===-- RegisterContextPOSIXCore_arm64.cpp --------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "RegisterContextPOSIXCore_arm64.h"
10 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
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"
21 using namespace lldb_private
;
23 std::unique_ptr
<RegisterContextCorePOSIX_arm64
>
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
;
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
);
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
);
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
);
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
48 if (tls_data
.GetByteSize() >= sizeof(uint64_t))
49 opt_regsets
.Set(RegisterInfoPOSIX_arm64::eRegsetMaskTLS
);
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
);
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
);
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
);
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
);
72 auto register_info_up
=
73 std::make_unique
<RegisterInfoPOSIX_arm64
>(arch
, opt_regsets
);
74 return std::unique_ptr
<RegisterContextCorePOSIX_arm64
>(
75 new RegisterContextCorePOSIX_arm64(thread
, std::move(register_info_up
),
79 RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
80 Thread
&thread
, std::unique_ptr
<RegisterInfoPOSIX_arm64
> register_info
,
81 const DataExtractor
&gpregset
, llvm::ArrayRef
<CoreNote
> notes
)
82 : RegisterContextPOSIX_arm64(thread
, std::move(register_info
)) {
83 ::memset(&m_sme_pseudo_regs
, 0, sizeof(m_sme_pseudo_regs
));
85 ProcessElfCore
*process
=
86 static_cast<ProcessElfCore
*>(thread
.GetProcess().get());
87 llvm::Triple::OSType os
= process
->GetArchitecture().GetTriple().getOS();
88 if ((os
== llvm::Triple::Linux
) || (os
== llvm::Triple::FreeBSD
)) {
89 AuxVector
aux_vec(process
->GetAuxvData());
90 std::optional
<uint64_t> auxv_at_hwcap
= aux_vec
.GetAuxValue(
91 os
== llvm::Triple::FreeBSD
? AuxVector::AUXV_FREEBSD_AT_HWCAP
92 : AuxVector::AUXV_AT_HWCAP
);
93 std::optional
<uint64_t> auxv_at_hwcap2
=
94 aux_vec
.GetAuxValue(AuxVector::AUXV_AT_HWCAP2
);
96 m_register_flags_detector
.DetectFields(auxv_at_hwcap
.value_or(0),
97 auxv_at_hwcap2
.value_or(0));
98 m_register_flags_detector
.UpdateRegisterInfo(GetRegisterInfo(),
102 m_gpr_data
.SetData(std::make_shared
<DataBufferHeap
>(gpregset
.GetDataStart(),
103 gpregset
.GetByteSize()));
104 m_gpr_data
.SetByteOrder(gpregset
.GetByteOrder());
106 const llvm::Triple
&target_triple
=
107 m_register_info_up
->GetTargetArchitecture().GetTriple();
108 m_fpr_data
= getRegset(notes
, target_triple
, FPR_Desc
);
110 if (m_register_info_up
->IsSSVEPresent()) {
111 m_sve_data
= getRegset(notes
, target_triple
, AARCH64_SSVE_Desc
);
112 lldb::offset_t flags_offset
= 12;
113 uint16_t flags
= m_sve_data
.GetU32(&flags_offset
);
114 if ((flags
& sve::ptrace_regs_mask
) == sve::ptrace_regs_sve
)
115 m_sve_state
= SVEState::Streaming
;
118 if (m_sve_state
!= SVEState::Streaming
&& m_register_info_up
->IsSVEPresent())
119 m_sve_data
= getRegset(notes
, target_triple
, AARCH64_SVE_Desc
);
121 if (m_register_info_up
->IsPAuthPresent())
122 m_pac_data
= getRegset(notes
, target_triple
, AARCH64_PAC_Desc
);
124 if (m_register_info_up
->IsTLSPresent())
125 m_tls_data
= getRegset(notes
, target_triple
, AARCH64_TLS_Desc
);
127 if (m_register_info_up
->IsZAPresent())
128 m_za_data
= getRegset(notes
, target_triple
, AARCH64_ZA_Desc
);
130 if (m_register_info_up
->IsMTEPresent())
131 m_mte_data
= getRegset(notes
, target_triple
, AARCH64_MTE_Desc
);
133 if (m_register_info_up
->IsZTPresent())
134 m_zt_data
= getRegset(notes
, target_triple
, AARCH64_ZT_Desc
);
136 if (m_register_info_up
->IsFPMRPresent())
137 m_fpmr_data
= getRegset(notes
, target_triple
, AARCH64_FPMR_Desc
);
139 ConfigureRegisterContext();
142 RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() = default;
144 bool RegisterContextCorePOSIX_arm64::ReadGPR() { return true; }
146 bool RegisterContextCorePOSIX_arm64::ReadFPR() { return false; }
148 bool RegisterContextCorePOSIX_arm64::WriteGPR() {
153 bool RegisterContextCorePOSIX_arm64::WriteFPR() {
158 const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset
) {
159 return m_sve_data
.GetDataStart() + offset
;
162 void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() {
163 if (m_sve_data
.GetByteSize() > sizeof(sve::user_sve_header
)) {
164 uint64_t sve_header_field_offset
= 8;
165 m_sve_vector_length
= m_sve_data
.GetU16(&sve_header_field_offset
);
167 if (m_sve_state
!= SVEState::Streaming
) {
168 sve_header_field_offset
= 12;
169 uint16_t sve_header_flags_field
=
170 m_sve_data
.GetU16(&sve_header_field_offset
);
171 if ((sve_header_flags_field
& sve::ptrace_regs_mask
) ==
172 sve::ptrace_regs_fpsimd
)
173 m_sve_state
= SVEState::FPSIMD
;
174 else if ((sve_header_flags_field
& sve::ptrace_regs_mask
) ==
175 sve::ptrace_regs_sve
)
176 m_sve_state
= SVEState::Full
;
179 if (!sve::vl_valid(m_sve_vector_length
)) {
180 m_sve_state
= SVEState::Disabled
;
181 m_sve_vector_length
= 0;
184 m_sve_state
= SVEState::Disabled
;
186 if (m_sve_state
!= SVEState::Disabled
)
187 m_register_info_up
->ConfigureVectorLengthSVE(
188 sve::vq_from_vl(m_sve_vector_length
));
190 if (m_sve_state
== SVEState::Streaming
)
191 m_sme_pseudo_regs
.ctrl_reg
|= 1;
193 if (m_za_data
.GetByteSize() >= sizeof(sve::user_za_header
)) {
194 lldb::offset_t vlen_offset
= 8;
195 uint16_t svl
= m_za_data
.GetU16(&vlen_offset
);
196 m_sme_pseudo_regs
.svg_reg
= svl
/ 8;
197 m_register_info_up
->ConfigureVectorLengthZA(svl
/ 16);
199 // If there is register data then ZA is active. The size of the note may be
200 // misleading here so we use the size field of the embedded header.
201 lldb::offset_t size_offset
= 0;
202 uint32_t size
= m_za_data
.GetU32(&size_offset
);
203 if (size
> sizeof(sve::user_za_header
))
204 m_sme_pseudo_regs
.ctrl_reg
|= 1 << 1;
208 uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset(
209 const RegisterInfo
*reg_info
) {
210 // Start of Z0 data is after GPRs plus 8 bytes of vg register
211 uint32_t sve_reg_offset
= LLDB_INVALID_INDEX32
;
212 if (m_sve_state
== SVEState::FPSIMD
) {
213 const uint32_t reg
= reg_info
->kinds
[lldb::eRegisterKindLLDB
];
214 sve_reg_offset
= sve::ptrace_fpsimd_offset
+ (reg
- GetRegNumSVEZ0()) * 16;
215 } else if (m_sve_state
== SVEState::Full
||
216 m_sve_state
== SVEState::Streaming
) {
217 uint32_t sve_z0_offset
= GetGPRSize() + 16;
219 sve::SigRegsOffset() + reg_info
->byte_offset
- sve_z0_offset
;
222 return sve_reg_offset
;
225 bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo
*reg_info
,
226 RegisterValue
&value
) {
228 lldb::offset_t offset
;
230 offset
= reg_info
->byte_offset
;
231 if (offset
+ reg_info
->byte_size
<= GetGPRSize()) {
232 value
.SetFromMemoryData(*reg_info
, m_gpr_data
.GetDataStart() + offset
,
233 reg_info
->byte_size
, lldb::eByteOrderLittle
, error
);
234 return error
.Success();
237 const uint32_t reg
= reg_info
->kinds
[lldb::eRegisterKindLLDB
];
238 if (reg
== LLDB_INVALID_REGNUM
)
242 if (m_sve_state
== SVEState::Disabled
) {
243 // SVE is disabled take legacy route for FPU register access
244 offset
-= GetGPRSize();
245 if (offset
< m_fpr_data
.GetByteSize()) {
246 value
.SetFromMemoryData(*reg_info
, m_fpr_data
.GetDataStart() + offset
,
247 reg_info
->byte_size
, lldb::eByteOrderLittle
,
249 return error
.Success();
252 // FPSR and FPCR will be located right after Z registers in
253 // SVEState::FPSIMD while in SVEState::Full/SVEState::Streaming they will
254 // be located at the end of register data after an alignment correction
255 // based on currently selected vector length.
256 uint32_t sve_reg_num
= LLDB_INVALID_REGNUM
;
257 if (reg
== GetRegNumFPSR()) {
259 if (m_sve_state
== SVEState::Full
|| m_sve_state
== SVEState::Streaming
)
260 offset
= sve::PTraceFPSROffset(sve::vq_from_vl(m_sve_vector_length
));
261 else if (m_sve_state
== SVEState::FPSIMD
)
262 offset
= sve::ptrace_fpsimd_offset
+ (32 * 16);
263 } else if (reg
== GetRegNumFPCR()) {
265 if (m_sve_state
== SVEState::Full
|| m_sve_state
== SVEState::Streaming
)
266 offset
= sve::PTraceFPCROffset(sve::vq_from_vl(m_sve_vector_length
));
267 else if (m_sve_state
== SVEState::FPSIMD
)
268 offset
= sve::ptrace_fpsimd_offset
+ (32 * 16) + 4;
270 // Extract SVE Z register value register number for this reg_info
271 if (reg_info
->value_regs
&&
272 reg_info
->value_regs
[0] != LLDB_INVALID_REGNUM
)
273 sve_reg_num
= reg_info
->value_regs
[0];
274 offset
= CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num
));
277 assert(sve_reg_num
!= LLDB_INVALID_REGNUM
);
278 assert(offset
< m_sve_data
.GetByteSize());
279 value
.SetFromMemoryData(*reg_info
, GetSVEBuffer(offset
),
280 reg_info
->byte_size
, lldb::eByteOrderLittle
,
283 } else if (IsSVE(reg
)) {
285 value
= GetSVERegVG();
289 switch (m_sve_state
) {
290 case SVEState::FPSIMD
: {
291 // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just
292 // copy 16 bytes of v register to the start of z register. All other
293 // SVE register will be set to zero.
294 uint64_t byte_size
= 1;
296 const uint8_t *src
= &zeros
;
299 offset
= CalculateSVEOffset(reg_info
);
300 assert(offset
< m_sve_data
.GetByteSize());
301 src
= GetSVEBuffer(offset
);
303 value
.SetFromMemoryData(*reg_info
, src
, byte_size
, lldb::eByteOrderLittle
,
307 case SVEState::Streaming
:
308 offset
= CalculateSVEOffset(reg_info
);
309 assert(offset
< m_sve_data
.GetByteSize());
310 value
.SetFromMemoryData(*reg_info
, GetSVEBuffer(offset
),
311 reg_info
->byte_size
, lldb::eByteOrderLittle
,
314 case SVEState::Disabled
:
318 } else if (IsPAuth(reg
)) {
319 offset
= reg_info
->byte_offset
- m_register_info_up
->GetPAuthOffset();
320 assert(offset
< m_pac_data
.GetByteSize());
321 value
.SetFromMemoryData(*reg_info
, m_pac_data
.GetDataStart() + offset
,
322 reg_info
->byte_size
, lldb::eByteOrderLittle
, error
);
323 } else if (IsTLS(reg
)) {
324 offset
= reg_info
->byte_offset
- m_register_info_up
->GetTLSOffset();
325 assert(offset
< m_tls_data
.GetByteSize());
326 value
.SetFromMemoryData(*reg_info
, m_tls_data
.GetDataStart() + offset
,
327 reg_info
->byte_size
, lldb::eByteOrderLittle
, error
);
328 } else if (IsMTE(reg
)) {
329 offset
= reg_info
->byte_offset
- m_register_info_up
->GetMTEOffset();
330 assert(offset
< m_mte_data
.GetByteSize());
331 value
.SetFromMemoryData(*reg_info
, m_mte_data
.GetDataStart() + offset
,
332 reg_info
->byte_size
, lldb::eByteOrderLittle
, error
);
333 } else if (IsSME(reg
)) {
334 // If you had SME in the process, active or otherwise, there will at least
335 // be a ZA header. No header, no SME at all.
336 if (m_za_data
.GetByteSize() < sizeof(sve::user_za_header
))
339 if (m_register_info_up
->IsSMERegZA(reg
)) {
340 // Don't use the size of the note to tell whether ZA is enabled. There may
341 // be non-register padding data after the header. Use the embedded
342 // header's size field instead.
343 lldb::offset_t size_offset
= 0;
344 uint32_t size
= m_za_data
.GetU32(&size_offset
);
345 bool za_enabled
= size
> sizeof(sve::user_za_header
);
347 size_t za_note_size
= m_za_data
.GetByteSize();
348 // For a disabled ZA we fake a value of all 0s.
350 uint64_t svl
= m_sme_pseudo_regs
.svg_reg
* 8;
351 za_note_size
= sizeof(sve::user_za_header
) + (svl
* svl
);
354 const uint8_t *src
= nullptr;
355 std::vector
<uint8_t> disabled_za_data
;
358 src
= m_za_data
.GetDataStart();
360 disabled_za_data
.resize(za_note_size
);
361 std::fill(disabled_za_data
.begin(), disabled_za_data
.end(), 0);
362 src
= disabled_za_data
.data();
365 value
.SetFromMemoryData(*reg_info
, src
+ sizeof(sve::user_za_header
),
366 reg_info
->byte_size
, lldb::eByteOrderLittle
,
368 } else if (m_register_info_up
->IsSMERegZT(reg
)) {
369 value
.SetFromMemoryData(*reg_info
, m_zt_data
.GetDataStart(),
370 reg_info
->byte_size
, lldb::eByteOrderLittle
,
373 offset
= reg_info
->byte_offset
- m_register_info_up
->GetSMEOffset();
374 assert(offset
< sizeof(m_sme_pseudo_regs
));
375 // Host endian since these values are derived instead of being read from a
377 value
.SetFromMemoryData(
378 *reg_info
, reinterpret_cast<uint8_t *>(&m_sme_pseudo_regs
) + offset
,
379 reg_info
->byte_size
, lldb_private::endian::InlHostByteOrder(), error
);
381 } else if (IsFPMR(reg
)) {
382 offset
= reg_info
->byte_offset
- m_register_info_up
->GetFPMROffset();
383 assert(offset
< m_fpmr_data
.GetByteSize());
384 value
.SetFromMemoryData(*reg_info
, m_fpmr_data
.GetDataStart() + offset
,
385 reg_info
->byte_size
, lldb::eByteOrderLittle
, error
);
389 return error
.Success();
392 bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues(
393 lldb::WritableDataBufferSP
&data_sp
) {
397 bool RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo
*reg_info
,
398 const RegisterValue
&value
) {
402 bool RegisterContextCorePOSIX_arm64::WriteAllRegisterValues(
403 const lldb::DataBufferSP
&data_sp
) {
407 bool RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable
) {