Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lldb / source / Plugins / Process / elf-core / RegisterContextPOSIXCore_arm64.cpp
blobdb37b7cbb99d7e84872fa696909bf89fb272741d
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 //===----------------------------------------------------------------------===//
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"
16 #include <memory>
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
44 // expand in future.
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),
61 gpregset, notes));
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() {
111 assert(0);
112 return false;
115 bool RegisterContextCorePOSIX_arm64::WriteFPR() {
116 assert(0);
117 return false;
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;
145 } else
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;
180 sve_reg_offset =
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) {
189 Status error;
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)
201 return false;
203 if (IsFPR(reg)) {
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,
210 error);
211 return error.Success();
213 } else {
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()) {
220 sve_reg_num = reg;
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()) {
226 sve_reg_num = reg;
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;
231 } else {
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,
243 error);
245 } else if (IsSVE(reg)) {
246 if (IsSVEVG(reg)) {
247 value = GetSVERegVG();
248 return true;
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;
257 uint8_t zeros = 0;
258 const uint8_t *src = &zeros;
259 if (IsSVEZ(reg)) {
260 byte_size = 16;
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,
266 error);
267 } break;
268 case SVEState::Full:
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,
274 error);
275 break;
276 case SVEState::Disabled:
277 default:
278 return false;
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))
299 return false;
301 if (!IsSMEZA(reg)) {
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
305 // core file note.
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);
309 } else {
310 // If the process did not have the SME extension.
311 if (m_za_data.GetByteSize() < sizeof(sve::user_za_header))
312 return false;
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.
323 if (!za_enabled) {
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;
331 if (za_enabled)
332 src = m_za_data.GetDataStart();
333 else {
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,
341 error);
343 } else
344 return false;
346 return error.Success();
349 bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues(
350 lldb::WritableDataBufferSP &data_sp) {
351 return false;
354 bool RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo *reg_info,
355 const RegisterValue &value) {
356 return false;
359 bool RegisterContextCorePOSIX_arm64::WriteAllRegisterValues(
360 const lldb::DataBufferSP &data_sp) {
361 return false;
364 bool RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable) {
365 return false;