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