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/elf-core/RegisterUtilities.h"
13 #include "lldb/Target/Thread.h"
14 #include "lldb/Utility/RegisterValue.h"
18 using namespace lldb_private
;
20 std::unique_ptr
<RegisterContextCorePOSIX_arm64
>
21 RegisterContextCorePOSIX_arm64::Create(Thread
&thread
, const ArchSpec
&arch
,
22 const DataExtractor
&gpregset
,
23 llvm::ArrayRef
<CoreNote
> notes
) {
24 Flags opt_regsets
= RegisterInfoPOSIX_arm64::eRegsetMaskDefault
;
26 DataExtractor ssve_data
=
27 getRegset(notes
, arch
.GetTriple(), AARCH64_SSVE_Desc
);
28 if (ssve_data
.GetByteSize() >= sizeof(sve::user_sve_header
))
29 opt_regsets
.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSSVE
);
31 DataExtractor sve_data
= getRegset(notes
, arch
.GetTriple(), AARCH64_SVE_Desc
);
32 if (sve_data
.GetByteSize() >= sizeof(sve::user_sve_header
))
33 opt_regsets
.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE
);
35 // Pointer Authentication register set data is based on struct
36 // user_pac_mask declared in ptrace.h. See reference implementation
37 // in Linux kernel source at arch/arm64/include/uapi/asm/ptrace.h.
38 DataExtractor pac_data
= getRegset(notes
, arch
.GetTriple(), AARCH64_PAC_Desc
);
39 if (pac_data
.GetByteSize() >= sizeof(uint64_t) * 2)
40 opt_regsets
.Set(RegisterInfoPOSIX_arm64::eRegsetMaskPAuth
);
42 DataExtractor tls_data
= getRegset(notes
, arch
.GetTriple(), AARCH64_TLS_Desc
);
43 // A valid note will always contain at least one register, "tpidr". It may
45 if (tls_data
.GetByteSize() >= sizeof(uint64_t))
46 opt_regsets
.Set(RegisterInfoPOSIX_arm64::eRegsetMaskTLS
);
48 DataExtractor za_data
= getRegset(notes
, arch
.GetTriple(), AARCH64_ZA_Desc
);
49 // Nothing if ZA is not present, just the header if it is disabled.
50 if (za_data
.GetByteSize() >= sizeof(sve::user_za_header
))
51 opt_regsets
.Set(RegisterInfoPOSIX_arm64::eRegsetMaskZA
);
53 DataExtractor mte_data
= getRegset(notes
, arch
.GetTriple(), AARCH64_MTE_Desc
);
54 if (mte_data
.GetByteSize() >= sizeof(uint64_t))
55 opt_regsets
.Set(RegisterInfoPOSIX_arm64::eRegsetMaskMTE
);
57 auto register_info_up
=
58 std::make_unique
<RegisterInfoPOSIX_arm64
>(arch
, opt_regsets
);
59 return std::unique_ptr
<RegisterContextCorePOSIX_arm64
>(
60 new RegisterContextCorePOSIX_arm64(thread
, std::move(register_info_up
),
64 RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
65 Thread
&thread
, std::unique_ptr
<RegisterInfoPOSIX_arm64
> register_info
,
66 const DataExtractor
&gpregset
, llvm::ArrayRef
<CoreNote
> notes
)
67 : RegisterContextPOSIX_arm64(thread
, std::move(register_info
)) {
68 ::memset(&m_sme_pseudo_regs
, 0, sizeof(m_sme_pseudo_regs
));
70 m_gpr_data
.SetData(std::make_shared
<DataBufferHeap
>(gpregset
.GetDataStart(),
71 gpregset
.GetByteSize()));
72 m_gpr_data
.SetByteOrder(gpregset
.GetByteOrder());
74 const llvm::Triple
&target_triple
=
75 m_register_info_up
->GetTargetArchitecture().GetTriple();
76 m_fpr_data
= getRegset(notes
, target_triple
, FPR_Desc
);
78 if (m_register_info_up
->IsSSVEPresent()) {
79 m_sve_data
= getRegset(notes
, target_triple
, AARCH64_SSVE_Desc
);
80 lldb::offset_t flags_offset
= 12;
81 uint16_t flags
= m_sve_data
.GetU32(&flags_offset
);
82 if ((flags
& sve::ptrace_regs_mask
) == sve::ptrace_regs_sve
)
83 m_sve_state
= SVEState::Streaming
;
86 if (m_sve_state
!= SVEState::Streaming
&& m_register_info_up
->IsSVEPresent())
87 m_sve_data
= getRegset(notes
, target_triple
, AARCH64_SVE_Desc
);
89 if (m_register_info_up
->IsPAuthPresent())
90 m_pac_data
= getRegset(notes
, target_triple
, AARCH64_PAC_Desc
);
92 if (m_register_info_up
->IsTLSPresent())
93 m_tls_data
= getRegset(notes
, target_triple
, AARCH64_TLS_Desc
);
95 if (m_register_info_up
->IsZAPresent())
96 m_za_data
= getRegset(notes
, target_triple
, AARCH64_ZA_Desc
);
98 if (m_register_info_up
->IsMTEPresent())
99 m_mte_data
= getRegset(notes
, target_triple
, AARCH64_MTE_Desc
);
101 ConfigureRegisterContext();
104 RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() = default;
106 bool RegisterContextCorePOSIX_arm64::ReadGPR() { return true; }
108 bool RegisterContextCorePOSIX_arm64::ReadFPR() { return false; }
110 bool RegisterContextCorePOSIX_arm64::WriteGPR() {
115 bool RegisterContextCorePOSIX_arm64::WriteFPR() {
120 const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset
) {
121 return m_sve_data
.GetDataStart() + offset
;
124 void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() {
125 if (m_sve_data
.GetByteSize() > sizeof(sve::user_sve_header
)) {
126 uint64_t sve_header_field_offset
= 8;
127 m_sve_vector_length
= m_sve_data
.GetU16(&sve_header_field_offset
);
129 if (m_sve_state
!= SVEState::Streaming
) {
130 sve_header_field_offset
= 12;
131 uint16_t sve_header_flags_field
=
132 m_sve_data
.GetU16(&sve_header_field_offset
);
133 if ((sve_header_flags_field
& sve::ptrace_regs_mask
) ==
134 sve::ptrace_regs_fpsimd
)
135 m_sve_state
= SVEState::FPSIMD
;
136 else if ((sve_header_flags_field
& sve::ptrace_regs_mask
) ==
137 sve::ptrace_regs_sve
)
138 m_sve_state
= SVEState::Full
;
141 if (!sve::vl_valid(m_sve_vector_length
)) {
142 m_sve_state
= SVEState::Disabled
;
143 m_sve_vector_length
= 0;
146 m_sve_state
= SVEState::Disabled
;
148 if (m_sve_state
!= SVEState::Disabled
)
149 m_register_info_up
->ConfigureVectorLengthSVE(
150 sve::vq_from_vl(m_sve_vector_length
));
152 if (m_sve_state
== SVEState::Streaming
)
153 m_sme_pseudo_regs
.ctrl_reg
|= 1;
155 if (m_za_data
.GetByteSize() >= sizeof(sve::user_za_header
)) {
156 lldb::offset_t vlen_offset
= 8;
157 uint16_t svl
= m_za_data
.GetU16(&vlen_offset
);
158 m_sme_pseudo_regs
.svg_reg
= svl
/ 8;
159 m_register_info_up
->ConfigureVectorLengthZA(svl
/ 16);
161 // If there is register data then ZA is active. The size of the note may be
162 // misleading here so we use the size field of the embedded header.
163 lldb::offset_t size_offset
= 0;
164 uint32_t size
= m_za_data
.GetU32(&size_offset
);
165 if (size
> sizeof(sve::user_za_header
))
166 m_sme_pseudo_regs
.ctrl_reg
|= 1 << 1;
170 uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset(
171 const RegisterInfo
*reg_info
) {
172 // Start of Z0 data is after GPRs plus 8 bytes of vg register
173 uint32_t sve_reg_offset
= LLDB_INVALID_INDEX32
;
174 if (m_sve_state
== SVEState::FPSIMD
) {
175 const uint32_t reg
= reg_info
->kinds
[lldb::eRegisterKindLLDB
];
176 sve_reg_offset
= sve::ptrace_fpsimd_offset
+ (reg
- GetRegNumSVEZ0()) * 16;
177 } else if (m_sve_state
== SVEState::Full
||
178 m_sve_state
== SVEState::Streaming
) {
179 uint32_t sve_z0_offset
= GetGPRSize() + 16;
181 sve::SigRegsOffset() + reg_info
->byte_offset
- sve_z0_offset
;
184 return sve_reg_offset
;
187 bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo
*reg_info
,
188 RegisterValue
&value
) {
190 lldb::offset_t offset
;
192 offset
= reg_info
->byte_offset
;
193 if (offset
+ reg_info
->byte_size
<= GetGPRSize()) {
194 value
.SetFromMemoryData(*reg_info
, m_gpr_data
.GetDataStart() + offset
,
195 reg_info
->byte_size
, lldb::eByteOrderLittle
, error
);
196 return error
.Success();
199 const uint32_t reg
= reg_info
->kinds
[lldb::eRegisterKindLLDB
];
200 if (reg
== LLDB_INVALID_REGNUM
)
204 if (m_sve_state
== SVEState::Disabled
) {
205 // SVE is disabled take legacy route for FPU register access
206 offset
-= GetGPRSize();
207 if (offset
< m_fpr_data
.GetByteSize()) {
208 value
.SetFromMemoryData(*reg_info
, m_fpr_data
.GetDataStart() + offset
,
209 reg_info
->byte_size
, lldb::eByteOrderLittle
,
211 return error
.Success();
214 // FPSR and FPCR will be located right after Z registers in
215 // SVEState::FPSIMD while in SVEState::Full/SVEState::Streaming they will
216 // be located at the end of register data after an alignment correction
217 // based on currently selected vector length.
218 uint32_t sve_reg_num
= LLDB_INVALID_REGNUM
;
219 if (reg
== GetRegNumFPSR()) {
221 if (m_sve_state
== SVEState::Full
|| m_sve_state
== SVEState::Streaming
)
222 offset
= sve::PTraceFPSROffset(sve::vq_from_vl(m_sve_vector_length
));
223 else if (m_sve_state
== SVEState::FPSIMD
)
224 offset
= sve::ptrace_fpsimd_offset
+ (32 * 16);
225 } else if (reg
== GetRegNumFPCR()) {
227 if (m_sve_state
== SVEState::Full
|| m_sve_state
== SVEState::Streaming
)
228 offset
= sve::PTraceFPCROffset(sve::vq_from_vl(m_sve_vector_length
));
229 else if (m_sve_state
== SVEState::FPSIMD
)
230 offset
= sve::ptrace_fpsimd_offset
+ (32 * 16) + 4;
232 // Extract SVE Z register value register number for this reg_info
233 if (reg_info
->value_regs
&&
234 reg_info
->value_regs
[0] != LLDB_INVALID_REGNUM
)
235 sve_reg_num
= reg_info
->value_regs
[0];
236 offset
= CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num
));
239 assert(sve_reg_num
!= LLDB_INVALID_REGNUM
);
240 assert(offset
< m_sve_data
.GetByteSize());
241 value
.SetFromMemoryData(*reg_info
, GetSVEBuffer(offset
),
242 reg_info
->byte_size
, lldb::eByteOrderLittle
,
245 } else if (IsSVE(reg
)) {
247 value
= GetSVERegVG();
251 switch (m_sve_state
) {
252 case SVEState::FPSIMD
: {
253 // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just
254 // copy 16 bytes of v register to the start of z register. All other
255 // SVE register will be set to zero.
256 uint64_t byte_size
= 1;
258 const uint8_t *src
= &zeros
;
261 offset
= CalculateSVEOffset(reg_info
);
262 assert(offset
< m_sve_data
.GetByteSize());
263 src
= GetSVEBuffer(offset
);
265 value
.SetFromMemoryData(*reg_info
, src
, byte_size
, lldb::eByteOrderLittle
,
269 case SVEState::Streaming
:
270 offset
= CalculateSVEOffset(reg_info
);
271 assert(offset
< m_sve_data
.GetByteSize());
272 value
.SetFromMemoryData(*reg_info
, GetSVEBuffer(offset
),
273 reg_info
->byte_size
, lldb::eByteOrderLittle
,
276 case SVEState::Disabled
:
280 } else if (IsPAuth(reg
)) {
281 offset
= reg_info
->byte_offset
- m_register_info_up
->GetPAuthOffset();
282 assert(offset
< m_pac_data
.GetByteSize());
283 value
.SetFromMemoryData(*reg_info
, m_pac_data
.GetDataStart() + offset
,
284 reg_info
->byte_size
, lldb::eByteOrderLittle
, error
);
285 } else if (IsTLS(reg
)) {
286 offset
= reg_info
->byte_offset
- m_register_info_up
->GetTLSOffset();
287 assert(offset
< m_tls_data
.GetByteSize());
288 value
.SetFromMemoryData(*reg_info
, m_tls_data
.GetDataStart() + offset
,
289 reg_info
->byte_size
, lldb::eByteOrderLittle
, error
);
290 } else if (IsMTE(reg
)) {
291 offset
= reg_info
->byte_offset
- m_register_info_up
->GetMTEOffset();
292 assert(offset
< m_mte_data
.GetByteSize());
293 value
.SetFromMemoryData(*reg_info
, m_mte_data
.GetDataStart() + offset
,
294 reg_info
->byte_size
, lldb::eByteOrderLittle
, error
);
295 } else if (IsSME(reg
)) {
296 // If you had SME in the process, active or otherwise, there will at least
297 // be a ZA header. No header, no SME at all.
298 if (m_za_data
.GetByteSize() < sizeof(sve::user_za_header
))
302 offset
= reg_info
->byte_offset
- m_register_info_up
->GetSMEOffset();
303 assert(offset
< sizeof(m_sme_pseudo_regs
));
304 // Host endian since these values are derived instead of being read from a
306 value
.SetFromMemoryData(
307 *reg_info
, reinterpret_cast<uint8_t *>(&m_sme_pseudo_regs
) + offset
,
308 reg_info
->byte_size
, lldb_private::endian::InlHostByteOrder(), error
);
310 // If the process did not have the SME extension.
311 if (m_za_data
.GetByteSize() < sizeof(sve::user_za_header
))
314 // Don't use the size of the note to tell whether ZA is enabled. There may
315 // be non-register padding data after the header. Use the embedded
316 // header's size field instead.
317 lldb::offset_t size_offset
= 0;
318 uint32_t size
= m_za_data
.GetU32(&size_offset
);
319 bool za_enabled
= size
> sizeof(sve::user_za_header
);
321 size_t za_note_size
= m_za_data
.GetByteSize();
322 // For a disabled ZA we fake a value of all 0s.
324 uint64_t svl
= m_sme_pseudo_regs
.svg_reg
* 8;
325 za_note_size
= sizeof(sve::user_za_header
) + (svl
* svl
);
328 const uint8_t *src
= nullptr;
329 std::vector
<uint8_t> disabled_za_data
;
332 src
= m_za_data
.GetDataStart();
334 disabled_za_data
.resize(za_note_size
);
335 std::fill(disabled_za_data
.begin(), disabled_za_data
.end(), 0);
336 src
= disabled_za_data
.data();
339 value
.SetFromMemoryData(*reg_info
, src
+ sizeof(sve::user_za_header
),
340 reg_info
->byte_size
, lldb::eByteOrderLittle
,
346 return error
.Success();
349 bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues(
350 lldb::WritableDataBufferSP
&data_sp
) {
354 bool RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo
*reg_info
,
355 const RegisterValue
&value
) {
359 bool RegisterContextCorePOSIX_arm64::WriteAllRegisterValues(
360 const lldb::DataBufferSP
&data_sp
) {
364 bool RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable
) {