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/RegisterFlagsDetector_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 DataExtractor fpmr_data = 68 getRegset(notes, arch.GetTriple(), AARCH64_FPMR_Desc); 69 if (fpmr_data.GetByteSize() >= sizeof(uint64_t)) 70 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskFPMR); 71 72 DataExtractor gcs_data = getRegset(notes, arch.GetTriple(), AARCH64_GCS_Desc); 73 struct __attribute__((packed)) gcs_regs { 74 uint64_t features_enabled; 75 uint64_t features_locked; 76 uint64_t gcspr_e0; 77 }; 78 if (gcs_data.GetByteSize() >= sizeof(gcs_regs)) 79 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskGCS); 80 81 auto register_info_up = 82 std::make_unique<RegisterInfoPOSIX_arm64>(arch, opt_regsets); 83 return std::unique_ptr<RegisterContextCorePOSIX_arm64>( 84 new RegisterContextCorePOSIX_arm64(thread, std::move(register_info_up), 85 gpregset, notes)); 86 } 87 88 RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64( 89 Thread &thread, std::unique_ptr<RegisterInfoPOSIX_arm64> register_info, 90 const DataExtractor &gpregset, llvm::ArrayRef<CoreNote> notes) 91 : RegisterContextPOSIX_arm64(thread, std::move(register_info)) { 92 ::memset(&m_sme_pseudo_regs, 0, sizeof(m_sme_pseudo_regs)); 93 94 ProcessElfCore *process = 95 static_cast<ProcessElfCore *>(thread.GetProcess().get()); 96 llvm::Triple::OSType os = process->GetArchitecture().GetTriple().getOS(); 97 if ((os == llvm::Triple::Linux) || (os == llvm::Triple::FreeBSD)) { 98 AuxVector aux_vec(process->GetAuxvData()); 99 std::optional<uint64_t> auxv_at_hwcap = aux_vec.GetAuxValue( 100 os == llvm::Triple::FreeBSD ? AuxVector::AUXV_FREEBSD_AT_HWCAP 101 : AuxVector::AUXV_AT_HWCAP); 102 std::optional<uint64_t> auxv_at_hwcap2 = 103 aux_vec.GetAuxValue(AuxVector::AUXV_AT_HWCAP2); 104 105 m_register_flags_detector.DetectFields(auxv_at_hwcap.value_or(0), 106 auxv_at_hwcap2.value_or(0)); 107 m_register_flags_detector.UpdateRegisterInfo(GetRegisterInfo(), 108 GetRegisterCount()); 109 } 110 111 m_gpr_data.SetData(std::make_shared<DataBufferHeap>(gpregset.GetDataStart(), 112 gpregset.GetByteSize())); 113 m_gpr_data.SetByteOrder(gpregset.GetByteOrder()); 114 115 const llvm::Triple &target_triple = 116 m_register_info_up->GetTargetArchitecture().GetTriple(); 117 m_fpr_data = getRegset(notes, target_triple, FPR_Desc); 118 119 if (m_register_info_up->IsSSVEPresent()) { 120 m_sve_data = getRegset(notes, target_triple, AARCH64_SSVE_Desc); 121 lldb::offset_t flags_offset = 12; 122 uint16_t flags = m_sve_data.GetU32(&flags_offset); 123 if ((flags & sve::ptrace_regs_mask) == sve::ptrace_regs_sve) 124 m_sve_state = SVEState::Streaming; 125 } 126 127 if (m_sve_state != SVEState::Streaming && m_register_info_up->IsSVEPresent()) 128 m_sve_data = getRegset(notes, target_triple, AARCH64_SVE_Desc); 129 130 if (m_register_info_up->IsPAuthPresent()) 131 m_pac_data = getRegset(notes, target_triple, AARCH64_PAC_Desc); 132 133 if (m_register_info_up->IsTLSPresent()) 134 m_tls_data = getRegset(notes, target_triple, AARCH64_TLS_Desc); 135 136 if (m_register_info_up->IsZAPresent()) 137 m_za_data = getRegset(notes, target_triple, AARCH64_ZA_Desc); 138 139 if (m_register_info_up->IsMTEPresent()) 140 m_mte_data = getRegset(notes, target_triple, AARCH64_MTE_Desc); 141 142 if (m_register_info_up->IsZTPresent()) 143 m_zt_data = getRegset(notes, target_triple, AARCH64_ZT_Desc); 144 145 if (m_register_info_up->IsFPMRPresent()) 146 m_fpmr_data = getRegset(notes, target_triple, AARCH64_FPMR_Desc); 147 148 if (m_register_info_up->IsGCSPresent()) 149 m_gcs_data = getRegset(notes, target_triple, AARCH64_GCS_Desc); 150 151 ConfigureRegisterContext(); 152 } 153 154 RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() = default; 155 156 bool RegisterContextCorePOSIX_arm64::ReadGPR() { return true; } 157 158 bool RegisterContextCorePOSIX_arm64::ReadFPR() { return false; } 159 160 bool RegisterContextCorePOSIX_arm64::WriteGPR() { 161 assert(0); 162 return false; 163 } 164 165 bool RegisterContextCorePOSIX_arm64::WriteFPR() { 166 assert(0); 167 return false; 168 } 169 170 const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) { 171 return m_sve_data.GetDataStart() + offset; 172 } 173 174 void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() { 175 if (m_sve_data.GetByteSize() > sizeof(sve::user_sve_header)) { 176 uint64_t sve_header_field_offset = 8; 177 m_sve_vector_length = m_sve_data.GetU16(&sve_header_field_offset); 178 179 if (m_sve_state != SVEState::Streaming) { 180 sve_header_field_offset = 12; 181 uint16_t sve_header_flags_field = 182 m_sve_data.GetU16(&sve_header_field_offset); 183 if ((sve_header_flags_field & sve::ptrace_regs_mask) == 184 sve::ptrace_regs_fpsimd) 185 m_sve_state = SVEState::FPSIMD; 186 else if ((sve_header_flags_field & sve::ptrace_regs_mask) == 187 sve::ptrace_regs_sve) 188 m_sve_state = SVEState::Full; 189 } 190 191 if (!sve::vl_valid(m_sve_vector_length)) { 192 m_sve_state = SVEState::Disabled; 193 m_sve_vector_length = 0; 194 } 195 } else 196 m_sve_state = SVEState::Disabled; 197 198 if (m_sve_state != SVEState::Disabled) 199 m_register_info_up->ConfigureVectorLengthSVE( 200 sve::vq_from_vl(m_sve_vector_length)); 201 202 if (m_sve_state == SVEState::Streaming) 203 m_sme_pseudo_regs.ctrl_reg |= 1; 204 205 if (m_za_data.GetByteSize() >= sizeof(sve::user_za_header)) { 206 lldb::offset_t vlen_offset = 8; 207 uint16_t svl = m_za_data.GetU16(&vlen_offset); 208 m_sme_pseudo_regs.svg_reg = svl / 8; 209 m_register_info_up->ConfigureVectorLengthZA(svl / 16); 210 211 // If there is register data then ZA is active. The size of the note may be 212 // misleading here so we use the size field of the embedded header. 213 lldb::offset_t size_offset = 0; 214 uint32_t size = m_za_data.GetU32(&size_offset); 215 if (size > sizeof(sve::user_za_header)) 216 m_sme_pseudo_regs.ctrl_reg |= 1 << 1; 217 } 218 } 219 220 uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset( 221 const RegisterInfo *reg_info) { 222 // Start of Z0 data is after GPRs plus 8 bytes of vg register 223 uint32_t sve_reg_offset = LLDB_INVALID_INDEX32; 224 if (m_sve_state == SVEState::FPSIMD) { 225 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 226 sve_reg_offset = sve::ptrace_fpsimd_offset + (reg - GetRegNumSVEZ0()) * 16; 227 } else if (m_sve_state == SVEState::Full || 228 m_sve_state == SVEState::Streaming) { 229 uint32_t sve_z0_offset = GetGPRSize() + 16; 230 sve_reg_offset = 231 sve::SigRegsOffset() + reg_info->byte_offset - sve_z0_offset; 232 } 233 234 return sve_reg_offset; 235 } 236 237 bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, 238 RegisterValue &value) { 239 Status error; 240 lldb::offset_t offset; 241 242 offset = reg_info->byte_offset; 243 if (offset + reg_info->byte_size <= GetGPRSize()) { 244 value.SetFromMemoryData(*reg_info, m_gpr_data.GetDataStart() + offset, 245 reg_info->byte_size, lldb::eByteOrderLittle, error); 246 return error.Success(); 247 } 248 249 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 250 if (reg == LLDB_INVALID_REGNUM) 251 return false; 252 253 if (IsFPR(reg)) { 254 if (m_sve_state == SVEState::Disabled) { 255 // SVE is disabled take legacy route for FPU register access 256 offset -= GetGPRSize(); 257 if (offset < m_fpr_data.GetByteSize()) { 258 value.SetFromMemoryData(*reg_info, m_fpr_data.GetDataStart() + offset, 259 reg_info->byte_size, lldb::eByteOrderLittle, 260 error); 261 return error.Success(); 262 } 263 } else { 264 // FPSR and FPCR will be located right after Z registers in 265 // SVEState::FPSIMD while in SVEState::Full/SVEState::Streaming they will 266 // be located at the end of register data after an alignment correction 267 // based on currently selected vector length. 268 uint32_t sve_reg_num = LLDB_INVALID_REGNUM; 269 if (reg == GetRegNumFPSR()) { 270 sve_reg_num = reg; 271 if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming) 272 offset = sve::PTraceFPSROffset(sve::vq_from_vl(m_sve_vector_length)); 273 else if (m_sve_state == SVEState::FPSIMD) 274 offset = sve::ptrace_fpsimd_offset + (32 * 16); 275 } else if (reg == GetRegNumFPCR()) { 276 sve_reg_num = reg; 277 if (m_sve_state == SVEState::Full || m_sve_state == SVEState::Streaming) 278 offset = sve::PTraceFPCROffset(sve::vq_from_vl(m_sve_vector_length)); 279 else if (m_sve_state == SVEState::FPSIMD) 280 offset = sve::ptrace_fpsimd_offset + (32 * 16) + 4; 281 } else { 282 // Extract SVE Z register value register number for this reg_info 283 if (reg_info->value_regs && 284 reg_info->value_regs[0] != LLDB_INVALID_REGNUM) 285 sve_reg_num = reg_info->value_regs[0]; 286 offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num)); 287 } 288 289 assert(sve_reg_num != LLDB_INVALID_REGNUM); 290 assert(offset < m_sve_data.GetByteSize()); 291 value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset), 292 reg_info->byte_size, lldb::eByteOrderLittle, 293 error); 294 } 295 } else if (IsSVE(reg)) { 296 if (IsSVEVG(reg)) { 297 value = GetSVERegVG(); 298 return true; 299 } 300 301 switch (m_sve_state) { 302 case SVEState::FPSIMD: { 303 // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just 304 // copy 16 bytes of v register to the start of z register. All other 305 // SVE register will be set to zero. 306 uint64_t byte_size = 1; 307 uint8_t zeros = 0; 308 const uint8_t *src = &zeros; 309 if (IsSVEZ(reg)) { 310 byte_size = 16; 311 offset = CalculateSVEOffset(reg_info); 312 assert(offset < m_sve_data.GetByteSize()); 313 src = GetSVEBuffer(offset); 314 } 315 value.SetFromMemoryData(*reg_info, src, byte_size, lldb::eByteOrderLittle, 316 error); 317 } break; 318 case SVEState::Full: 319 case SVEState::Streaming: 320 offset = CalculateSVEOffset(reg_info); 321 assert(offset < m_sve_data.GetByteSize()); 322 value.SetFromMemoryData(*reg_info, GetSVEBuffer(offset), 323 reg_info->byte_size, lldb::eByteOrderLittle, 324 error); 325 break; 326 case SVEState::Disabled: 327 default: 328 return false; 329 } 330 } else if (IsPAuth(reg)) { 331 offset = reg_info->byte_offset - m_register_info_up->GetPAuthOffset(); 332 assert(offset < m_pac_data.GetByteSize()); 333 value.SetFromMemoryData(*reg_info, m_pac_data.GetDataStart() + offset, 334 reg_info->byte_size, lldb::eByteOrderLittle, error); 335 } else if (IsTLS(reg)) { 336 offset = reg_info->byte_offset - m_register_info_up->GetTLSOffset(); 337 assert(offset < m_tls_data.GetByteSize()); 338 value.SetFromMemoryData(*reg_info, m_tls_data.GetDataStart() + offset, 339 reg_info->byte_size, lldb::eByteOrderLittle, error); 340 } else if (IsMTE(reg)) { 341 offset = reg_info->byte_offset - m_register_info_up->GetMTEOffset(); 342 assert(offset < m_mte_data.GetByteSize()); 343 value.SetFromMemoryData(*reg_info, m_mte_data.GetDataStart() + offset, 344 reg_info->byte_size, lldb::eByteOrderLittle, error); 345 } else if (IsGCS(reg)) { 346 offset = reg_info->byte_offset - m_register_info_up->GetGCSOffset(); 347 assert(offset < m_gcs_data.GetByteSize()); 348 value.SetFromMemoryData(*reg_info, m_gcs_data.GetDataStart() + offset, 349 reg_info->byte_size, lldb::eByteOrderLittle, error); 350 } else if (IsSME(reg)) { 351 // If you had SME in the process, active or otherwise, there will at least 352 // be a ZA header. No header, no SME at all. 353 if (m_za_data.GetByteSize() < sizeof(sve::user_za_header)) 354 return false; 355 356 if (m_register_info_up->IsSMERegZA(reg)) { 357 // Don't use the size of the note to tell whether ZA is enabled. There may 358 // be non-register padding data after the header. Use the embedded 359 // header's size field instead. 360 lldb::offset_t size_offset = 0; 361 uint32_t size = m_za_data.GetU32(&size_offset); 362 bool za_enabled = size > sizeof(sve::user_za_header); 363 364 size_t za_note_size = m_za_data.GetByteSize(); 365 // For a disabled ZA we fake a value of all 0s. 366 if (!za_enabled) { 367 uint64_t svl = m_sme_pseudo_regs.svg_reg * 8; 368 za_note_size = sizeof(sve::user_za_header) + (svl * svl); 369 } 370 371 const uint8_t *src = nullptr; 372 std::vector<uint8_t> disabled_za_data; 373 374 if (za_enabled) 375 src = m_za_data.GetDataStart(); 376 else { 377 disabled_za_data.resize(za_note_size); 378 std::fill(disabled_za_data.begin(), disabled_za_data.end(), 0); 379 src = disabled_za_data.data(); 380 } 381 382 value.SetFromMemoryData(*reg_info, src + sizeof(sve::user_za_header), 383 reg_info->byte_size, lldb::eByteOrderLittle, 384 error); 385 } else if (m_register_info_up->IsSMERegZT(reg)) { 386 value.SetFromMemoryData(*reg_info, m_zt_data.GetDataStart(), 387 reg_info->byte_size, lldb::eByteOrderLittle, 388 error); 389 } else { 390 offset = reg_info->byte_offset - m_register_info_up->GetSMEOffset(); 391 assert(offset < sizeof(m_sme_pseudo_regs)); 392 // Host endian since these values are derived instead of being read from a 393 // core file note. 394 value.SetFromMemoryData( 395 *reg_info, reinterpret_cast<uint8_t *>(&m_sme_pseudo_regs) + offset, 396 reg_info->byte_size, lldb_private::endian::InlHostByteOrder(), error); 397 } 398 } else if (IsFPMR(reg)) { 399 offset = reg_info->byte_offset - m_register_info_up->GetFPMROffset(); 400 assert(offset < m_fpmr_data.GetByteSize()); 401 value.SetFromMemoryData(*reg_info, m_fpmr_data.GetDataStart() + offset, 402 reg_info->byte_size, lldb::eByteOrderLittle, error); 403 } else 404 return false; 405 406 return error.Success(); 407 } 408 409 bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues( 410 lldb::WritableDataBufferSP &data_sp) { 411 return false; 412 } 413 414 bool RegisterContextCorePOSIX_arm64::WriteRegister(const RegisterInfo *reg_info, 415 const RegisterValue &value) { 416 return false; 417 } 418 419 bool RegisterContextCorePOSIX_arm64::WriteAllRegisterValues( 420 const lldb::DataBufferSP &data_sp) { 421 return false; 422 } 423 424 bool RegisterContextCorePOSIX_arm64::HardwareSingleStep(bool enable) { 425 return false; 426 } 427