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>
Create(Thread & thread,const ArchSpec & arch,const DataExtractor & gpregset,llvm::ArrayRef<CoreNote> notes)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
RegisterContextCorePOSIX_arm64(Thread & thread,std::unique_ptr<RegisterInfoPOSIX_arm64> register_info,const DataExtractor & gpregset,llvm::ArrayRef<CoreNote> notes)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
ReadGPR()67 bool RegisterContextCorePOSIX_arm64::ReadGPR() { return true; }
68
ReadFPR()69 bool RegisterContextCorePOSIX_arm64::ReadFPR() { return false; }
70
WriteGPR()71 bool RegisterContextCorePOSIX_arm64::WriteGPR() {
72 assert(0);
73 return false;
74 }
75
WriteFPR()76 bool RegisterContextCorePOSIX_arm64::WriteFPR() {
77 assert(0);
78 return false;
79 }
80
GetSVEBuffer(uint64_t offset)81 const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) {
82 return m_sve_data.GetDataStart() + offset;
83 }
84
ConfigureRegisterContext()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
CalculateSVEOffset(const RegisterInfo * reg_info)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
ReadRegister(const RegisterInfo * reg_info,RegisterValue & value)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
ReadAllRegisterValues(lldb::DataBufferSP & data_sp)232 bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues(
233 lldb::DataBufferSP &data_sp) {
234 return false;
235 }
236
WriteRegister(const RegisterInfo * reg_info,const RegisterValue & value)237 bool RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo *reg_info,
238 const RegisterValue &value) {
239 return false;
240 }
241
WriteAllRegisterValues(const lldb::DataBufferSP & data_sp)242 bool RegisterContextCorePOSIX_arm64::WriteAllRegisterValues(
243 const lldb::DataBufferSP &data_sp) {
244 return false;
245 }
246
HardwareSingleStep(bool enable)247 bool RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable) {
248 return false;
249 }
250