1 //===-- NativeRegisterContextLinux_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 #if defined(__arm64__) || defined(__aarch64__) 10 11 #include "NativeRegisterContextLinux_arm.h" 12 #include "NativeRegisterContextLinux_arm64.h" 13 14 15 #include "lldb/Host/common/NativeProcessProtocol.h" 16 #include "lldb/Utility/DataBufferHeap.h" 17 #include "lldb/Utility/Log.h" 18 #include "lldb/Utility/RegisterValue.h" 19 #include "lldb/Utility/Status.h" 20 21 #include "Plugins/Process/Linux/NativeProcessLinux.h" 22 #include "Plugins/Process/Linux/Procfs.h" 23 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 24 #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" 25 26 // System includes - They have to be included after framework includes because 27 // they define some macros which collide with variable names in other modules 28 #include <sys/socket.h> 29 // NT_PRSTATUS and NT_FPREGSET definition 30 #include <elf.h> 31 32 #ifndef NT_ARM_SVE 33 #define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension */ 34 #endif 35 36 #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize()) 37 38 using namespace lldb; 39 using namespace lldb_private; 40 using namespace lldb_private::process_linux; 41 42 std::unique_ptr<NativeRegisterContextLinux> 43 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( 44 const ArchSpec &target_arch, NativeThreadLinux &native_thread) { 45 switch (target_arch.GetMachine()) { 46 case llvm::Triple::arm: 47 return std::make_unique<NativeRegisterContextLinux_arm>(target_arch, 48 native_thread); 49 case llvm::Triple::aarch64: { 50 // Configure register sets supported by this AArch64 target. 51 // Read SVE header to check for SVE support. 52 struct user_sve_header sve_header; 53 struct iovec ioVec; 54 ioVec.iov_base = &sve_header; 55 ioVec.iov_len = sizeof(sve_header); 56 unsigned int regset = NT_ARM_SVE; 57 58 Flags opt_regsets; 59 if (NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, 60 native_thread.GetID(), ®set, 61 &ioVec, sizeof(sve_header)) 62 .Success()) 63 opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE); 64 65 auto register_info_up = 66 std::make_unique<RegisterInfoPOSIX_arm64>(target_arch, opt_regsets); 67 return std::make_unique<NativeRegisterContextLinux_arm64>( 68 target_arch, native_thread, std::move(register_info_up)); 69 } 70 default: 71 llvm_unreachable("have no register context for architecture"); 72 } 73 } 74 75 NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64( 76 const ArchSpec &target_arch, NativeThreadProtocol &native_thread, 77 std::unique_ptr<RegisterInfoPOSIX_arm64> register_info_up) 78 : NativeRegisterContextRegisterInfo(native_thread, 79 register_info_up.release()), 80 NativeRegisterContextLinux(native_thread) { 81 ::memset(&m_fpr, 0, sizeof(m_fpr)); 82 ::memset(&m_gpr_arm64, 0, sizeof(m_gpr_arm64)); 83 ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); 84 ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs)); 85 ::memset(&m_sve_header, 0, sizeof(m_sve_header)); 86 87 // 16 is just a maximum value, query hardware for actual watchpoint count 88 m_max_hwp_supported = 16; 89 m_max_hbp_supported = 16; 90 91 m_refresh_hwdebug_info = true; 92 93 m_gpr_is_valid = false; 94 m_fpu_is_valid = false; 95 m_sve_buffer_is_valid = false; 96 m_sve_header_is_valid = false; 97 98 if (GetRegisterInfo().IsSVEEnabled()) 99 m_sve_state = SVEState::Unknown; 100 else 101 m_sve_state = SVEState::Disabled; 102 } 103 104 RegisterInfoPOSIX_arm64 & 105 NativeRegisterContextLinux_arm64::GetRegisterInfo() const { 106 return static_cast<RegisterInfoPOSIX_arm64 &>(*m_register_info_interface_up); 107 } 108 109 uint32_t NativeRegisterContextLinux_arm64::GetRegisterSetCount() const { 110 return GetRegisterInfo().GetRegisterSetCount(); 111 } 112 113 const RegisterSet * 114 NativeRegisterContextLinux_arm64::GetRegisterSet(uint32_t set_index) const { 115 return GetRegisterInfo().GetRegisterSet(set_index); 116 } 117 118 uint32_t NativeRegisterContextLinux_arm64::GetUserRegisterCount() const { 119 uint32_t count = 0; 120 for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) 121 count += GetRegisterSet(set_index)->num_registers; 122 return count; 123 } 124 125 Status 126 NativeRegisterContextLinux_arm64::ReadRegister(const RegisterInfo *reg_info, 127 RegisterValue ®_value) { 128 Status error; 129 130 if (!reg_info) { 131 error.SetErrorString("reg_info NULL"); 132 return error; 133 } 134 135 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 136 137 if (reg == LLDB_INVALID_REGNUM) 138 return Status("no lldb regnum for %s", reg_info && reg_info->name 139 ? reg_info->name 140 : "<unknown register>"); 141 142 uint8_t *src; 143 uint32_t offset = LLDB_INVALID_INDEX32; 144 uint64_t sve_vg; 145 std::vector<uint8_t> sve_reg_non_live; 146 147 if (IsGPR(reg)) { 148 error = ReadGPR(); 149 if (error.Fail()) 150 return error; 151 152 offset = reg_info->byte_offset; 153 assert(offset < GetGPRSize()); 154 src = (uint8_t *)GetGPRBuffer() + offset; 155 156 } else if (IsFPR(reg)) { 157 if (m_sve_state == SVEState::Disabled) { 158 // SVE is disabled take legacy route for FPU register access 159 error = ReadFPR(); 160 if (error.Fail()) 161 return error; 162 163 offset = CalculateFprOffset(reg_info); 164 assert(offset < GetFPRSize()); 165 src = (uint8_t *)GetFPRBuffer() + offset; 166 } else { 167 // SVE enabled, we will read and cache SVE ptrace data 168 error = ReadAllSVE(); 169 if (error.Fail()) 170 return error; 171 172 // FPSR and FPCR will be located right after Z registers in 173 // SVEState::FPSIMD while in SVEState::Full they will be located at the 174 // end of register data after an alignment correction based on currently 175 // selected vector length. 176 uint32_t sve_reg_num = LLDB_INVALID_REGNUM; 177 if (reg == GetRegisterInfo().GetRegNumFPSR()) { 178 sve_reg_num = reg; 179 if (m_sve_state == SVEState::Full) 180 offset = SVE_PT_SVE_FPSR_OFFSET(sve_vq_from_vl(m_sve_header.vl)); 181 else if (m_sve_state == SVEState::FPSIMD) 182 offset = SVE_PT_FPSIMD_OFFSET + (32 * 16); 183 } else if (reg == GetRegisterInfo().GetRegNumFPCR()) { 184 sve_reg_num = reg; 185 if (m_sve_state == SVEState::Full) 186 offset = SVE_PT_SVE_FPCR_OFFSET(sve_vq_from_vl(m_sve_header.vl)); 187 else if (m_sve_state == SVEState::FPSIMD) 188 offset = SVE_PT_FPSIMD_OFFSET + (32 * 16) + 4; 189 } else { 190 // Extract SVE Z register value register number for this reg_info 191 if (reg_info->value_regs && 192 reg_info->value_regs[0] != LLDB_INVALID_REGNUM) 193 sve_reg_num = reg_info->value_regs[0]; 194 offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num)); 195 } 196 197 assert(offset < GetSVEBufferSize()); 198 src = (uint8_t *)GetSVEBuffer() + offset; 199 } 200 } else if (IsSVE(reg)) { 201 202 if (m_sve_state == SVEState::Disabled || m_sve_state == SVEState::Unknown) 203 return Status("SVE disabled or not supported"); 204 205 if (GetRegisterInfo().IsSVERegVG(reg)) { 206 sve_vg = GetSVERegVG(); 207 src = (uint8_t *)&sve_vg; 208 } else { 209 // SVE enabled, we will read and cache SVE ptrace data 210 error = ReadAllSVE(); 211 if (error.Fail()) 212 return error; 213 214 if (m_sve_state == SVEState::FPSIMD) { 215 // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so 216 // just copy 16 bytes of v register to the start of z register. All 217 // other SVE register will be set to zero. 218 sve_reg_non_live.resize(reg_info->byte_size, 0); 219 src = sve_reg_non_live.data(); 220 221 if (GetRegisterInfo().IsSVEZReg(reg)) { 222 offset = CalculateSVEOffset(reg_info); 223 assert(offset < GetSVEBufferSize()); 224 ::memcpy(sve_reg_non_live.data(), (uint8_t *)GetSVEBuffer() + offset, 225 16); 226 } 227 } else { 228 offset = CalculateSVEOffset(reg_info); 229 assert(offset < GetSVEBufferSize()); 230 src = (uint8_t *)GetSVEBuffer() + offset; 231 } 232 } 233 } else 234 return Status("failed - register wasn't recognized to be a GPR or an FPR, " 235 "write strategy unknown"); 236 237 reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, 238 eByteOrderLittle, error); 239 240 return error; 241 } 242 243 Status NativeRegisterContextLinux_arm64::WriteRegister( 244 const RegisterInfo *reg_info, const RegisterValue ®_value) { 245 Status error; 246 247 if (!reg_info) 248 return Status("reg_info NULL"); 249 250 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 251 252 if (reg == LLDB_INVALID_REGNUM) 253 return Status("no lldb regnum for %s", reg_info && reg_info->name 254 ? reg_info->name 255 : "<unknown register>"); 256 257 uint8_t *dst; 258 uint32_t offset = LLDB_INVALID_INDEX32; 259 std::vector<uint8_t> sve_reg_non_live; 260 261 if (IsGPR(reg)) { 262 error = ReadGPR(); 263 if (error.Fail()) 264 return error; 265 266 assert(reg_info->byte_offset < GetGPRSize()); 267 dst = (uint8_t *)GetGPRBuffer() + reg_info->byte_offset; 268 ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); 269 270 return WriteGPR(); 271 } else if (IsFPR(reg)) { 272 if (m_sve_state == SVEState::Disabled) { 273 // SVE is disabled take legacy route for FPU register access 274 error = ReadFPR(); 275 if (error.Fail()) 276 return error; 277 278 offset = CalculateFprOffset(reg_info); 279 assert(offset < GetFPRSize()); 280 dst = (uint8_t *)GetFPRBuffer() + offset; 281 ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); 282 283 return WriteFPR(); 284 } else { 285 // SVE enabled, we will read and cache SVE ptrace data 286 error = ReadAllSVE(); 287 if (error.Fail()) 288 return error; 289 290 // FPSR and FPCR will be located right after Z registers in 291 // SVEState::FPSIMD while in SVEState::Full they will be located at the 292 // end of register data after an alignment correction based on currently 293 // selected vector length. 294 uint32_t sve_reg_num = LLDB_INVALID_REGNUM; 295 if (reg == GetRegisterInfo().GetRegNumFPSR()) { 296 sve_reg_num = reg; 297 if (m_sve_state == SVEState::Full) 298 offset = SVE_PT_SVE_FPSR_OFFSET(sve_vq_from_vl(m_sve_header.vl)); 299 else if (m_sve_state == SVEState::FPSIMD) 300 offset = SVE_PT_FPSIMD_OFFSET + (32 * 16); 301 } else if (reg == GetRegisterInfo().GetRegNumFPCR()) { 302 sve_reg_num = reg; 303 if (m_sve_state == SVEState::Full) 304 offset = SVE_PT_SVE_FPCR_OFFSET(sve_vq_from_vl(m_sve_header.vl)); 305 else if (m_sve_state == SVEState::FPSIMD) 306 offset = SVE_PT_FPSIMD_OFFSET + (32 * 16) + 4; 307 } else { 308 // Extract SVE Z register value register number for this reg_info 309 if (reg_info->value_regs && 310 reg_info->value_regs[0] != LLDB_INVALID_REGNUM) 311 sve_reg_num = reg_info->value_regs[0]; 312 offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num)); 313 } 314 315 assert(offset < GetSVEBufferSize()); 316 dst = (uint8_t *)GetSVEBuffer() + offset; 317 ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); 318 return WriteAllSVE(); 319 } 320 } else if (IsSVE(reg)) { 321 if (m_sve_state == SVEState::Disabled || m_sve_state == SVEState::Unknown) 322 return Status("SVE disabled or not supported"); 323 else { 324 // Target has SVE enabled, we will read and cache SVE ptrace data 325 error = ReadAllSVE(); 326 if (error.Fail()) 327 return error; 328 329 if (GetRegisterInfo().IsSVERegVG(reg)) { 330 uint64_t vg_value = reg_value.GetAsUInt64(); 331 332 if (sve_vl_valid(vg_value * 8)) { 333 if (m_sve_header_is_valid && vg_value == GetSVERegVG()) 334 return error; 335 336 SetSVERegVG(vg_value); 337 338 error = WriteSVEHeader(); 339 if (error.Success()) 340 ConfigureRegisterContext(); 341 342 if (m_sve_header_is_valid && vg_value == GetSVERegVG()) 343 return error; 344 } 345 346 return Status("SVE vector length update failed."); 347 } 348 349 // If target supports SVE but currently in FPSIMD mode. 350 if (m_sve_state == SVEState::FPSIMD) { 351 // Here we will check if writing this SVE register enables 352 // SVEState::Full 353 bool set_sve_state_full = false; 354 const uint8_t *reg_bytes = (const uint8_t *)reg_value.GetBytes(); 355 if (GetRegisterInfo().IsSVEZReg(reg)) { 356 for (uint32_t i = 16; i < reg_info->byte_size; i++) { 357 if (reg_bytes[i]) { 358 set_sve_state_full = true; 359 break; 360 } 361 } 362 } else if (GetRegisterInfo().IsSVEPReg(reg) || 363 reg == GetRegisterInfo().GetRegNumSVEFFR()) { 364 for (uint32_t i = 0; i < reg_info->byte_size; i++) { 365 if (reg_bytes[i]) { 366 set_sve_state_full = true; 367 break; 368 } 369 } 370 } 371 372 if (!set_sve_state_full && GetRegisterInfo().IsSVEZReg(reg)) { 373 // We are writing a Z register which is zero beyond 16 bytes so copy 374 // first 16 bytes only as SVE payload mirrors legacy fpsimd structure 375 offset = CalculateSVEOffset(reg_info); 376 assert(offset < GetSVEBufferSize()); 377 dst = (uint8_t *)GetSVEBuffer() + offset; 378 ::memcpy(dst, reg_value.GetBytes(), 16); 379 380 return WriteAllSVE(); 381 } else 382 return Status("SVE state change operation not supported"); 383 } else { 384 offset = CalculateSVEOffset(reg_info); 385 assert(offset < GetSVEBufferSize()); 386 dst = (uint8_t *)GetSVEBuffer() + offset; 387 ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); 388 return WriteAllSVE(); 389 } 390 } 391 } 392 393 return Status("Failed to write register value"); 394 } 395 396 Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues( 397 lldb::DataBufferSP &data_sp) { 398 Status error; 399 400 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 401 402 error = ReadGPR(); 403 if (error.Fail()) 404 return error; 405 406 error = ReadFPR(); 407 if (error.Fail()) 408 return error; 409 410 uint8_t *dst = data_sp->GetBytes(); 411 ::memcpy(dst, GetGPRBuffer(), GetGPRSize()); 412 dst += GetGPRSize(); 413 ::memcpy(dst, GetFPRBuffer(), GetFPRSize()); 414 415 return error; 416 } 417 418 Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues( 419 const lldb::DataBufferSP &data_sp) { 420 Status error; 421 422 if (!data_sp) { 423 error.SetErrorStringWithFormat( 424 "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", 425 __FUNCTION__); 426 return error; 427 } 428 429 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 430 error.SetErrorStringWithFormat( 431 "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched " 432 "data size, expected %" PRIu64 ", actual %" PRIu64, 433 __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); 434 return error; 435 } 436 437 uint8_t *src = data_sp->GetBytes(); 438 if (src == nullptr) { 439 error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " 440 "DataBuffer::GetBytes() returned a null " 441 "pointer", 442 __FUNCTION__); 443 return error; 444 } 445 ::memcpy(GetGPRBuffer(), src, GetRegisterInfoInterface().GetGPRSize()); 446 447 error = WriteGPR(); 448 if (error.Fail()) 449 return error; 450 451 src += GetRegisterInfoInterface().GetGPRSize(); 452 ::memcpy(GetFPRBuffer(), src, GetFPRSize()); 453 454 error = WriteFPR(); 455 if (error.Fail()) 456 return error; 457 458 return error; 459 } 460 461 bool NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const { 462 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) == 463 RegisterInfoPOSIX_arm64::GPRegSet) 464 return true; 465 return false; 466 } 467 468 bool NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const { 469 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) == 470 RegisterInfoPOSIX_arm64::FPRegSet) 471 return true; 472 return false; 473 } 474 475 bool NativeRegisterContextLinux_arm64::IsSVE(unsigned reg) const { 476 return GetRegisterInfo().IsSVEReg(reg); 477 } 478 479 llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() { 480 if (!m_refresh_hwdebug_info) { 481 return llvm::Error::success(); 482 } 483 484 ::pid_t tid = m_thread.GetID(); 485 486 int regset = NT_ARM_HW_WATCH; 487 struct iovec ioVec; 488 struct user_hwdebug_state dreg_state; 489 Status error; 490 491 ioVec.iov_base = &dreg_state; 492 ioVec.iov_len = sizeof(dreg_state); 493 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, 494 &ioVec, ioVec.iov_len); 495 496 if (error.Fail()) 497 return error.ToError(); 498 499 m_max_hwp_supported = dreg_state.dbg_info & 0xff; 500 501 regset = NT_ARM_HW_BREAK; 502 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, 503 &ioVec, ioVec.iov_len); 504 505 if (error.Fail()) 506 return error.ToError(); 507 508 m_max_hbp_supported = dreg_state.dbg_info & 0xff; 509 m_refresh_hwdebug_info = false; 510 511 return llvm::Error::success(); 512 } 513 514 llvm::Error 515 NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(DREGType hwbType) { 516 struct iovec ioVec; 517 struct user_hwdebug_state dreg_state; 518 int regset; 519 520 memset(&dreg_state, 0, sizeof(dreg_state)); 521 ioVec.iov_base = &dreg_state; 522 523 switch (hwbType) { 524 case eDREGTypeWATCH: 525 regset = NT_ARM_HW_WATCH; 526 ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + 527 (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported); 528 529 for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 530 dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address; 531 dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control; 532 } 533 break; 534 case eDREGTypeBREAK: 535 regset = NT_ARM_HW_BREAK; 536 ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + 537 (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported); 538 539 for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 540 dreg_state.dbg_regs[i].addr = m_hbp_regs[i].address; 541 dreg_state.dbg_regs[i].ctrl = m_hbp_regs[i].control; 542 } 543 break; 544 } 545 546 return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), 547 ®set, &ioVec, ioVec.iov_len) 548 .ToError(); 549 } 550 551 Status NativeRegisterContextLinux_arm64::ReadGPR() { 552 Status error; 553 554 if (m_gpr_is_valid) 555 return error; 556 557 struct iovec ioVec; 558 ioVec.iov_base = GetGPRBuffer(); 559 ioVec.iov_len = GetGPRBufferSize(); 560 561 error = ReadRegisterSet(&ioVec, GetGPRBufferSize(), NT_PRSTATUS); 562 563 if (error.Success()) 564 m_gpr_is_valid = true; 565 566 return error; 567 } 568 569 Status NativeRegisterContextLinux_arm64::WriteGPR() { 570 Status error = ReadGPR(); 571 if (error.Fail()) 572 return error; 573 574 struct iovec ioVec; 575 ioVec.iov_base = GetGPRBuffer(); 576 ioVec.iov_len = GetGPRBufferSize(); 577 578 m_gpr_is_valid = false; 579 580 return WriteRegisterSet(&ioVec, GetGPRBufferSize(), NT_PRSTATUS); 581 } 582 583 Status NativeRegisterContextLinux_arm64::ReadFPR() { 584 Status error; 585 586 if (m_fpu_is_valid) 587 return error; 588 589 struct iovec ioVec; 590 ioVec.iov_base = GetFPRBuffer(); 591 ioVec.iov_len = GetFPRSize(); 592 593 error = ReadRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET); 594 595 if (error.Success()) 596 m_fpu_is_valid = true; 597 598 return error; 599 } 600 601 Status NativeRegisterContextLinux_arm64::WriteFPR() { 602 Status error = ReadFPR(); 603 if (error.Fail()) 604 return error; 605 606 struct iovec ioVec; 607 ioVec.iov_base = GetFPRBuffer(); 608 ioVec.iov_len = GetFPRSize(); 609 610 m_fpu_is_valid = false; 611 612 return WriteRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET); 613 } 614 615 void NativeRegisterContextLinux_arm64::InvalidateAllRegisters() { 616 m_gpr_is_valid = false; 617 m_fpu_is_valid = false; 618 m_sve_buffer_is_valid = false; 619 m_sve_header_is_valid = false; 620 621 // Update SVE registers in case there is change in configuration. 622 ConfigureRegisterContext(); 623 } 624 625 Status NativeRegisterContextLinux_arm64::ReadSVEHeader() { 626 Status error; 627 628 if (m_sve_header_is_valid) 629 return error; 630 631 struct iovec ioVec; 632 ioVec.iov_base = GetSVEHeader(); 633 ioVec.iov_len = GetSVEHeaderSize(); 634 635 error = ReadRegisterSet(&ioVec, GetSVEHeaderSize(), NT_ARM_SVE); 636 637 m_sve_header_is_valid = true; 638 639 return error; 640 } 641 642 Status NativeRegisterContextLinux_arm64::WriteSVEHeader() { 643 Status error; 644 645 error = ReadSVEHeader(); 646 if (error.Fail()) 647 return error; 648 649 struct iovec ioVec; 650 ioVec.iov_base = GetSVEHeader(); 651 ioVec.iov_len = GetSVEHeaderSize(); 652 653 m_sve_buffer_is_valid = false; 654 m_sve_header_is_valid = false; 655 m_fpu_is_valid = false; 656 657 return WriteRegisterSet(&ioVec, GetSVEHeaderSize(), NT_ARM_SVE); 658 } 659 660 Status NativeRegisterContextLinux_arm64::ReadAllSVE() { 661 Status error; 662 663 if (m_sve_buffer_is_valid) 664 return error; 665 666 struct iovec ioVec; 667 ioVec.iov_base = GetSVEBuffer(); 668 ioVec.iov_len = GetSVEBufferSize(); 669 670 error = ReadRegisterSet(&ioVec, GetSVEBufferSize(), NT_ARM_SVE); 671 672 if (error.Success()) 673 m_sve_buffer_is_valid = true; 674 675 return error; 676 } 677 678 Status NativeRegisterContextLinux_arm64::WriteAllSVE() { 679 Status error; 680 681 error = ReadAllSVE(); 682 if (error.Fail()) 683 return error; 684 685 struct iovec ioVec; 686 687 ioVec.iov_base = GetSVEBuffer(); 688 ioVec.iov_len = GetSVEBufferSize(); 689 690 m_sve_buffer_is_valid = false; 691 m_sve_header_is_valid = false; 692 m_fpu_is_valid = false; 693 694 return WriteRegisterSet(&ioVec, GetSVEBufferSize(), NT_ARM_SVE); 695 } 696 697 void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() { 698 // ConfigureRegisterContext gets called from InvalidateAllRegisters 699 // on every stop and configures SVE vector length. 700 // If m_sve_state is set to SVEState::Disabled on first stop, code below will 701 // be deemed non operational for the lifetime of current process. 702 if (!m_sve_header_is_valid && m_sve_state != SVEState::Disabled) { 703 Status error = ReadSVEHeader(); 704 if (error.Success()) { 705 // If SVE is enabled thread can switch between SVEState::FPSIMD and 706 // SVEState::Full on every stop. 707 if ((m_sve_header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_FPSIMD) 708 m_sve_state = SVEState::FPSIMD; 709 else if ((m_sve_header.flags & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE) 710 m_sve_state = SVEState::Full; 711 712 // On every stop we configure SVE vector length by calling 713 // ConfigureVectorLength regardless of current SVEState of this thread. 714 uint32_t vq = RegisterInfoPOSIX_arm64::eVectorQuadwordAArch64SVE; 715 if (sve_vl_valid(m_sve_header.vl)) 716 vq = sve_vq_from_vl(m_sve_header.vl); 717 718 GetRegisterInfo().ConfigureVectorLength(vq); 719 m_sve_ptrace_payload.resize(SVE_PT_SIZE(vq, SVE_PT_REGS_SVE)); 720 } 721 } 722 } 723 724 uint32_t NativeRegisterContextLinux_arm64::CalculateFprOffset( 725 const RegisterInfo *reg_info) const { 726 return reg_info->byte_offset - GetGPRSize(); 727 } 728 729 uint32_t NativeRegisterContextLinux_arm64::CalculateSVEOffset( 730 const RegisterInfo *reg_info) const { 731 // Start of Z0 data is after GPRs plus 8 bytes of vg register 732 uint32_t sve_reg_offset = LLDB_INVALID_INDEX32; 733 if (m_sve_state == SVEState::FPSIMD) { 734 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 735 sve_reg_offset = 736 SVE_PT_FPSIMD_OFFSET + (reg - GetRegisterInfo().GetRegNumSVEZ0()) * 16; 737 } else if (m_sve_state == SVEState::Full) { 738 uint32_t sve_z0_offset = GetGPRSize() + 16; 739 sve_reg_offset = 740 SVE_SIG_REGS_OFFSET + reg_info->byte_offset - sve_z0_offset; 741 } 742 return sve_reg_offset; 743 } 744 745 void *NativeRegisterContextLinux_arm64::GetSVEBuffer() { 746 if (m_sve_state == SVEState::FPSIMD) 747 return m_sve_ptrace_payload.data() + SVE_PT_FPSIMD_OFFSET; 748 749 return m_sve_ptrace_payload.data(); 750 } 751 752 std::vector<uint32_t> NativeRegisterContextLinux_arm64::GetExpeditedRegisters( 753 ExpeditedRegs expType) const { 754 std::vector<uint32_t> expedited_reg_nums = 755 NativeRegisterContext::GetExpeditedRegisters(expType); 756 if (m_sve_state == SVEState::FPSIMD || m_sve_state == SVEState::Full) 757 expedited_reg_nums.push_back(GetRegisterInfo().GetRegNumSVEVG()); 758 759 return expedited_reg_nums; 760 } 761 762 #endif // defined (__arm64__) || defined (__aarch64__) 763