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
21using namespace lldb_private;
22
23std::unique_ptr<RegisterContextCorePOSIX_arm64>
24RegisterContextCorePOSIX_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
74RegisterContextCorePOSIX_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
132RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() = default;
133
134bool RegisterContextCorePOSIX_arm64::ReadGPR() { return true; }
135
136bool RegisterContextCorePOSIX_arm64::ReadFPR() { return false; }
137
138bool RegisterContextCorePOSIX_arm64::WriteGPR() {
139  assert(0);
140  return false;
141}
142
143bool RegisterContextCorePOSIX_arm64::WriteFPR() {
144  assert(0);
145  return false;
146}
147
148const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) {
149  return m_sve_data.GetDataStart() + offset;
150}
151
152void 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
198uint32_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
215bool 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
377bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues(
378    lldb::WritableDataBufferSP &data_sp) {
379  return false;
380}
381
382bool RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo *reg_info,
383                                                   const RegisterValue &value) {
384  return false;
385}
386
387bool RegisterContextCorePOSIX_arm64::WriteAllRegisterValues(
388    const lldb::DataBufferSP &data_sp) {
389  return false;
390}
391
392bool RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable) {
393  return false;
394}
395