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