1 //===-- NativeRegisterContextLinux_arm64.cpp --------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #if defined (__arm64__) || defined (__aarch64__) 11 12 #include "NativeRegisterContextLinux_arm.h" 13 #include "NativeRegisterContextLinux_arm64.h" 14 15 // C Includes 16 // C++ Includes 17 18 // Other libraries and framework includes 19 #include "lldb/Core/DataBufferHeap.h" 20 #include "lldb/Core/Error.h" 21 #include "lldb/Core/Log.h" 22 #include "lldb/Core/RegisterValue.h" 23 #include "lldb/Host/common/NativeProcessProtocol.h" 24 25 #include "Plugins/Process/Linux/NativeProcessLinux.h" 26 #include "Plugins/Process/Linux/Procfs.h" 27 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 28 #include "Plugins/Process/Utility/RegisterContextLinux_arm64.h" 29 30 // System includes - They have to be included after framework includes because they define some 31 // macros which collide with variable names in other modules 32 #include <sys/socket.h> 33 // NT_PRSTATUS and NT_FPREGSET definition 34 #include <elf.h> 35 // user_hwdebug_state definition 36 #include <asm/ptrace.h> 37 38 #define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize()) 39 40 using namespace lldb; 41 using namespace lldb_private; 42 using namespace lldb_private::process_linux; 43 44 // ARM64 general purpose registers. 45 static const uint32_t g_gpr_regnums_arm64[] = 46 { 47 gpr_x0_arm64, 48 gpr_x1_arm64, 49 gpr_x2_arm64, 50 gpr_x3_arm64, 51 gpr_x4_arm64, 52 gpr_x5_arm64, 53 gpr_x6_arm64, 54 gpr_x7_arm64, 55 gpr_x8_arm64, 56 gpr_x9_arm64, 57 gpr_x10_arm64, 58 gpr_x11_arm64, 59 gpr_x12_arm64, 60 gpr_x13_arm64, 61 gpr_x14_arm64, 62 gpr_x15_arm64, 63 gpr_x16_arm64, 64 gpr_x17_arm64, 65 gpr_x18_arm64, 66 gpr_x19_arm64, 67 gpr_x20_arm64, 68 gpr_x21_arm64, 69 gpr_x22_arm64, 70 gpr_x23_arm64, 71 gpr_x24_arm64, 72 gpr_x25_arm64, 73 gpr_x26_arm64, 74 gpr_x27_arm64, 75 gpr_x28_arm64, 76 gpr_fp_arm64, 77 gpr_lr_arm64, 78 gpr_sp_arm64, 79 gpr_pc_arm64, 80 gpr_cpsr_arm64, 81 LLDB_INVALID_REGNUM // register sets need to end with this flag 82 }; 83 static_assert(((sizeof g_gpr_regnums_arm64 / sizeof g_gpr_regnums_arm64[0]) - 1) == k_num_gpr_registers_arm64, \ 84 "g_gpr_regnums_arm64 has wrong number of register infos"); 85 86 // ARM64 floating point registers. 87 static const uint32_t g_fpu_regnums_arm64[] = 88 { 89 fpu_v0_arm64, 90 fpu_v1_arm64, 91 fpu_v2_arm64, 92 fpu_v3_arm64, 93 fpu_v4_arm64, 94 fpu_v5_arm64, 95 fpu_v6_arm64, 96 fpu_v7_arm64, 97 fpu_v8_arm64, 98 fpu_v9_arm64, 99 fpu_v10_arm64, 100 fpu_v11_arm64, 101 fpu_v12_arm64, 102 fpu_v13_arm64, 103 fpu_v14_arm64, 104 fpu_v15_arm64, 105 fpu_v16_arm64, 106 fpu_v17_arm64, 107 fpu_v18_arm64, 108 fpu_v19_arm64, 109 fpu_v20_arm64, 110 fpu_v21_arm64, 111 fpu_v22_arm64, 112 fpu_v23_arm64, 113 fpu_v24_arm64, 114 fpu_v25_arm64, 115 fpu_v26_arm64, 116 fpu_v27_arm64, 117 fpu_v28_arm64, 118 fpu_v29_arm64, 119 fpu_v30_arm64, 120 fpu_v31_arm64, 121 fpu_fpsr_arm64, 122 fpu_fpcr_arm64, 123 LLDB_INVALID_REGNUM // register sets need to end with this flag 124 }; 125 static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers_arm64, \ 126 "g_fpu_regnums_arm64 has wrong number of register infos"); 127 128 namespace { 129 // Number of register sets provided by this context. 130 enum 131 { 132 k_num_register_sets = 2 133 }; 134 } 135 136 // Register sets for ARM64. 137 static const RegisterSet 138 g_reg_sets_arm64[k_num_register_sets] = 139 { 140 { "General Purpose Registers", "gpr", k_num_gpr_registers_arm64, g_gpr_regnums_arm64 }, 141 { "Floating Point Registers", "fpu", k_num_fpr_registers_arm64, g_fpu_regnums_arm64 } 142 }; 143 144 NativeRegisterContextLinux* 145 NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& target_arch, 146 NativeThreadProtocol &native_thread, 147 uint32_t concrete_frame_idx) 148 { 149 Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS); 150 switch (target_arch.GetMachine()) 151 { 152 case llvm::Triple::arm: 153 return new NativeRegisterContextLinux_arm(target_arch, native_thread, concrete_frame_idx); 154 case llvm::Triple::aarch64: 155 return new NativeRegisterContextLinux_arm64(target_arch, native_thread, concrete_frame_idx); 156 default: 157 if (log) 158 log->Printf("NativeRegisterContextLinux::%s() have no register context for architecture: %s\n", __FUNCTION__, 159 target_arch.GetTriple().getArchName().str().c_str()); 160 return nullptr; 161 } 162 } 163 164 NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64 (const ArchSpec& target_arch, 165 NativeThreadProtocol &native_thread, 166 uint32_t concrete_frame_idx) : 167 NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_arm64(target_arch)) 168 { 169 switch (target_arch.GetMachine()) 170 { 171 case llvm::Triple::aarch64: 172 m_reg_info.num_registers = k_num_registers_arm64; 173 m_reg_info.num_gpr_registers = k_num_gpr_registers_arm64; 174 m_reg_info.num_fpr_registers = k_num_fpr_registers_arm64; 175 m_reg_info.last_gpr = k_last_gpr_arm64; 176 m_reg_info.first_fpr = k_first_fpr_arm64; 177 m_reg_info.last_fpr = k_last_fpr_arm64; 178 m_reg_info.first_fpr_v = fpu_v0_arm64; 179 m_reg_info.last_fpr_v = fpu_v31_arm64; 180 m_reg_info.gpr_flags = gpr_cpsr_arm64; 181 break; 182 default: 183 assert(false && "Unhandled target architecture."); 184 break; 185 } 186 187 ::memset(&m_fpr, 0, sizeof (m_fpr)); 188 ::memset(&m_gpr_arm64, 0, sizeof (m_gpr_arm64)); 189 ::memset(&m_hwp_regs, 0, sizeof (m_hwp_regs)); 190 191 // 16 is just a maximum value, query hardware for actual watchpoint count 192 m_max_hwp_supported = 16; 193 m_max_hbp_supported = 16; 194 m_refresh_hwdebug_info = true; 195 } 196 197 uint32_t 198 NativeRegisterContextLinux_arm64::GetRegisterSetCount () const 199 { 200 return k_num_register_sets; 201 } 202 203 const RegisterSet * 204 NativeRegisterContextLinux_arm64::GetRegisterSet (uint32_t set_index) const 205 { 206 if (set_index < k_num_register_sets) 207 return &g_reg_sets_arm64[set_index]; 208 209 return nullptr; 210 } 211 212 uint32_t 213 NativeRegisterContextLinux_arm64::GetUserRegisterCount() const 214 { 215 uint32_t count = 0; 216 for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) 217 count += g_reg_sets_arm64[set_index].num_registers; 218 return count; 219 } 220 221 Error 222 NativeRegisterContextLinux_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) 223 { 224 Error error; 225 226 if (!reg_info) 227 { 228 error.SetErrorString ("reg_info NULL"); 229 return error; 230 } 231 232 const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; 233 234 if (IsFPR(reg)) 235 { 236 error = ReadFPR(); 237 if (error.Fail()) 238 return error; 239 } 240 else 241 { 242 uint32_t full_reg = reg; 243 bool is_subreg = reg_info->invalidate_regs && (reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM); 244 245 if (is_subreg) 246 { 247 // Read the full aligned 64-bit register. 248 full_reg = reg_info->invalidate_regs[0]; 249 } 250 251 error = ReadRegisterRaw(full_reg, reg_value); 252 253 if (error.Success ()) 254 { 255 // If our read was not aligned (for ah,bh,ch,dh), shift our returned value one byte to the right. 256 if (is_subreg && (reg_info->byte_offset & 0x1)) 257 reg_value.SetUInt64(reg_value.GetAsUInt64() >> 8); 258 259 // If our return byte size was greater than the return value reg size, then 260 // use the type specified by reg_info rather than the uint64_t default 261 if (reg_value.GetByteSize() > reg_info->byte_size) 262 reg_value.SetType(reg_info); 263 } 264 return error; 265 } 266 267 // Get pointer to m_fpr variable and set the data from it. 268 uint32_t fpr_offset = CalculateFprOffset(reg_info); 269 assert (fpr_offset < sizeof m_fpr); 270 uint8_t *src = (uint8_t *)&m_fpr + fpr_offset; 271 reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, eByteOrderLittle, error); 272 273 return error; 274 } 275 276 Error 277 NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) 278 { 279 if (!reg_info) 280 return Error ("reg_info NULL"); 281 282 const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; 283 if (reg_index == LLDB_INVALID_REGNUM) 284 return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>"); 285 286 if (IsGPR(reg_index)) 287 return WriteRegisterRaw(reg_index, reg_value); 288 289 if (IsFPR(reg_index)) 290 { 291 // Get pointer to m_fpr variable and set the data to it. 292 uint32_t fpr_offset = CalculateFprOffset(reg_info); 293 assert (fpr_offset < sizeof m_fpr); 294 uint8_t *dst = (uint8_t *)&m_fpr + fpr_offset; 295 switch (reg_info->byte_size) 296 { 297 case 2: 298 *(uint16_t *)dst = reg_value.GetAsUInt16(); 299 break; 300 case 4: 301 *(uint32_t *)dst = reg_value.GetAsUInt32(); 302 break; 303 case 8: 304 *(uint64_t *)dst = reg_value.GetAsUInt64(); 305 break; 306 default: 307 assert(false && "Unhandled data size."); 308 return Error ("unhandled register data size %" PRIu32, reg_info->byte_size); 309 } 310 311 Error error = WriteFPR(); 312 if (error.Fail()) 313 return error; 314 315 return Error (); 316 } 317 318 return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown"); 319 } 320 321 Error 322 NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) 323 { 324 Error error; 325 326 data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); 327 if (!data_sp) 328 return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE); 329 330 error = ReadGPR(); 331 if (error.Fail()) 332 return error; 333 334 error = ReadFPR(); 335 if (error.Fail()) 336 return error; 337 338 uint8_t *dst = data_sp->GetBytes (); 339 if (dst == nullptr) 340 { 341 error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE); 342 return error; 343 } 344 345 ::memcpy (dst, &m_gpr_arm64, GetGPRSize()); 346 dst += GetGPRSize(); 347 ::memcpy (dst, &m_fpr, sizeof(m_fpr)); 348 349 return error; 350 } 351 352 Error 353 NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) 354 { 355 Error error; 356 357 if (!data_sp) 358 { 359 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__); 360 return error; 361 } 362 363 if (data_sp->GetByteSize () != REG_CONTEXT_SIZE) 364 { 365 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ()); 366 return error; 367 } 368 369 370 uint8_t *src = data_sp->GetBytes (); 371 if (src == nullptr) 372 { 373 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__); 374 return error; 375 } 376 ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ()); 377 378 error = WriteGPR(); 379 if (error.Fail()) 380 return error; 381 382 src += GetRegisterInfoInterface ().GetGPRSize (); 383 ::memcpy (&m_fpr, src, sizeof(m_fpr)); 384 385 error = WriteFPR(); 386 if (error.Fail()) 387 return error; 388 389 return error; 390 } 391 392 bool 393 NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const 394 { 395 return reg <= m_reg_info.last_gpr; // GPR's come first. 396 } 397 398 bool 399 NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const 400 { 401 return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); 402 } 403 404 uint32_t 405 NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) 406 { 407 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 408 409 if (log) 410 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 411 412 Error error; 413 414 // Read hardware breakpoint and watchpoint information. 415 error = ReadHardwareDebugInfo (); 416 417 if (error.Fail()) 418 return LLDB_INVALID_INDEX32; 419 420 uint32_t control_value = 0, bp_index = 0; 421 422 // Check if size has a valid hardware breakpoint length. 423 if (size != 4) 424 return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware breakpoint 425 426 // Check 4-byte alignment for hardware breakpoint target address. 427 if (addr & 0x03) 428 return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned. 429 430 // Setup control value 431 control_value = 0; 432 control_value |= ((1 << size) - 1) << 5; 433 control_value |= (2 << 1) | 1; 434 435 // Iterate over stored hardware breakpoints 436 // Find a free bp_index or update reference count if duplicate. 437 bp_index = LLDB_INVALID_INDEX32; 438 for (uint32_t i = 0; i < m_max_hbp_supported; i++) 439 { 440 if ((m_hbr_regs[i].control & 1) == 0) 441 { 442 bp_index = i; // Mark last free slot 443 } 444 else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value) 445 { 446 bp_index = i; // Mark duplicate index 447 break; // Stop searching here 448 } 449 } 450 451 if (bp_index == LLDB_INVALID_INDEX32) 452 return LLDB_INVALID_INDEX32; 453 454 // Add new or update existing breakpoint 455 if ((m_hbr_regs[bp_index].control & 1) == 0) 456 { 457 m_hbr_regs[bp_index].address = addr; 458 m_hbr_regs[bp_index].control = control_value; 459 m_hbr_regs[bp_index].refcount = 1; 460 461 // PTRACE call to set corresponding hardware breakpoint register. 462 error = WriteHardwareDebugRegs(eDREGTypeBREAK); 463 464 if (error.Fail()) 465 { 466 m_hbr_regs[bp_index].address = 0; 467 m_hbr_regs[bp_index].control &= ~1; 468 m_hbr_regs[bp_index].refcount = 0; 469 470 return LLDB_INVALID_INDEX32; 471 } 472 } 473 else 474 m_hbr_regs[bp_index].refcount++; 475 476 return bp_index; 477 } 478 479 bool 480 NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint (uint32_t hw_idx) 481 { 482 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 483 484 if (log) 485 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 486 487 Error error; 488 489 // Read hardware breakpoint and watchpoint information. 490 error = ReadHardwareDebugInfo (); 491 492 if (error.Fail()) 493 return false; 494 495 if (hw_idx >= m_max_hbp_supported) 496 return false; 497 498 // Update reference count if multiple references. 499 if (m_hbr_regs[hw_idx].refcount > 1) 500 { 501 m_hbr_regs[hw_idx].refcount--; 502 return true; 503 } 504 else if (m_hbr_regs[hw_idx].refcount == 1) 505 { 506 // Create a backup we can revert to in case of failure. 507 lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address; 508 uint32_t tempControl = m_hbr_regs[hw_idx].control; 509 uint32_t tempRefCount = m_hbr_regs[hw_idx].refcount; 510 511 m_hbr_regs[hw_idx].control &= ~1; 512 m_hbr_regs[hw_idx].address = 0; 513 m_hbr_regs[hw_idx].refcount = 0; 514 515 // PTRACE call to clear corresponding hardware breakpoint register. 516 WriteHardwareDebugRegs(eDREGTypeBREAK); 517 518 if (error.Fail()) 519 { 520 m_hbr_regs[hw_idx].control = tempControl; 521 m_hbr_regs[hw_idx].address = tempAddr; 522 m_hbr_regs[hw_idx].refcount = tempRefCount; 523 524 return false; 525 } 526 527 return true; 528 } 529 530 return false; 531 } 532 533 uint32_t 534 NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints () 535 { 536 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 537 538 if (log) 539 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 540 541 Error error; 542 543 // Read hardware breakpoint and watchpoint information. 544 error = ReadHardwareDebugInfo (); 545 546 if (error.Fail()) 547 return LLDB_INVALID_INDEX32; 548 549 return m_max_hwp_supported; 550 } 551 552 uint32_t 553 NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags) 554 { 555 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 556 557 if (log) 558 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 559 560 Error error; 561 562 // Read hardware breakpoint and watchpoint information. 563 error = ReadHardwareDebugInfo (); 564 565 if (error.Fail()) 566 return LLDB_INVALID_INDEX32; 567 568 uint32_t control_value = 0, wp_index = 0; 569 lldb::addr_t real_addr = addr; 570 571 // Check if we are setting watchpoint other than read/write/access 572 // Also update watchpoint flag to match AArch64 write-read bit configuration. 573 switch (watch_flags) 574 { 575 case 1: 576 watch_flags = 2; 577 break; 578 case 2: 579 watch_flags = 1; 580 break; 581 case 3: 582 break; 583 default: 584 return LLDB_INVALID_INDEX32; 585 } 586 587 // Check if size has a valid hardware watchpoint length. 588 if (size != 1 && size != 2 && size != 4 && size != 8) 589 return LLDB_INVALID_INDEX32; 590 591 // Check 8-byte alignment for hardware watchpoint target address. 592 // Below is a hack to recalculate address and size in order to 593 // make sure we can watch non 8-byte alligned addresses as well. 594 if (addr & 0x07) 595 { 596 uint8_t watch_mask = (addr & 0x07) + size; 597 598 if (watch_mask > 0x08) 599 return LLDB_INVALID_INDEX32; 600 else if (watch_mask <= 0x02) 601 size = 2; 602 else if (watch_mask <= 0x04) 603 size = 4; 604 else 605 size = 8; 606 607 addr = addr & (~0x07); 608 } 609 610 // Setup control value 611 control_value = watch_flags << 3; 612 control_value |= ((1 << size) - 1) << 5; 613 control_value |= (2 << 1) | 1; 614 615 // Iterate over stored watchpoints 616 // Find a free wp_index or update reference count if duplicate. 617 wp_index = LLDB_INVALID_INDEX32; 618 for (uint32_t i = 0; i < m_max_hwp_supported; i++) 619 { 620 if ((m_hwp_regs[i].control & 1) == 0) 621 { 622 wp_index = i; // Mark last free slot 623 } 624 else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value) 625 { 626 wp_index = i; // Mark duplicate index 627 break; // Stop searching here 628 } 629 } 630 631 if (wp_index == LLDB_INVALID_INDEX32) 632 return LLDB_INVALID_INDEX32; 633 634 // Add new or update existing watchpoint 635 if ((m_hwp_regs[wp_index].control & 1) == 0) 636 { 637 // Update watchpoint in local cache 638 m_hwp_regs[wp_index].real_addr = real_addr; 639 m_hwp_regs[wp_index].address = addr; 640 m_hwp_regs[wp_index].control = control_value; 641 m_hwp_regs[wp_index].refcount = 1; 642 643 // PTRACE call to set corresponding watchpoint register. 644 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 645 646 if (error.Fail()) 647 { 648 m_hwp_regs[wp_index].address = 0; 649 m_hwp_regs[wp_index].control &= ~1; 650 m_hwp_regs[wp_index].refcount = 0; 651 652 return LLDB_INVALID_INDEX32; 653 } 654 } 655 else 656 m_hwp_regs[wp_index].refcount++; 657 658 return wp_index; 659 } 660 661 bool 662 NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index) 663 { 664 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 665 666 if (log) 667 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 668 669 Error error; 670 671 // Read hardware breakpoint and watchpoint information. 672 error = ReadHardwareDebugInfo (); 673 674 if (error.Fail()) 675 return false; 676 677 if (wp_index >= m_max_hwp_supported) 678 return false; 679 680 // Update reference count if multiple references. 681 if (m_hwp_regs[wp_index].refcount > 1) 682 { 683 m_hwp_regs[wp_index].refcount--; 684 return true; 685 } 686 else if (m_hwp_regs[wp_index].refcount == 1) 687 { 688 // Create a backup we can revert to in case of failure. 689 lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; 690 uint32_t tempControl = m_hwp_regs[wp_index].control; 691 uint32_t tempRefCount = m_hwp_regs[wp_index].refcount; 692 693 // Update watchpoint in local cache 694 m_hwp_regs[wp_index].control &= ~1; 695 m_hwp_regs[wp_index].address = 0; 696 m_hwp_regs[wp_index].refcount = 0; 697 698 // Ptrace call to update hardware debug registers 699 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 700 701 if (error.Fail()) 702 { 703 m_hwp_regs[wp_index].control = tempControl; 704 m_hwp_regs[wp_index].address = tempAddr; 705 m_hwp_regs[wp_index].refcount = tempRefCount; 706 707 return false; 708 } 709 710 return true; 711 } 712 713 return false; 714 } 715 716 Error 717 NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints () 718 { 719 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 720 721 if (log) 722 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 723 724 Error error; 725 726 // Read hardware breakpoint and watchpoint information. 727 error = ReadHardwareDebugInfo (); 728 729 if (error.Fail()) 730 return error; 731 732 lldb::addr_t tempAddr = 0; 733 uint32_t tempControl = 0, tempRefCount = 0; 734 735 for (uint32_t i = 0; i < m_max_hwp_supported; i++) 736 { 737 if (m_hwp_regs[i].control & 0x01) 738 { 739 // Create a backup we can revert to in case of failure. 740 tempAddr = m_hwp_regs[i].address; 741 tempControl = m_hwp_regs[i].control; 742 tempRefCount = m_hwp_regs[i].refcount; 743 744 // Clear watchpoints in local cache 745 m_hwp_regs[i].control &= ~1; 746 m_hwp_regs[i].address = 0; 747 m_hwp_regs[i].refcount = 0; 748 749 // Ptrace call to update hardware debug registers 750 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 751 752 if (error.Fail()) 753 { 754 m_hwp_regs[i].control = tempControl; 755 m_hwp_regs[i].address = tempAddr; 756 m_hwp_regs[i].refcount = tempRefCount; 757 758 return error; 759 } 760 } 761 } 762 763 return Error(); 764 } 765 766 uint32_t 767 NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) 768 { 769 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 770 771 if (log) 772 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 773 switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) 774 { 775 case 0x01: 776 return 1; 777 case 0x03: 778 return 2; 779 case 0x0f: 780 return 4; 781 case 0xff: 782 return 8; 783 default: 784 return 0; 785 } 786 } 787 bool 788 NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) 789 { 790 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 791 792 if (log) 793 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 794 795 if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) 796 return true; 797 else 798 return false; 799 } 800 801 Error 802 NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) 803 { 804 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 805 806 if (log) 807 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 808 809 uint32_t watch_size; 810 lldb::addr_t watch_addr; 811 812 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) 813 { 814 watch_size = GetWatchpointSize (wp_index); 815 watch_addr = m_hwp_regs[wp_index].address; 816 817 if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index) 818 && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size) 819 { 820 m_hwp_regs[wp_index].hit_addr = trap_addr; 821 return Error(); 822 } 823 } 824 825 wp_index = LLDB_INVALID_INDEX32; 826 return Error(); 827 } 828 829 lldb::addr_t 830 NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index) 831 { 832 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 833 834 if (log) 835 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 836 837 if (wp_index >= m_max_hwp_supported) 838 return LLDB_INVALID_ADDRESS; 839 840 if (WatchpointIsEnabled(wp_index)) 841 return m_hwp_regs[wp_index].real_addr; 842 else 843 return LLDB_INVALID_ADDRESS; 844 } 845 846 lldb::addr_t 847 NativeRegisterContextLinux_arm64::GetWatchpointHitAddress (uint32_t wp_index) 848 { 849 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 850 851 if (log) 852 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 853 854 if (wp_index >= m_max_hwp_supported) 855 return LLDB_INVALID_ADDRESS; 856 857 if (WatchpointIsEnabled(wp_index)) 858 return m_hwp_regs[wp_index].hit_addr; 859 else 860 return LLDB_INVALID_ADDRESS; 861 } 862 863 Error 864 NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() 865 { 866 if (!m_refresh_hwdebug_info) 867 { 868 return Error(); 869 } 870 871 ::pid_t tid = m_thread.GetID(); 872 873 int regset = NT_ARM_HW_WATCH; 874 struct iovec ioVec; 875 struct user_hwdebug_state dreg_state; 876 Error error; 877 878 ioVec.iov_base = &dreg_state; 879 ioVec.iov_len = sizeof (dreg_state); 880 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); 881 882 if (error.Fail()) 883 return error; 884 885 m_max_hwp_supported = dreg_state.dbg_info & 0xff; 886 887 regset = NT_ARM_HW_BREAK; 888 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); 889 890 if (error.Fail()) 891 return error; 892 893 m_max_hbp_supported = dreg_state.dbg_info & 0xff; 894 m_refresh_hwdebug_info = false; 895 896 return error; 897 } 898 899 Error 900 NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) 901 { 902 struct iovec ioVec; 903 struct user_hwdebug_state dreg_state; 904 Error error; 905 906 memset (&dreg_state, 0, sizeof (dreg_state)); 907 ioVec.iov_base = &dreg_state; 908 909 if (hwbType == eDREGTypeWATCH) 910 { 911 hwbType = NT_ARM_HW_WATCH; 912 ioVec.iov_len = sizeof (dreg_state.dbg_info) + sizeof (dreg_state.pad) 913 + (sizeof (dreg_state.dbg_regs [0]) * m_max_hwp_supported); 914 915 for (uint32_t i = 0; i < m_max_hwp_supported; i++) 916 { 917 dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address; 918 dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control; 919 } 920 } 921 else 922 { 923 hwbType = NT_ARM_HW_BREAK; 924 ioVec.iov_len = sizeof (dreg_state.dbg_info) + sizeof (dreg_state.pad) 925 + (sizeof (dreg_state.dbg_regs [0]) * m_max_hbp_supported); 926 927 for (uint32_t i = 0; i < m_max_hbp_supported; i++) 928 { 929 dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address; 930 dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control; 931 } 932 } 933 934 return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &hwbType, &ioVec, ioVec.iov_len); 935 } 936 937 Error 938 NativeRegisterContextLinux_arm64::DoReadRegisterValue(uint32_t offset, 939 const char* reg_name, 940 uint32_t size, 941 RegisterValue &value) 942 { 943 Error error; 944 if (offset > sizeof(struct user_pt_regs)) 945 { 946 uintptr_t offset = offset - sizeof(struct user_pt_regs); 947 if (offset > sizeof(struct user_fpsimd_state)) 948 { 949 error.SetErrorString("invalid offset value"); 950 return error; 951 } 952 elf_fpregset_t regs; 953 int regset = NT_FPREGSET; 954 struct iovec ioVec; 955 956 ioVec.iov_base = ®s; 957 ioVec.iov_len = sizeof regs; 958 error = NativeProcessLinux::PtraceWrapper( 959 PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 960 if (error.Success()) 961 { 962 ArchSpec arch; 963 if (m_thread.GetProcess()->GetArchitecture(arch)) 964 value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, arch.GetByteOrder()); 965 else 966 error.SetErrorString("failed to get architecture"); 967 } 968 } 969 else 970 { 971 elf_gregset_t regs; 972 int regset = NT_PRSTATUS; 973 struct iovec ioVec; 974 975 ioVec.iov_base = ®s; 976 ioVec.iov_len = sizeof regs; 977 error = NativeProcessLinux::PtraceWrapper( 978 PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 979 if (error.Success()) 980 { 981 ArchSpec arch; 982 if (m_thread.GetProcess()->GetArchitecture(arch)) 983 value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder()); 984 else 985 error.SetErrorString("failed to get architecture"); 986 } 987 } 988 return error; 989 } 990 991 Error 992 NativeRegisterContextLinux_arm64::DoWriteRegisterValue(uint32_t offset, 993 const char* reg_name, 994 const RegisterValue &value) 995 { 996 Error error; 997 ::pid_t tid = m_thread.GetID(); 998 if (offset > sizeof(struct user_pt_regs)) 999 { 1000 uintptr_t offset = offset - sizeof(struct user_pt_regs); 1001 if (offset > sizeof(struct user_fpsimd_state)) 1002 { 1003 error.SetErrorString("invalid offset value"); 1004 return error; 1005 } 1006 elf_fpregset_t regs; 1007 int regset = NT_FPREGSET; 1008 struct iovec ioVec; 1009 1010 ioVec.iov_base = ®s; 1011 ioVec.iov_len = sizeof regs; 1012 error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, tid, ®set, &ioVec, sizeof regs); 1013 1014 if (error.Success()) 1015 { 1016 ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 16); 1017 error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, &ioVec, sizeof regs); 1018 } 1019 } 1020 else 1021 { 1022 elf_gregset_t regs; 1023 int regset = NT_PRSTATUS; 1024 struct iovec ioVec; 1025 1026 ioVec.iov_base = ®s; 1027 ioVec.iov_len = sizeof regs; 1028 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, sizeof regs); 1029 if (error.Success()) 1030 { 1031 ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 8); 1032 error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, &ioVec, sizeof regs); 1033 } 1034 } 1035 return error; 1036 } 1037 1038 Error 1039 NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size) 1040 { 1041 int regset = NT_PRSTATUS; 1042 struct iovec ioVec; 1043 Error error; 1044 1045 ioVec.iov_base = buf; 1046 ioVec.iov_len = buf_size; 1047 return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1048 } 1049 1050 Error 1051 NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size) 1052 { 1053 int regset = NT_PRSTATUS; 1054 struct iovec ioVec; 1055 Error error; 1056 1057 ioVec.iov_base = buf; 1058 ioVec.iov_len = buf_size; 1059 return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1060 } 1061 1062 Error 1063 NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size) 1064 { 1065 int regset = NT_FPREGSET; 1066 struct iovec ioVec; 1067 Error error; 1068 1069 ioVec.iov_base = buf; 1070 ioVec.iov_len = buf_size; 1071 return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1072 } 1073 1074 Error 1075 NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size) 1076 { 1077 int regset = NT_FPREGSET; 1078 struct iovec ioVec; 1079 Error error; 1080 1081 ioVec.iov_base = buf; 1082 ioVec.iov_len = buf_size; 1083 return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1084 } 1085 1086 uint32_t 1087 NativeRegisterContextLinux_arm64::CalculateFprOffset(const RegisterInfo* reg_info) const 1088 { 1089 return reg_info->byte_offset - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset; 1090 } 1091 1092 #endif // defined (__arm64__) || defined (__aarch64__) 1093