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