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 25 // System includes - They have to be included after framework includes because 26 // they define some macros which collide with variable names in other modules 27 #include <sys/socket.h> 28 // NT_PRSTATUS and NT_FPREGSET definition 29 #include <elf.h> 30 // user_hwdebug_state definition 31 #include <asm/ptrace.h> 32 33 #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize()) 34 35 using namespace lldb; 36 using namespace lldb_private; 37 using namespace lldb_private::process_linux; 38 39 std::unique_ptr<NativeRegisterContextLinux> 40 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( 41 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { 42 switch (target_arch.GetMachine()) { 43 case llvm::Triple::arm: 44 return std::make_unique<NativeRegisterContextLinux_arm>(target_arch, 45 native_thread); 46 case llvm::Triple::aarch64: 47 return std::make_unique<NativeRegisterContextLinux_arm64>(target_arch, 48 native_thread); 49 default: 50 llvm_unreachable("have no register context for architecture"); 51 } 52 } 53 54 NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64( 55 const ArchSpec &target_arch, NativeThreadProtocol &native_thread) 56 : NativeRegisterContextLinux(native_thread, 57 new RegisterInfoPOSIX_arm64(target_arch)) { 58 ::memset(&m_fpr, 0, sizeof(m_fpr)); 59 ::memset(&m_gpr_arm64, 0, sizeof(m_gpr_arm64)); 60 ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); 61 ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs)); 62 63 // 16 is just a maximum value, query hardware for actual watchpoint count 64 m_max_hwp_supported = 16; 65 m_max_hbp_supported = 16; 66 m_refresh_hwdebug_info = true; 67 68 m_gpr_is_valid = false; 69 m_fpu_is_valid = false; 70 } 71 72 RegisterInfoPOSIX_arm64 & 73 NativeRegisterContextLinux_arm64::GetRegisterInfo() const { 74 return static_cast<RegisterInfoPOSIX_arm64 &>(*m_register_info_interface_up); 75 } 76 77 uint32_t NativeRegisterContextLinux_arm64::GetRegisterSetCount() const { 78 return GetRegisterInfo().GetRegisterSetCount(); 79 } 80 81 const RegisterSet * 82 NativeRegisterContextLinux_arm64::GetRegisterSet(uint32_t set_index) const { 83 return GetRegisterInfo().GetRegisterSet(set_index); 84 } 85 86 uint32_t NativeRegisterContextLinux_arm64::GetUserRegisterCount() const { 87 uint32_t count = 0; 88 for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) 89 count += GetRegisterSet(set_index)->num_registers; 90 return count; 91 } 92 93 Status 94 NativeRegisterContextLinux_arm64::ReadRegister(const RegisterInfo *reg_info, 95 RegisterValue ®_value) { 96 Status error; 97 98 if (!reg_info) { 99 error.SetErrorString("reg_info NULL"); 100 return error; 101 } 102 103 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 104 105 if (reg == LLDB_INVALID_REGNUM) 106 return Status("no lldb regnum for %s", reg_info && reg_info->name 107 ? reg_info->name 108 : "<unknown register>"); 109 110 uint8_t *src; 111 uint32_t offset; 112 113 if (IsGPR(reg)) { 114 if (!m_gpr_is_valid) { 115 error = ReadGPR(); 116 if (error.Fail()) 117 return error; 118 } 119 120 offset = reg_info->byte_offset; 121 assert(offset < GetGPRSize()); 122 src = (uint8_t *)GetGPRBuffer() + offset; 123 124 } else if (IsFPR(reg)) { 125 if (!m_fpu_is_valid) { 126 127 error = ReadFPR(); 128 if (error.Fail()) 129 return error; 130 } 131 offset = CalculateFprOffset(reg_info); 132 assert(offset < GetFPRSize()); 133 src = (uint8_t *)GetFPRBuffer() + offset; 134 } else 135 return Status("failed - register wasn't recognized to be a GPR or an FPR, " 136 "write strategy unknown"); 137 138 reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, 139 eByteOrderLittle, error); 140 141 return error; 142 } 143 144 Status NativeRegisterContextLinux_arm64::WriteRegister( 145 const RegisterInfo *reg_info, const RegisterValue ®_value) { 146 Status error; 147 148 if (!reg_info) 149 return Status("reg_info NULL"); 150 151 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 152 153 if (reg == LLDB_INVALID_REGNUM) 154 return Status("no lldb regnum for %s", reg_info && reg_info->name 155 ? reg_info->name 156 : "<unknown register>"); 157 158 uint8_t *dst; 159 uint32_t offset; 160 161 if (IsGPR(reg)) { 162 if (!m_gpr_is_valid) { 163 error = ReadGPR(); 164 if (error.Fail()) 165 return error; 166 } 167 168 offset = reg_info->byte_offset; 169 assert(offset < GetGPRSize()); 170 dst = (uint8_t *)GetGPRBuffer() + offset; 171 172 ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); 173 174 return WriteGPR(); 175 } else if (IsFPR(reg)) { 176 if (!m_fpu_is_valid) { 177 error = ReadFPR(); 178 if (error.Fail()) 179 return error; 180 } 181 offset = CalculateFprOffset(reg_info); 182 assert(offset < GetFPRSize()); 183 dst = (uint8_t *)GetFPRBuffer() + offset; 184 185 ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); 186 187 return WriteFPR(); 188 } 189 190 return error; 191 } 192 193 Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues( 194 lldb::DataBufferSP &data_sp) { 195 Status error; 196 197 data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); 198 if (!m_gpr_is_valid) { 199 error = ReadGPR(); 200 if (error.Fail()) 201 return error; 202 } 203 204 if (!m_fpu_is_valid) { 205 error = ReadFPR(); 206 if (error.Fail()) 207 return error; 208 } 209 uint8_t *dst = data_sp->GetBytes(); 210 ::memcpy(dst, GetGPRBuffer(), GetGPRSize()); 211 dst += GetGPRSize(); 212 ::memcpy(dst, GetFPRBuffer(), GetFPRSize()); 213 214 return error; 215 } 216 217 Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues( 218 const lldb::DataBufferSP &data_sp) { 219 Status error; 220 221 if (!data_sp) { 222 error.SetErrorStringWithFormat( 223 "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", 224 __FUNCTION__); 225 return error; 226 } 227 228 if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { 229 error.SetErrorStringWithFormat( 230 "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched " 231 "data size, expected %" PRIu64 ", actual %" PRIu64, 232 __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); 233 return error; 234 } 235 236 uint8_t *src = data_sp->GetBytes(); 237 if (src == nullptr) { 238 error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " 239 "DataBuffer::GetBytes() returned a null " 240 "pointer", 241 __FUNCTION__); 242 return error; 243 } 244 ::memcpy(GetGPRBuffer(), src, GetRegisterInfoInterface().GetGPRSize()); 245 246 error = WriteGPR(); 247 if (error.Fail()) 248 return error; 249 250 src += GetRegisterInfoInterface().GetGPRSize(); 251 ::memcpy(GetFPRBuffer(), src, GetFPRSize()); 252 253 error = WriteFPR(); 254 if (error.Fail()) 255 return error; 256 257 return error; 258 } 259 260 bool NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const { 261 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) == 262 RegisterInfoPOSIX_arm64::GPRegSet) 263 return true; 264 return false; 265 } 266 267 bool NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const { 268 if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) == 269 RegisterInfoPOSIX_arm64::FPRegSet) 270 return true; 271 return false; 272 } 273 274 uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareBreakpoints() { 275 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 276 277 LLDB_LOGF(log, "NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 278 279 Status error; 280 281 // Read hardware breakpoint and watchpoint information. 282 error = ReadHardwareDebugInfo(); 283 284 if (error.Fail()) 285 return 0; 286 287 return m_max_hbp_supported; 288 } 289 290 uint32_t 291 NativeRegisterContextLinux_arm64::SetHardwareBreakpoint(lldb::addr_t addr, 292 size_t size) { 293 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 294 LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size); 295 296 // Read hardware breakpoint and watchpoint information. 297 Status error = ReadHardwareDebugInfo(); 298 299 if (error.Fail()) 300 return LLDB_INVALID_INDEX32; 301 302 uint32_t control_value = 0, bp_index = 0; 303 304 // Check if size has a valid hardware breakpoint length. 305 if (size != 4) 306 return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware 307 // breakpoint 308 309 // Check 4-byte alignment for hardware breakpoint target address. 310 if (addr & 0x03) 311 return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned. 312 313 // Setup control value 314 control_value = 0; 315 control_value |= ((1 << size) - 1) << 5; 316 control_value |= (2 << 1) | 1; 317 318 // Iterate over stored breakpoints and find a free bp_index 319 bp_index = LLDB_INVALID_INDEX32; 320 for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 321 if ((m_hbr_regs[i].control & 1) == 0) { 322 bp_index = i; // Mark last free slot 323 } else if (m_hbr_regs[i].address == addr) { 324 return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints. 325 } 326 } 327 328 if (bp_index == LLDB_INVALID_INDEX32) 329 return LLDB_INVALID_INDEX32; 330 331 // Update breakpoint in local cache 332 m_hbr_regs[bp_index].real_addr = addr; 333 m_hbr_regs[bp_index].address = addr; 334 m_hbr_regs[bp_index].control = control_value; 335 336 // PTRACE call to set corresponding hardware breakpoint register. 337 error = WriteHardwareDebugRegs(eDREGTypeBREAK); 338 339 if (error.Fail()) { 340 m_hbr_regs[bp_index].address = 0; 341 m_hbr_regs[bp_index].control &= ~1; 342 343 return LLDB_INVALID_INDEX32; 344 } 345 346 return bp_index; 347 } 348 349 bool NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint( 350 uint32_t hw_idx) { 351 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 352 LLDB_LOG(log, "hw_idx: {0}", hw_idx); 353 354 // Read hardware breakpoint and watchpoint information. 355 Status error = ReadHardwareDebugInfo(); 356 357 if (error.Fail()) 358 return false; 359 360 if (hw_idx >= m_max_hbp_supported) 361 return false; 362 363 // Create a backup we can revert to in case of failure. 364 lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address; 365 uint32_t tempControl = m_hbr_regs[hw_idx].control; 366 367 m_hbr_regs[hw_idx].control &= ~1; 368 m_hbr_regs[hw_idx].address = 0; 369 370 // PTRACE call to clear corresponding hardware breakpoint register. 371 error = WriteHardwareDebugRegs(eDREGTypeBREAK); 372 373 if (error.Fail()) { 374 m_hbr_regs[hw_idx].control = tempControl; 375 m_hbr_regs[hw_idx].address = tempAddr; 376 377 return false; 378 } 379 380 return true; 381 } 382 383 Status NativeRegisterContextLinux_arm64::GetHardwareBreakHitIndex( 384 uint32_t &bp_index, lldb::addr_t trap_addr) { 385 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 386 387 LLDB_LOGF(log, "NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 388 389 lldb::addr_t break_addr; 390 391 for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) { 392 break_addr = m_hbr_regs[bp_index].address; 393 394 if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) { 395 m_hbr_regs[bp_index].hit_addr = trap_addr; 396 return Status(); 397 } 398 } 399 400 bp_index = LLDB_INVALID_INDEX32; 401 return Status(); 402 } 403 404 Status NativeRegisterContextLinux_arm64::ClearAllHardwareBreakpoints() { 405 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); 406 407 LLDB_LOGF(log, "NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 408 409 Status error; 410 411 // Read hardware breakpoint and watchpoint information. 412 error = ReadHardwareDebugInfo(); 413 414 if (error.Fail()) 415 return error; 416 417 lldb::addr_t tempAddr = 0; 418 uint32_t tempControl = 0; 419 420 for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 421 if (m_hbr_regs[i].control & 0x01) { 422 // Create a backup we can revert to in case of failure. 423 tempAddr = m_hbr_regs[i].address; 424 tempControl = m_hbr_regs[i].control; 425 426 // Clear watchpoints in local cache 427 m_hbr_regs[i].control &= ~1; 428 m_hbr_regs[i].address = 0; 429 430 // Ptrace call to update hardware debug registers 431 error = WriteHardwareDebugRegs(eDREGTypeBREAK); 432 433 if (error.Fail()) { 434 m_hbr_regs[i].control = tempControl; 435 m_hbr_regs[i].address = tempAddr; 436 437 return error; 438 } 439 } 440 } 441 442 return Status(); 443 } 444 445 uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints() { 446 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 447 448 // Read hardware breakpoint and watchpoint information. 449 Status error = ReadHardwareDebugInfo(); 450 451 if (error.Fail()) 452 return 0; 453 454 LLDB_LOG(log, "{0}", m_max_hwp_supported); 455 return m_max_hwp_supported; 456 } 457 458 uint32_t NativeRegisterContextLinux_arm64::SetHardwareWatchpoint( 459 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 460 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 461 LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, 462 watch_flags); 463 464 // Read hardware breakpoint and watchpoint information. 465 Status error = ReadHardwareDebugInfo(); 466 467 if (error.Fail()) 468 return LLDB_INVALID_INDEX32; 469 470 uint32_t control_value = 0, wp_index = 0; 471 lldb::addr_t real_addr = addr; 472 473 // Check if we are setting watchpoint other than read/write/access Also 474 // update watchpoint flag to match AArch64 write-read bit configuration. 475 switch (watch_flags) { 476 case 1: 477 watch_flags = 2; 478 break; 479 case 2: 480 watch_flags = 1; 481 break; 482 case 3: 483 break; 484 default: 485 return LLDB_INVALID_INDEX32; 486 } 487 488 // Check if size has a valid hardware watchpoint length. 489 if (size != 1 && size != 2 && size != 4 && size != 8) 490 return LLDB_INVALID_INDEX32; 491 492 // Check 8-byte alignment for hardware watchpoint target address. Below is a 493 // hack to recalculate address and size in order to make sure we can watch 494 // non 8-byte aligned addresses as well. 495 if (addr & 0x07) { 496 uint8_t watch_mask = (addr & 0x07) + size; 497 498 if (watch_mask > 0x08) 499 return LLDB_INVALID_INDEX32; 500 else if (watch_mask <= 0x02) 501 size = 2; 502 else if (watch_mask <= 0x04) 503 size = 4; 504 else 505 size = 8; 506 507 addr = addr & (~0x07); 508 } 509 510 // Setup control value 511 control_value = watch_flags << 3; 512 control_value |= ((1 << size) - 1) << 5; 513 control_value |= (2 << 1) | 1; 514 515 // Iterate over stored watchpoints and find a free wp_index 516 wp_index = LLDB_INVALID_INDEX32; 517 for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 518 if ((m_hwp_regs[i].control & 1) == 0) { 519 wp_index = i; // Mark last free slot 520 } else if (m_hwp_regs[i].address == addr) { 521 return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. 522 } 523 } 524 525 if (wp_index == LLDB_INVALID_INDEX32) 526 return LLDB_INVALID_INDEX32; 527 528 // Update watchpoint in local cache 529 m_hwp_regs[wp_index].real_addr = real_addr; 530 m_hwp_regs[wp_index].address = addr; 531 m_hwp_regs[wp_index].control = control_value; 532 533 // PTRACE call to set corresponding watchpoint register. 534 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 535 536 if (error.Fail()) { 537 m_hwp_regs[wp_index].address = 0; 538 m_hwp_regs[wp_index].control &= ~1; 539 540 return LLDB_INVALID_INDEX32; 541 } 542 543 return wp_index; 544 } 545 546 bool NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint( 547 uint32_t wp_index) { 548 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 549 LLDB_LOG(log, "wp_index: {0}", wp_index); 550 551 // Read hardware breakpoint and watchpoint information. 552 Status error = ReadHardwareDebugInfo(); 553 554 if (error.Fail()) 555 return false; 556 557 if (wp_index >= m_max_hwp_supported) 558 return false; 559 560 // Create a backup we can revert to in case of failure. 561 lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; 562 uint32_t tempControl = m_hwp_regs[wp_index].control; 563 564 // Update watchpoint in local cache 565 m_hwp_regs[wp_index].control &= ~1; 566 m_hwp_regs[wp_index].address = 0; 567 568 // Ptrace call to update hardware debug registers 569 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 570 571 if (error.Fail()) { 572 m_hwp_regs[wp_index].control = tempControl; 573 m_hwp_regs[wp_index].address = tempAddr; 574 575 return false; 576 } 577 578 return true; 579 } 580 581 Status NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints() { 582 // Read hardware breakpoint and watchpoint information. 583 Status error = ReadHardwareDebugInfo(); 584 585 if (error.Fail()) 586 return error; 587 588 lldb::addr_t tempAddr = 0; 589 uint32_t tempControl = 0; 590 591 for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 592 if (m_hwp_regs[i].control & 0x01) { 593 // Create a backup we can revert to in case of failure. 594 tempAddr = m_hwp_regs[i].address; 595 tempControl = m_hwp_regs[i].control; 596 597 // Clear watchpoints in local cache 598 m_hwp_regs[i].control &= ~1; 599 m_hwp_regs[i].address = 0; 600 601 // Ptrace call to update hardware debug registers 602 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 603 604 if (error.Fail()) { 605 m_hwp_regs[i].control = tempControl; 606 m_hwp_regs[i].address = tempAddr; 607 608 return error; 609 } 610 } 611 } 612 613 return Status(); 614 } 615 616 uint32_t 617 NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) { 618 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 619 LLDB_LOG(log, "wp_index: {0}", wp_index); 620 621 switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) { 622 case 0x01: 623 return 1; 624 case 0x03: 625 return 2; 626 case 0x0f: 627 return 4; 628 case 0xff: 629 return 8; 630 default: 631 return 0; 632 } 633 } 634 bool NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) { 635 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 636 LLDB_LOG(log, "wp_index: {0}", wp_index); 637 638 if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) 639 return true; 640 else 641 return false; 642 } 643 644 Status NativeRegisterContextLinux_arm64::GetWatchpointHitIndex( 645 uint32_t &wp_index, lldb::addr_t trap_addr) { 646 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 647 LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); 648 649 uint32_t watch_size; 650 lldb::addr_t watch_addr; 651 652 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { 653 watch_size = GetWatchpointSize(wp_index); 654 watch_addr = m_hwp_regs[wp_index].address; 655 656 if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && 657 trap_addr < watch_addr + watch_size) { 658 m_hwp_regs[wp_index].hit_addr = trap_addr; 659 return Status(); 660 } 661 } 662 663 wp_index = LLDB_INVALID_INDEX32; 664 return Status(); 665 } 666 667 lldb::addr_t 668 NativeRegisterContextLinux_arm64::GetWatchpointAddress(uint32_t wp_index) { 669 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 670 LLDB_LOG(log, "wp_index: {0}", wp_index); 671 672 if (wp_index >= m_max_hwp_supported) 673 return LLDB_INVALID_ADDRESS; 674 675 if (WatchpointIsEnabled(wp_index)) 676 return m_hwp_regs[wp_index].real_addr; 677 else 678 return LLDB_INVALID_ADDRESS; 679 } 680 681 lldb::addr_t 682 NativeRegisterContextLinux_arm64::GetWatchpointHitAddress(uint32_t wp_index) { 683 Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); 684 LLDB_LOG(log, "wp_index: {0}", wp_index); 685 686 if (wp_index >= m_max_hwp_supported) 687 return LLDB_INVALID_ADDRESS; 688 689 if (WatchpointIsEnabled(wp_index)) 690 return m_hwp_regs[wp_index].hit_addr; 691 else 692 return LLDB_INVALID_ADDRESS; 693 } 694 695 Status NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() { 696 if (!m_refresh_hwdebug_info) { 697 return Status(); 698 } 699 700 ::pid_t tid = m_thread.GetID(); 701 702 int regset = NT_ARM_HW_WATCH; 703 struct iovec ioVec; 704 struct user_hwdebug_state dreg_state; 705 Status error; 706 707 ioVec.iov_base = &dreg_state; 708 ioVec.iov_len = sizeof(dreg_state); 709 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, 710 &ioVec, ioVec.iov_len); 711 712 if (error.Fail()) 713 return error; 714 715 m_max_hwp_supported = dreg_state.dbg_info & 0xff; 716 717 regset = NT_ARM_HW_BREAK; 718 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, 719 &ioVec, ioVec.iov_len); 720 721 if (error.Fail()) 722 return error; 723 724 m_max_hbp_supported = dreg_state.dbg_info & 0xff; 725 m_refresh_hwdebug_info = false; 726 727 return error; 728 } 729 730 Status NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) { 731 struct iovec ioVec; 732 struct user_hwdebug_state dreg_state; 733 Status error; 734 735 memset(&dreg_state, 0, sizeof(dreg_state)); 736 ioVec.iov_base = &dreg_state; 737 738 if (hwbType == eDREGTypeWATCH) { 739 hwbType = NT_ARM_HW_WATCH; 740 ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + 741 (sizeof(dreg_state.dbg_regs[0]) * m_max_hwp_supported); 742 743 for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 744 dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address; 745 dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control; 746 } 747 } else { 748 hwbType = NT_ARM_HW_BREAK; 749 ioVec.iov_len = sizeof(dreg_state.dbg_info) + sizeof(dreg_state.pad) + 750 (sizeof(dreg_state.dbg_regs[0]) * m_max_hbp_supported); 751 752 for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 753 dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address; 754 dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control; 755 } 756 } 757 758 return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), 759 &hwbType, &ioVec, ioVec.iov_len); 760 } 761 762 Status NativeRegisterContextLinux_arm64::ReadGPR() { 763 Status error; 764 765 struct iovec ioVec; 766 767 ioVec.iov_base = GetGPRBuffer(); 768 ioVec.iov_len = GetGPRSize(); 769 770 error = ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS); 771 772 if (error.Success()) 773 m_gpr_is_valid = true; 774 775 return error; 776 } 777 778 Status NativeRegisterContextLinux_arm64::WriteGPR() { 779 struct iovec ioVec; 780 781 m_gpr_is_valid = false; 782 783 ioVec.iov_base = GetGPRBuffer(); 784 ioVec.iov_len = GetGPRSize(); 785 786 return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS); 787 } 788 789 Status NativeRegisterContextLinux_arm64::ReadFPR() { 790 Status error; 791 792 struct iovec ioVec; 793 794 ioVec.iov_base = GetFPRBuffer(); 795 ioVec.iov_len = GetFPRSize(); 796 797 error = ReadRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET); 798 799 if (error.Success()) 800 m_fpu_is_valid = true; 801 802 return error; 803 } 804 805 Status NativeRegisterContextLinux_arm64::WriteFPR() { 806 struct iovec ioVec; 807 808 m_fpu_is_valid = false; 809 810 ioVec.iov_base = GetFPRBuffer(); 811 ioVec.iov_len = GetFPRSize(); 812 813 return WriteRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET); 814 } 815 816 void NativeRegisterContextLinux_arm64::InvalidateAllRegisters() { 817 m_gpr_is_valid = false; 818 m_fpu_is_valid = false; 819 } 820 821 uint32_t NativeRegisterContextLinux_arm64::CalculateFprOffset( 822 const RegisterInfo *reg_info) const { 823 return reg_info->byte_offset - GetGPRSize(); 824 } 825 826 #endif // defined (__arm64__) || defined (__aarch64__) 827