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