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/elf-core/RegisterUtilities.h"
13 #include "lldb/Target/Thread.h"
14 #include "lldb/Utility/RegisterValue.h"
15 
16 #include <memory>
17 
18 using namespace lldb_private;
19 
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;
25 
26   DataExtractor sve_data = getRegset(notes, arch.GetTriple(), AARCH64_SVE_Desc);
27   if (sve_data.GetByteSize() > sizeof(sve::user_sve_header))
28     opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE);
29 
30   // Pointer Authentication register set data is based on struct
31   // user_pac_mask declared in ptrace.h. See reference implementation
32   // in Linux kernel source at arch/arm64/include/uapi/asm/ptrace.h.
33   DataExtractor pac_data = getRegset(notes, arch.GetTriple(), AARCH64_PAC_Desc);
34   if (pac_data.GetByteSize() >= sizeof(uint64_t) * 2)
35     opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskPAuth);
36 
37   auto register_info_up =
38       std::make_unique<RegisterInfoPOSIX_arm64>(arch, opt_regsets);
39   return std::unique_ptr<RegisterContextCorePOSIX_arm64>(
40       new RegisterContextCorePOSIX_arm64(thread, std::move(register_info_up),
41                                          gpregset, notes));
42 }
43 
44 RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64(
45     Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info,
46     const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes)
47     : RegisterContextPOSIX_arm64(thread, std::move(register_info)) {
48   m_gpr_data.SetData(std::make_shared<DataBufferHeap>(gpregset.GetDataStart(),
49                                                       gpregset.GetByteSize()));
50   m_gpr_data.SetByteOrder(gpregset.GetByteOrder());
51 
52   const llvm::Triple &target_triple =
53       m_register_info_up->GetTargetArchitecture().GetTriple();
54   m_fpr_data = getRegset(notes, target_triple, FPR_Desc);
55 
56   if (m_register_info_up->IsSVEEnabled())
57     m_sve_data = getRegset(notes, target_triple, AARCH64_SVE_Desc);
58 
59   if (m_register_info_up->IsPAuthEnabled())
60     m_pac_data = getRegset(notes, target_triple, AARCH64_PAC_Desc);
61 
62   ConfigureRegisterContext();
63 }
64 
65 RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() = default;
66 
67 bool RegisterContextCorePOSIX_arm64::ReadGPR() { return true; }
68 
69 bool RegisterContextCorePOSIX_arm64::ReadFPR() { return false; }
70 
71 bool RegisterContextCorePOSIX_arm64::WriteGPR() {
72   assert(0);
73   return false;
74 }
75 
76 bool RegisterContextCorePOSIX_arm64::WriteFPR() {
77   assert(0);
78   return false;
79 }
80 
81 const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) {
82   return m_sve_data.GetDataStart() + offset;
83 }
84 
85 void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() {
86   if (m_sve_data.GetByteSize() > sizeof(sve::user_sve_header)) {
87     uint64_t sve_header_field_offset = 8;
88     m_sve_vector_length = m_sve_data.GetU16(&sve_header_field_offset);
89     sve_header_field_offset = 12;
90     uint16_t sve_header_flags_field =
91         m_sve_data.GetU16(&sve_header_field_offset);
92     if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
93         sve::ptrace_regs_fpsimd)
94       m_sve_state = SVEState::FPSIMD;
95     else if ((sve_header_flags_field & sve::ptrace_regs_mask) ==
96              sve::ptrace_regs_sve)
97       m_sve_state = SVEState::Full;
98 
99     if (!sve::vl_valid(m_sve_vector_length)) {
100       m_sve_state = SVEState::Disabled;
101       m_sve_vector_length = 0;
102     }
103   } else
104     m_sve_state = SVEState::Disabled;
105 
106   if (m_sve_state != SVEState::Disabled)
107     m_register_info_up->ConfigureVectorLength(
108         sve::vq_from_vl(m_sve_vector_length));
109 }
110 
111 uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset(
112     const RegisterInfo *reg_info) {
113   // Start of Z0 data is after GPRs plus 8 bytes of vg register
114   uint32_t sve_reg_offset = LLDB_INVALID_INDEX32;
115   if (m_sve_state == SVEState::FPSIMD) {
116     const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
117     sve_reg_offset = sve::ptrace_fpsimd_offset + (reg - GetRegNumSVEZ0()) * 16;
118   } else if (m_sve_state == SVEState::Full) {
119     uint32_t sve_z0_offset = GetGPRSize() + 16;
120     sve_reg_offset =
121         sve::SigRegsOffset() + reg_info->byte_offset - sve_z0_offset;
122   }
123 
124   return sve_reg_offset;
125 }
126 
127 bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info,
128                                                   RegisterValue &value) {
129   Status error;
130   lldb::offset_t offset;
131 
132   offset = reg_info->byte_offset;
133   if (offset + reg_info->byte_size <= GetGPRSize()) {
134     uint64_t v = m_gpr_data.GetMaxU64(&offset, reg_info->byte_size);
135     if (offset == reg_info->byte_offset + reg_info->byte_size) {
136       value = v;
137       return true;
138     }
139   }
140 
141   const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB];
142   if (reg == LLDB_INVALID_REGNUM)
143     return false;
144 
145   if (IsFPR(reg)) {
146     if (m_sve_state == SVEState::Disabled) {
147       // SVE is disabled take legacy route for FPU register access
148       offset -= GetGPRSize();
149       if (offset < m_fpr_data.GetByteSize()) {
150         value.SetFromMemoryData(*reg_info, m_fpr_data.GetDataStart() + offset,
151                                 reg_info->byte_size, lldb::eByteOrderLittle,
152                                 error);
153         return error.Success();
154       }
155     } else {
156       // FPSR and FPCR will be located right after Z registers in
157       // SVEState::FPSIMD while in SVEState::Full they will be located at the
158       // end of register data after an alignment correction based on currently
159       // selected vector length.
160       uint32_t sve_reg_num = LLDB_INVALID_REGNUM;
161       if (reg == GetRegNumFPSR()) {
162         sve_reg_num = reg;
163         if (m_sve_state == SVEState::Full)
164           offset = sve::PTraceFPSROffset(sve::vq_from_vl(m_sve_vector_length));
165         else if (m_sve_state == SVEState::FPSIMD)
166           offset = sve::ptrace_fpsimd_offset + (32 * 16);
167       } else if (reg == GetRegNumFPCR()) {
168         sve_reg_num = reg;
169         if (m_sve_state == SVEState::Full)
170           offset = sve::PTraceFPCROffset(sve::vq_from_vl(m_sve_vector_length));
171         else if (m_sve_state == SVEState::FPSIMD)
172           offset = sve::ptrace_fpsimd_offset + (32 * 16) + 4;
173       } else {
174         // Extract SVE Z register value register number for this reg_info
175         if (reg_info->value_regs &&
176             reg_info->value_regs[0] != LLDB_INVALID_REGNUM)
177           sve_reg_num = reg_info->value_regs[0];
178         offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num));
179       }
180 
181       assert(sve_reg_num != LLDB_INVALID_REGNUM);
182       assert(offset < m_sve_data.GetByteSize());
183       value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset),
184                               reg_info->byte_size, lldb::eByteOrderLittle,
185                               error);
186     }
187   } else if (IsSVE(reg)) {
188     if (IsSVEVG(reg)) {
189       value = GetSVERegVG();
190       return true;
191     }
192 
193     switch (m_sve_state) {
194     case SVEState::FPSIMD: {
195       // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just
196       // copy 16 bytes of v register to the start of z register. All other
197       // SVE register will be set to zero.
198       uint64_t byte_size = 1;
199       uint8_t zeros = 0;
200       const uint8_t *src = &zeros;
201       if (IsSVEZ(reg)) {
202         byte_size = 16;
203         offset = CalculateSVEOffset(reg_info);
204         assert(offset < m_sve_data.GetByteSize());
205         src = GetSVEBuffer(offset);
206       }
207       value.SetFromMemoryData(*reg_info, src, byte_size, lldb::eByteOrderLittle,
208                               error);
209     } break;
210     case SVEState::Full:
211       offset = CalculateSVEOffset(reg_info);
212       assert(offset < m_sve_data.GetByteSize());
213       value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset),
214                               reg_info->byte_size, lldb::eByteOrderLittle,
215                               error);
216       break;
217     case SVEState::Disabled:
218     default:
219       return false;
220     }
221   } else if (IsPAuth(reg)) {
222     offset = reg_info->byte_offset - m_register_info_up->GetPAuthOffset();
223     assert(offset < m_pac_data.GetByteSize());
224     value.SetFromMemoryData(*reg_info, m_pac_data.GetDataStart() + offset,
225                             reg_info->byte_size, lldb::eByteOrderLittle, error);
226   } else
227     return false;
228 
229   return error.Success();
230 }
231 
232 bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues(
233     lldb::WritableDataBufferSP &data_sp) {
234   return false;
235 }
236 
237 bool RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo *reg_info,
238                                                    const RegisterValue &value) {
239   return false;
240 }
241 
242 bool RegisterContextCorePOSIX_arm64::WriteAllRegisterValues(
243     const lldb::DataBufferSP &data_sp) {
244   return false;
245 }
246 
247 bool RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable) {
248   return false;
249 }
250