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