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