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