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