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/Utility/AuxVector.h" 13 #include "Plugins/Process/Utility/RegisterFlagsLinux_arm64.h" 14 #include "Plugins/Process/elf-core/ProcessElfCore.h" 15 #include "Plugins/Process/elf-core/RegisterUtilities.h" 16 #include "lldb/Target/Thread.h" 17 #include "lldb/Utility/RegisterValue.h" 18 19 #include <memory> 20 21 using namespace lldb_private; 22 23 std::unique_ptr<RegisterContextCorePOSIX_arm64> 24 RegisterContextCorePOSIX_arm64::Create(Thread &thread, const ArchSpec &arch, 25 const DataExtractor &gpregset, 26 llvm::ArrayRef<CoreNote> notes) { 27 Flags opt_regsets = RegisterInfoPOSIX_arm64::eRegsetMaskDefault; 28 29 DataExtractor ssve_data = 30 getRegset(notes, arch.GetTriple(), AARCH64_SSVE_Desc); 31 if (ssve_data.GetByteSize() >= sizeof(sve::user_sve_header)) 32 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSSVE); 33 34 DataExtractor sve_data = getRegset(notes, arch.GetTriple(), AARCH64_SVE_Desc); 35 if (sve_data.GetByteSize() >= sizeof(sve::user_sve_header)) 36 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE); 37 38 // Pointer Authentication register set data is based on struct 39 // user_pac_mask declared in ptrace.h. See reference implementation 40 // in Linux kernel source at arch/arm64/include/uapi/asm/ptrace.h. 41 DataExtractor pac_data = getRegset(notes, arch.GetTriple(), AARCH64_PAC_Desc); 42 if (pac_data.GetByteSize() >= sizeof(uint64_t) * 2) 43 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskPAuth); 44 45 DataExtractor tls_data = getRegset(notes, arch.GetTriple(), AARCH64_TLS_Desc); 46 // A valid note will always contain at least one register, "tpidr". It may 47 // expand in future. 48 if (tls_data.GetByteSize() >= sizeof(uint64_t)) 49 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskTLS); 50 51 DataExtractor za_data = getRegset(notes, arch.GetTriple(), AARCH64_ZA_Desc); 52 // Nothing if ZA is not present, just the header if it is disabled. 53 if (za_data.GetByteSize() >= sizeof(sve::user_za_header)) 54 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskZA); 55 56 DataExtractor mte_data = getRegset(notes, arch.GetTriple(), AARCH64_MTE_Desc); 57 if (mte_data.GetByteSize() >= sizeof(uint64_t)) 58 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskMTE); 59 60 DataExtractor zt_data = getRegset(notes, arch.GetTriple(), AARCH64_ZT_Desc); 61 // Although ZT0 can be in a disabled state like ZA can, the kernel reports 62 // its content as 0s in that state. Therefore even a disabled ZT0 will have 63 // a note containing those 0s. ZT0 is a 512 bit / 64 byte register. 64 if (zt_data.GetByteSize() >= 64) 65 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskZT); 66 67 auto register_info_up = 68 std::make_unique<RegisterInfoPOSIX_arm64>(arch, opt_regsets); 69 return std::unique_ptr<RegisterContextCorePOSIX_arm64>( 70 new RegisterContextCorePOSIX_arm64(thread, std::move(register_info_up), 71 gpregset, notes)); 72 } 73 74 RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64( 75 Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info, 76 const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes) 77 : RegisterContextPOSIX_arm64(thread, std::move(register_info)) { 78 ::memset(&m_sme_pseudo_regs, 0, sizeof(m_sme_pseudo_regs)); 79 80 ProcessElfCore *process = 81 static_cast<ProcessElfCore *>(thread.GetProcess().get()); 82 if (process->GetArchitecture().GetTriple().getOS() == llvm::Triple::Linux) { 83 AuxVector aux_vec(process->GetAuxvData()); 84 std::optional<uint64_t> auxv_at_hwcap = 85 aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP); 86 std::optional<uint64_t> auxv_at_hwcap2 = 87 aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP2); 88 89 m_linux_register_flags.DetectFields(auxv_at_hwcap.value_or(0), 90 auxv_at_hwcap2.value_or(0)); 91 m_linux_register_flags.UpdateRegisterInfo(GetRegisterInfo(), 92 GetRegisterCount()); 93 } 94 95 m_gpr_data.SetData(std::make_shared<DataBufferHeap>(gpregset.GetDataStart(), 96 gpregset.GetByteSize())); 97 m_gpr_data.SetByteOrder(gpregset.GetByteOrder()); 98 99 const llvm::Triple &target_triple = 100 m_register_info_up->GetTargetArchitecture().GetTriple(); 101 m_fpr_data = getRegset(notes, target_triple, FPR_Desc); 102 103 if (m_register_info_up->IsSSVEPresent()) { 104 m_sve_data = getRegset(notes, target_triple, AARCH64_SSVE_Desc); 105 lldb::offset_t flags_offset = 12; 106 uint16_t flags = m_sve_data.GetU32(&flags_offset); 107 if ((flags & sve::ptrace_regs_mask) == sve::ptrace_regs_sve) 108 m_sve_state = SVEState::Streaming; 109 } 110 111 if (m_sve_state != SVEState::Streaming && m_register_info_up->IsSVEPresent()) 112 m_sve_data = getRegset(notes, target_triple, AARCH64_SVE_Desc); 113 114 if (m_register_info_up->IsPAuthPresent()) 115 m_pac_data = getRegset(notes, target_triple, AARCH64_PAC_Desc); 116 117 if (m_register_info_up->IsTLSPresent()) 118 m_tls_data = getRegset(notes, target_triple, AARCH64_TLS_Desc); 119 120 if (m_register_info_up->IsZAPresent()) 121 m_za_data = getRegset(notes, target_triple, AARCH64_ZA_Desc); 122 123 if (m_register_info_up->IsMTEPresent()) 124 m_mte_data = getRegset(notes, target_triple, AARCH64_MTE_Desc); 125 126 if (m_register_info_up->IsZTPresent()) 127 m_zt_data = getRegset(notes, target_triple, AARCH64_ZT_Desc); 128 129 ConfigureRegisterContext(); 130 } 131 132 RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() = default; 133 134 bool RegisterContextCorePOSIX_arm64::ReadGPR() { return true; } 135 136 bool RegisterContextCorePOSIX_arm64::ReadFPR() { return false; } 137 138 bool RegisterContextCorePOSIX_arm64::WriteGPR() { 139 assert(0); 140 return false; 141 } 142 143 bool RegisterContextCorePOSIX_arm64::WriteFPR() { 144 assert(0); 145 return false; 146 } 147 148 const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) { 149 return m_sve_data.GetDataStart() + offset; 150 } 151 152 void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() { 153 if (m_sve_data.GetByteSize() > sizeof(sve::user_sve_header)) { 154 uint64_t sve_header_field_offset = 8; 155 m_sve_vector_length = m_sve_data.GetU16(&sve_header_field_offset); 156 157 if (m_sve_state != SVEState::Streaming) { 158 sve_header_field_offset = 12; 159 uint16_t sve_header_flags_field = 160 m_sve_data.GetU16(&sve_header_field_offset); 161 if ((sve_header_flags_field & sve::ptrace_regs_mask) == 162 sve::ptrace_regs_fpsimd) 163 m_sve_state = SVEState::FPSIMD; 164 else if ((sve_header_flags_field & sve::ptrace_regs_mask) == 165 sve::ptrace_regs_sve) 166 m_sve_state = SVEState::Full; 167 } 168 169 if (!sve::vl_valid(m_sve_vector_length)) { 170 m_sve_state = SVEState::Disabled; 171 m_sve_vector_length = 0; 172 } 173 } else 174 m_sve_state = SVEState::Disabled; 175 176 if (m_sve_state != SVEState::Disabled) 177 m_register_info_up->ConfigureVectorLengthSVE( 178 sve::vq_from_vl(m_sve_vector_length)); 179 180 if (m_sve_state == SVEState::Streaming) 181 m_sme_pseudo_regs.ctrl_reg |= 1; 182 183 if (m_za_data.GetByteSize() >= sizeof(sve::user_za_header)) { 184 lldb::offset_t vlen_offset = 8; 185 uint16_t svl = m_za_data.GetU16(&vlen_offset); 186 m_sme_pseudo_regs.svg_reg = svl / 8; 187 m_register_info_up->ConfigureVectorLengthZA(svl / 16); 188 189 // If there is register data then ZA is active. The size of the note may be 190 // misleading here so we use the size field of the embedded header. 191 lldb::offset_t size_offset = 0; 192 uint32_t size = m_za_data.GetU32(&size_offset); 193 if (size > sizeof(sve::user_za_header)) 194 m_sme_pseudo_regs.ctrl_reg |= 1 << 1; 195 } 196 } 197 198 uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset( 199 const RegisterInfo *reg_info) { 200 // Start of Z0 data is after GPRs plus 8 bytes of vg register 201 uint32_t sve_reg_offset = LLDB_INVALID_INDEX32; 202 if (m_sve_state == SVEState::FPSIMD) { 203 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 204 sve_reg_offset = sve::ptrace_fpsimd_offset + (reg - GetRegNumSVEZ0()) * 16; 205 } else if (m_sve_state == SVEState::Full || 206 m_sve_state == SVEState::Streaming) { 207 uint32_t sve_z0_offset = GetGPRSize() + 16; 208 sve_reg_offset = 209 sve::SigRegsOffset() + reg_info->byte_offset - sve_z0_offset; 210 } 211 212 return sve_reg_offset; 213 } 214 215 bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, 216 RegisterValue &value) { 217 Status error; 218 lldb::offset_t offset; 219 220 offset = reg_info->byte_offset; 221 if (offset + reg_info->byte_size <= GetGPRSize()) { 222 value.SetFromMemoryData(*reg_info, m_gpr_data.GetDataStart() + offset, 223 reg_info->byte_size, lldb::eByteOrderLittle, error); 224 return error.Success(); 225 } 226 227 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 228 if (reg == LLDB_INVALID_REGNUM) 229 return false; 230 231 if (IsFPR(reg)) { 232 if (m_sve_state == SVEState::Disabled) { 233 // SVE is disabled take legacy route for FPU register access 234 offset -= GetGPRSize(); 235 if (offset < m_fpr_data.GetByteSize()) { 236 value.SetFromMemoryData(*reg_info, m_fpr_data.GetDataStart() + offset, 237 reg_info->byte_size, lldb::eByteOrderLittle, 238 error); 239 return error.Success(); 240 } 241 } else { 242 // FPSR and FPCR will be located right after Z registers in 243 // SVEState::FPSIMD while in SVEState::Full/SVEState::Streaming they will 244 // be located at the end of register data after an alignment correction 245 // based on currently selected vector length. 246 uint32_t sve_reg_num = LLDB_INVALID_REGNUM; 247 if (reg == GetRegNumFPSR()) { 248 sve_reg_num = reg; 249 if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming) 250 offset = sve::PTraceFPSROffset(sve::vq_from_vl(m_sve_vector_length)); 251 else if (m_sve_state == SVEState::FPSIMD) 252 offset = sve::ptrace_fpsimd_offset + (32 * 16); 253 } else if (reg == GetRegNumFPCR()) { 254 sve_reg_num = reg; 255 if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming) 256 offset = sve::PTraceFPCROffset(sve::vq_from_vl(m_sve_vector_length)); 257 else if (m_sve_state == SVEState::FPSIMD) 258 offset = sve::ptrace_fpsimd_offset + (32 * 16) + 4; 259 } else { 260 // Extract SVE Z register value register number for this reg_info 261 if (reg_info->value_regs && 262 reg_info->value_regs[0] != LLDB_INVALID_REGNUM) 263 sve_reg_num = reg_info->value_regs[0]; 264 offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num)); 265 } 266 267 assert(sve_reg_num != LLDB_INVALID_REGNUM); 268 assert(offset < m_sve_data.GetByteSize()); 269 value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset), 270 reg_info->byte_size, lldb::eByteOrderLittle, 271 error); 272 } 273 } else if (IsSVE(reg)) { 274 if (IsSVEVG(reg)) { 275 value = GetSVERegVG(); 276 return true; 277 } 278 279 switch (m_sve_state) { 280 case SVEState::FPSIMD: { 281 // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just 282 // copy 16 bytes of v register to the start of z register. All other 283 // SVE register will be set to zero. 284 uint64_t byte_size = 1; 285 uint8_t zeros = 0; 286 const uint8_t *src = &zeros; 287 if (IsSVEZ(reg)) { 288 byte_size = 16; 289 offset = CalculateSVEOffset(reg_info); 290 assert(offset < m_sve_data.GetByteSize()); 291 src = GetSVEBuffer(offset); 292 } 293 value.SetFromMemoryData(*reg_info, src, byte_size, lldb::eByteOrderLittle, 294 error); 295 } break; 296 case SVEState::Full: 297 case SVEState::Streaming: 298 offset = CalculateSVEOffset(reg_info); 299 assert(offset < m_sve_data.GetByteSize()); 300 value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset), 301 reg_info->byte_size, lldb::eByteOrderLittle, 302 error); 303 break; 304 case SVEState::Disabled: 305 default: 306 return false; 307 } 308 } else if (IsPAuth(reg)) { 309 offset = reg_info->byte_offset - m_register_info_up->GetPAuthOffset(); 310 assert(offset < m_pac_data.GetByteSize()); 311 value.SetFromMemoryData(*reg_info, m_pac_data.GetDataStart() + offset, 312 reg_info->byte_size, lldb::eByteOrderLittle, error); 313 } else if (IsTLS(reg)) { 314 offset = reg_info->byte_offset - m_register_info_up->GetTLSOffset(); 315 assert(offset < m_tls_data.GetByteSize()); 316 value.SetFromMemoryData(*reg_info, m_tls_data.GetDataStart() + offset, 317 reg_info->byte_size, lldb::eByteOrderLittle, error); 318 } else if (IsMTE(reg)) { 319 offset = reg_info->byte_offset - m_register_info_up->GetMTEOffset(); 320 assert(offset < m_mte_data.GetByteSize()); 321 value.SetFromMemoryData(*reg_info, m_mte_data.GetDataStart() + offset, 322 reg_info->byte_size, lldb::eByteOrderLittle, error); 323 } else if (IsSME(reg)) { 324 // If you had SME in the process, active or otherwise, there will at least 325 // be a ZA header. No header, no SME at all. 326 if (m_za_data.GetByteSize() < sizeof(sve::user_za_header)) 327 return false; 328 329 if (m_register_info_up->IsSMERegZA(reg)) { 330 // Don't use the size of the note to tell whether ZA is enabled. There may 331 // be non-register padding data after the header. Use the embedded 332 // header's size field instead. 333 lldb::offset_t size_offset = 0; 334 uint32_t size = m_za_data.GetU32(&size_offset); 335 bool za_enabled = size > sizeof(sve::user_za_header); 336 337 size_t za_note_size = m_za_data.GetByteSize(); 338 // For a disabled ZA we fake a value of all 0s. 339 if (!za_enabled) { 340 uint64_t svl = m_sme_pseudo_regs.svg_reg * 8; 341 za_note_size = sizeof(sve::user_za_header) + (svl * svl); 342 } 343 344 const uint8_t *src = nullptr; 345 std::vector<uint8_t> disabled_za_data; 346 347 if (za_enabled) 348 src = m_za_data.GetDataStart(); 349 else { 350 disabled_za_data.resize(za_note_size); 351 std::fill(disabled_za_data.begin(), disabled_za_data.end(), 0); 352 src = disabled_za_data.data(); 353 } 354 355 value.SetFromMemoryData(*reg_info, src + sizeof(sve::user_za_header), 356 reg_info->byte_size, lldb::eByteOrderLittle, 357 error); 358 } else if (m_register_info_up->IsSMERegZT(reg)) { 359 value.SetFromMemoryData(*reg_info, m_zt_data.GetDataStart(), 360 reg_info->byte_size, lldb::eByteOrderLittle, 361 error); 362 } else { 363 offset = reg_info->byte_offset - m_register_info_up->GetSMEOffset(); 364 assert(offset < sizeof(m_sme_pseudo_regs)); 365 // Host endian since these values are derived instead of being read from a 366 // core file note. 367 value.SetFromMemoryData( 368 *reg_info, reinterpret_cast<uint8_t *>(&m_sme_pseudo_regs) + offset, 369 reg_info->byte_size, lldb_private::endian::InlHostByteOrder(), error); 370 } 371 } else 372 return false; 373 374 return error.Success(); 375 } 376 377 bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues( 378 lldb::WritableDataBufferSP &data_sp) { 379 return false; 380 } 381 382 bool RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo *reg_info, 383 const RegisterValue &value) { 384 return false; 385 } 386 387 bool RegisterContextCorePOSIX_arm64::WriteAllRegisterValues( 388 const lldb::DataBufferSP &data_sp) { 389 return false; 390 } 391 392 bool RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable) { 393 return false; 394 } 395