xref: /llvm-project/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp (revision 75aa5a35568b9e0b3eabd1e7f991a6a0f5525e0c)
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 
9 #include "RegisterContextPOSIXCore_arm64.h"
10 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h"
11 
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"
18 
19 #include <memory>
20 
21 using namespace lldb_private;
22 
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;
28 
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);
33 
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);
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)
43     opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskPAuth);
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))
49     opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskTLS);
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))
54     opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskZA);
55 
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);
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)
65     opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskZT);
66 
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);
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))
79     opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskGCS);
80 
81   auto register_info_up =
82       std::make_unique<RegisterInfoPOSIX_arm64>(arch, opt_regsets);
83   return std::unique_ptr<RegisterContextCorePOSIX_arm64>(
84       new RegisterContextCorePOSIX_arm64(thread, std::move(register_info_up),
85                                          gpregset, notes));
86 }
87 
88 RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
89     Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info,
90     const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
91     : RegisterContextPOSIX_arm64(thread, std::move(register_info)) {
92   ::memset(&m_sme_pseudo_regs, 0, sizeof(m_sme_pseudo_regs));
93 
94   ProcessElfCore *process =
95       static_cast<ProcessElfCore *>(thread.GetProcess().get());
96   llvm::Triple::OSType os = process->GetArchitecture().GetTriple().getOS();
97   if ((os == llvm::Triple::Linux) || (os == llvm::Triple::FreeBSD)) {
98     AuxVector aux_vec(process->GetAuxvData());
99     std::optional<uint64_t> auxv_at_hwcap = aux_vec.GetAuxValue(
100         os == llvm::Triple::FreeBSD ? AuxVector::AUXV_FREEBSD_AT_HWCAP
101                                     : AuxVector::AUXV_AT_HWCAP);
102     std::optional<uint64_t> auxv_at_hwcap2 =
103         aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP2);
104 
105     m_register_flags_detector.DetectFields(auxv_at_hwcap.value_or(0),
106                                            auxv_at_hwcap2.value_or(0));
107     m_register_flags_detector.UpdateRegisterInfo(GetRegisterInfo(),
108                                                  GetRegisterCount());
109   }
110 
111   m_gpr_data.SetData(std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
112                                                       gpregset.GetByteSize()));
113   m_gpr_data.SetByteOrder(gpregset.GetByteOrder());
114 
115   const llvm::Triple &target_triple =
116       m_register_info_up->GetTargetArchitecture().GetTriple();
117   m_fpr_data = getRegset(notes, target_triple, FPR_Desc);
118 
119   if (m_register_info_up->IsSSVEPresent()) {
120     m_sve_data = getRegset(notes, target_triple, AARCH64_SSVE_Desc);
121     lldb::offset_t flags_offset = 12;
122     uint16_t flags = m_sve_data.GetU32(&flags_offset);
123     if ((flags & sve::ptrace_regs_mask) == sve::ptrace_regs_sve)
124       m_sve_state = SVEState::Streaming;
125   }
126 
127   if (m_sve_state != SVEState::Streaming && m_register_info_up->IsSVEPresent())
128     m_sve_data = getRegset(notes, target_triple, AARCH64_SVE_Desc);
129 
130   if (m_register_info_up->IsPAuthPresent())
131     m_pac_data = getRegset(notes, target_triple, AARCH64_PAC_Desc);
132 
133   if (m_register_info_up->IsTLSPresent())
134     m_tls_data = getRegset(notes, target_triple, AARCH64_TLS_Desc);
135 
136   if (m_register_info_up->IsZAPresent())
137     m_za_data = getRegset(notes, target_triple, AARCH64_ZA_Desc);
138 
139   if (m_register_info_up->IsMTEPresent())
140     m_mte_data = getRegset(notes, target_triple, AARCH64_MTE_Desc);
141 
142   if (m_register_info_up->IsZTPresent())
143     m_zt_data = getRegset(notes, target_triple, AARCH64_ZT_Desc);
144 
145   if (m_register_info_up->IsFPMRPresent())
146     m_fpmr_data = getRegset(notes, target_triple, AARCH64_FPMR_Desc);
147 
148   if (m_register_info_up->IsGCSPresent())
149     m_gcs_data = getRegset(notes, target_triple, AARCH64_GCS_Desc);
150 
151   ConfigureRegisterContext();
152 }
153 
154 RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() = default;
155 
156 bool RegisterContextCorePOSIX_arm64::ReadGPR() { return true; }
157 
158 bool RegisterContextCorePOSIX_arm64::ReadFPR() { return false; }
159 
160 bool RegisterContextCorePOSIX_arm64::WriteGPR() {
161   assert(0);
162   return false;
163 }
164 
165 bool RegisterContextCorePOSIX_arm64::WriteFPR() {
166   assert(0);
167   return false;
168 }
169 
170 const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) {
171   return m_sve_data.GetDataStart() + offset;
172 }
173 
174 void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() {
175   if (m_sve_data.GetByteSize() > sizeof(sve::user_sve_header)) {
176     uint64_t sve_header_field_offset = 8;
177     m_sve_vector_length = m_sve_data.GetU16(&sve_header_field_offset);
178 
179     if (m_sve_state != SVEState::Streaming) {
180       sve_header_field_offset = 12;
181       uint16_t sve_header_flags_field =
182           m_sve_data.GetU16(&sve_header_field_offset);
183       if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
184           sve::ptrace_regs_fpsimd)
185         m_sve_state = SVEState::FPSIMD;
186       else if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
187                sve::ptrace_regs_sve)
188         m_sve_state = SVEState::Full;
189     }
190 
191     if (!sve::vl_valid(m_sve_vector_length)) {
192       m_sve_state = SVEState::Disabled;
193       m_sve_vector_length = 0;
194     }
195   } else
196     m_sve_state = SVEState::Disabled;
197 
198   if (m_sve_state != SVEState::Disabled)
199     m_register_info_up->ConfigureVectorLengthSVE(
200         sve::vq_from_vl(m_sve_vector_length));
201 
202   if (m_sve_state == SVEState::Streaming)
203     m_sme_pseudo_regs.ctrl_reg |= 1;
204 
205   if (m_za_data.GetByteSize() >= sizeof(sve::user_za_header)) {
206     lldb::offset_t vlen_offset = 8;
207     uint16_t svl = m_za_data.GetU16(&vlen_offset);
208     m_sme_pseudo_regs.svg_reg = svl / 8;
209     m_register_info_up->ConfigureVectorLengthZA(svl / 16);
210 
211     // If there is register data then ZA is active. The size of the note may be
212     // misleading here so we use the size field of the embedded header.
213     lldb::offset_t size_offset = 0;
214     uint32_t size = m_za_data.GetU32(&size_offset);
215     if (size > sizeof(sve::user_za_header))
216       m_sme_pseudo_regs.ctrl_reg |= 1 << 1;
217   }
218 }
219 
220 uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset(
221     const RegisterInfo *reg_info) {
222   // Start of Z0 data is after GPRs plus 8 bytes of vg register
223   uint32_t sve_reg_offset = LLDB_INVALID_INDEX32;
224   if (m_sve_state == SVEState::FPSIMD) {
225     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
226     sve_reg_offset = sve::ptrace_fpsimd_offset + (reg - GetRegNumSVEZ0()) * 16;
227   } else if (m_sve_state == SVEState::Full ||
228              m_sve_state == SVEState::Streaming) {
229     uint32_t sve_z0_offset = GetGPRSize() + 16;
230     sve_reg_offset =
231         sve::SigRegsOffset() + reg_info->byte_offset - sve_z0_offset;
232   }
233 
234   return sve_reg_offset;
235 }
236 
237 bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info,
238                                                   RegisterValue &value) {
239   Status error;
240   lldb::offset_t offset;
241 
242   offset = reg_info->byte_offset;
243   if (offset + reg_info->byte_size <= GetGPRSize()) {
244     value.SetFromMemoryData(*reg_info, m_gpr_data.GetDataStart() + offset,
245                             reg_info->byte_size, lldb::eByteOrderLittle, error);
246     return error.Success();
247   }
248 
249   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
250   if (reg == LLDB_INVALID_REGNUM)
251     return false;
252 
253   if (IsFPR(reg)) {
254     if (m_sve_state == SVEState::Disabled) {
255       // SVE is disabled take legacy route for FPU register access
256       offset -= GetGPRSize();
257       if (offset < m_fpr_data.GetByteSize()) {
258         value.SetFromMemoryData(*reg_info, m_fpr_data.GetDataStart() + offset,
259                                 reg_info->byte_size, lldb::eByteOrderLittle,
260                                 error);
261         return error.Success();
262       }
263     } else {
264       // FPSR and FPCR will be located right after Z registers in
265       // SVEState::FPSIMD while in SVEState::Full/SVEState::Streaming they will
266       // be located at the end of register data after an alignment correction
267       // based on currently selected vector length.
268       uint32_t sve_reg_num = LLDB_INVALID_REGNUM;
269       if (reg == GetRegNumFPSR()) {
270         sve_reg_num = reg;
271         if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming)
272           offset = sve::PTraceFPSROffset(sve::vq_from_vl(m_sve_vector_length));
273         else if (m_sve_state == SVEState::FPSIMD)
274           offset = sve::ptrace_fpsimd_offset + (32 * 16);
275       } else if (reg == GetRegNumFPCR()) {
276         sve_reg_num = reg;
277         if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming)
278           offset = sve::PTraceFPCROffset(sve::vq_from_vl(m_sve_vector_length));
279         else if (m_sve_state == SVEState::FPSIMD)
280           offset = sve::ptrace_fpsimd_offset + (32 * 16) + 4;
281       } else {
282         // Extract SVE Z register value register number for this reg_info
283         if (reg_info->value_regs &&
284             reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
285           sve_reg_num = reg_info->value_regs[0];
286         offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num));
287       }
288 
289       assert(sve_reg_num != LLDB_INVALID_REGNUM);
290       assert(offset < m_sve_data.GetByteSize());
291       value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset),
292                               reg_info->byte_size, lldb::eByteOrderLittle,
293                               error);
294     }
295   } else if (IsSVE(reg)) {
296     if (IsSVEVG(reg)) {
297       value = GetSVERegVG();
298       return true;
299     }
300 
301     switch (m_sve_state) {
302     case SVEState::FPSIMD: {
303       // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just
304       // copy 16 bytes of v register to the start of z register. All other
305       // SVE register will be set to zero.
306       uint64_t byte_size = 1;
307       uint8_t zeros = 0;
308       const uint8_t *src = &zeros;
309       if (IsSVEZ(reg)) {
310         byte_size = 16;
311         offset = CalculateSVEOffset(reg_info);
312         assert(offset < m_sve_data.GetByteSize());
313         src = GetSVEBuffer(offset);
314       }
315       value.SetFromMemoryData(*reg_info, src, byte_size, lldb::eByteOrderLittle,
316                               error);
317     } break;
318     case SVEState::Full:
319     case SVEState::Streaming:
320       offset = CalculateSVEOffset(reg_info);
321       assert(offset < m_sve_data.GetByteSize());
322       value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset),
323                               reg_info->byte_size, lldb::eByteOrderLittle,
324                               error);
325       break;
326     case SVEState::Disabled:
327     default:
328       return false;
329     }
330   } else if (IsPAuth(reg)) {
331     offset = reg_info->byte_offset - m_register_info_up->GetPAuthOffset();
332     assert(offset < m_pac_data.GetByteSize());
333     value.SetFromMemoryData(*reg_info, m_pac_data.GetDataStart() + offset,
334                             reg_info->byte_size, lldb::eByteOrderLittle, error);
335   } else if (IsTLS(reg)) {
336     offset = reg_info->byte_offset - m_register_info_up->GetTLSOffset();
337     assert(offset < m_tls_data.GetByteSize());
338     value.SetFromMemoryData(*reg_info, m_tls_data.GetDataStart() + offset,
339                             reg_info->byte_size, lldb::eByteOrderLittle, error);
340   } else if (IsMTE(reg)) {
341     offset = reg_info->byte_offset - m_register_info_up->GetMTEOffset();
342     assert(offset < m_mte_data.GetByteSize());
343     value.SetFromMemoryData(*reg_info, m_mte_data.GetDataStart() + offset,
344                             reg_info->byte_size, lldb::eByteOrderLittle, error);
345   } else if (IsGCS(reg)) {
346     offset = reg_info->byte_offset - m_register_info_up->GetGCSOffset();
347     assert(offset < m_gcs_data.GetByteSize());
348     value.SetFromMemoryData(*reg_info, m_gcs_data.GetDataStart() + offset,
349                             reg_info->byte_size, lldb::eByteOrderLittle, error);
350   } else if (IsSME(reg)) {
351     // If you had SME in the process, active or otherwise, there will at least
352     // be a ZA header. No header, no SME at all.
353     if (m_za_data.GetByteSize() < sizeof(sve::user_za_header))
354       return false;
355 
356     if (m_register_info_up->IsSMERegZA(reg)) {
357       // Don't use the size of the note to tell whether ZA is enabled. There may
358       // be non-register padding data after the header. Use the embedded
359       // header's size field instead.
360       lldb::offset_t size_offset = 0;
361       uint32_t size = m_za_data.GetU32(&size_offset);
362       bool za_enabled = size > sizeof(sve::user_za_header);
363 
364       size_t za_note_size = m_za_data.GetByteSize();
365       // For a disabled ZA we fake a value of all 0s.
366       if (!za_enabled) {
367         uint64_t svl = m_sme_pseudo_regs.svg_reg * 8;
368         za_note_size = sizeof(sve::user_za_header) + (svl * svl);
369       }
370 
371       const uint8_t *src = nullptr;
372       std::vector<uint8_t> disabled_za_data;
373 
374       if (za_enabled)
375         src = m_za_data.GetDataStart();
376       else {
377         disabled_za_data.resize(za_note_size);
378         std::fill(disabled_za_data.begin(), disabled_za_data.end(), 0);
379         src = disabled_za_data.data();
380       }
381 
382       value.SetFromMemoryData(*reg_info, src + sizeof(sve::user_za_header),
383                               reg_info->byte_size, lldb::eByteOrderLittle,
384                               error);
385     } else if (m_register_info_up->IsSMERegZT(reg)) {
386       value.SetFromMemoryData(*reg_info, m_zt_data.GetDataStart(),
387                               reg_info->byte_size, lldb::eByteOrderLittle,
388                               error);
389     } else {
390       offset = reg_info->byte_offset - m_register_info_up->GetSMEOffset();
391       assert(offset < sizeof(m_sme_pseudo_regs));
392       // Host endian since these values are derived instead of being read from a
393       // core file note.
394       value.SetFromMemoryData(
395           *reg_info, reinterpret_cast<uint8_t *>(&m_sme_pseudo_regs) + offset,
396           reg_info->byte_size, lldb_private::endian::InlHostByteOrder(), error);
397     }
398   } else if (IsFPMR(reg)) {
399     offset = reg_info->byte_offset - m_register_info_up->GetFPMROffset();
400     assert(offset < m_fpmr_data.GetByteSize());
401     value.SetFromMemoryData(*reg_info, m_fpmr_data.GetDataStart() + offset,
402                             reg_info->byte_size, lldb::eByteOrderLittle, error);
403   } else
404     return false;
405 
406   return error.Success();
407 }
408 
409 bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues(
410     lldb::WritableDataBufferSP &data_sp) {
411   return false;
412 }
413 
414 bool RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo *reg_info,
415                                                    const RegisterValue &value) {
416   return false;
417 }
418 
419 bool RegisterContextCorePOSIX_arm64::WriteAllRegisterValues(
420     const lldb::DataBufferSP &data_sp) {
421   return false;
422 }
423 
424 bool RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable) {
425   return false;
426 }
427