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