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 570 // Check if we are setting watchpoint other than read/write/access 571 // Also update watchpoint flag to match AArch64 write-read bit configuration. 572 switch (watch_flags) 573 { 574 case 1: 575 watch_flags = 2; 576 break; 577 case 2: 578 watch_flags = 1; 579 break; 580 case 3: 581 break; 582 default: 583 return LLDB_INVALID_INDEX32; 584 } 585 586 // Check if size has a valid hardware watchpoint length. 587 if (size != 1 && size != 2 && size != 4 && size != 8) 588 return LLDB_INVALID_INDEX32; 589 590 // Check 8-byte alignment for hardware watchpoint target address. 591 // TODO: Add support for watching un-aligned addresses 592 if (addr & 0x07) 593 return LLDB_INVALID_INDEX32; 594 595 // Setup control value 596 control_value = watch_flags << 3; 597 control_value |= ((1 << size) - 1) << 5; 598 control_value |= (2 << 1) | 1; 599 600 // Iterate over stored watchpoints 601 // Find a free wp_index or update reference count if duplicate. 602 wp_index = LLDB_INVALID_INDEX32; 603 for (uint32_t i = 0; i < m_max_hwp_supported; i++) 604 { 605 if ((m_hwp_regs[i].control & 1) == 0) 606 { 607 wp_index = i; // Mark last free slot 608 } 609 else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value) 610 { 611 wp_index = i; // Mark duplicate index 612 break; // Stop searching here 613 } 614 } 615 616 if (wp_index == LLDB_INVALID_INDEX32) 617 return LLDB_INVALID_INDEX32; 618 619 // Add new or update existing watchpoint 620 if ((m_hwp_regs[wp_index].control & 1) == 0) 621 { 622 // Update watchpoint in local cache 623 m_hwp_regs[wp_index].address = addr; 624 m_hwp_regs[wp_index].control = control_value; 625 m_hwp_regs[wp_index].refcount = 1; 626 627 // PTRACE call to set corresponding watchpoint register. 628 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 629 630 if (error.Fail()) 631 { 632 m_hwp_regs[wp_index].address = 0; 633 m_hwp_regs[wp_index].control &= ~1; 634 m_hwp_regs[wp_index].refcount = 0; 635 636 return LLDB_INVALID_INDEX32; 637 } 638 } 639 else 640 m_hwp_regs[wp_index].refcount++; 641 642 return wp_index; 643 } 644 645 bool 646 NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index) 647 { 648 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 649 650 if (log) 651 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 652 653 Error error; 654 655 // Read hardware breakpoint and watchpoint information. 656 error = ReadHardwareDebugInfo (); 657 658 if (error.Fail()) 659 return false; 660 661 if (wp_index >= m_max_hwp_supported) 662 return false; 663 664 // Update reference count if multiple references. 665 if (m_hwp_regs[wp_index].refcount > 1) 666 { 667 m_hwp_regs[wp_index].refcount--; 668 return true; 669 } 670 else if (m_hwp_regs[wp_index].refcount == 1) 671 { 672 // Create a backup we can revert to in case of failure. 673 lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; 674 uint32_t tempControl = m_hwp_regs[wp_index].control; 675 uint32_t tempRefCount = m_hwp_regs[wp_index].refcount; 676 677 // Update watchpoint in local cache 678 m_hwp_regs[wp_index].control &= ~1; 679 m_hwp_regs[wp_index].address = 0; 680 m_hwp_regs[wp_index].refcount = 0; 681 682 // Ptrace call to update hardware debug registers 683 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 684 685 if (error.Fail()) 686 { 687 m_hwp_regs[wp_index].control = tempControl; 688 m_hwp_regs[wp_index].address = tempAddr; 689 m_hwp_regs[wp_index].refcount = tempRefCount; 690 691 return false; 692 } 693 694 return true; 695 } 696 697 return false; 698 } 699 700 Error 701 NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints () 702 { 703 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 704 705 if (log) 706 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 707 708 Error error; 709 710 // Read hardware breakpoint and watchpoint information. 711 error = ReadHardwareDebugInfo (); 712 713 if (error.Fail()) 714 return error; 715 716 lldb::addr_t tempAddr = 0; 717 uint32_t tempControl = 0, tempRefCount = 0; 718 719 for (uint32_t i = 0; i < m_max_hwp_supported; i++) 720 { 721 if (m_hwp_regs[i].control & 0x01) 722 { 723 // Create a backup we can revert to in case of failure. 724 tempAddr = m_hwp_regs[i].address; 725 tempControl = m_hwp_regs[i].control; 726 tempRefCount = m_hwp_regs[i].refcount; 727 728 // Clear watchpoints in local cache 729 m_hwp_regs[i].control &= ~1; 730 m_hwp_regs[i].address = 0; 731 m_hwp_regs[i].refcount = 0; 732 733 // Ptrace call to update hardware debug registers 734 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 735 736 if (error.Fail()) 737 { 738 m_hwp_regs[i].control = tempControl; 739 m_hwp_regs[i].address = tempAddr; 740 m_hwp_regs[i].refcount = tempRefCount; 741 742 return error; 743 } 744 } 745 } 746 747 return Error(); 748 } 749 750 uint32_t 751 NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) 752 { 753 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 754 755 if (log) 756 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 757 switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) 758 { 759 case 0x01: 760 return 1; 761 case 0x03: 762 return 2; 763 case 0x0f: 764 return 4; 765 case 0xff: 766 return 8; 767 default: 768 return 0; 769 } 770 } 771 bool 772 NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) 773 { 774 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 775 776 if (log) 777 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 778 779 if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) 780 return true; 781 else 782 return false; 783 } 784 785 Error 786 NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) 787 { 788 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 789 790 if (log) 791 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 792 793 uint32_t watch_size; 794 lldb::addr_t watch_addr; 795 796 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) 797 { 798 watch_size = GetWatchpointSize (wp_index); 799 watch_addr = m_hwp_regs[wp_index].address; 800 801 if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index) 802 && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size) 803 { 804 return Error(); 805 } 806 } 807 808 wp_index = LLDB_INVALID_INDEX32; 809 return Error(); 810 } 811 812 lldb::addr_t 813 NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index) 814 { 815 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 816 817 if (log) 818 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 819 820 if (wp_index >= m_max_hwp_supported) 821 return LLDB_INVALID_ADDRESS; 822 823 if (WatchpointIsEnabled(wp_index)) 824 return m_hwp_regs[wp_index].address; 825 else 826 return LLDB_INVALID_ADDRESS; 827 } 828 829 Error 830 NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() 831 { 832 if (!m_refresh_hwdebug_info) 833 { 834 return Error(); 835 } 836 837 ::pid_t tid = m_thread.GetID(); 838 839 int regset = NT_ARM_HW_WATCH; 840 struct iovec ioVec; 841 struct user_hwdebug_state dreg_state; 842 Error error; 843 844 ioVec.iov_base = &dreg_state; 845 ioVec.iov_len = sizeof (dreg_state); 846 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); 847 848 if (error.Fail()) 849 return error; 850 851 m_max_hwp_supported = dreg_state.dbg_info & 0xff; 852 853 regset = NT_ARM_HW_BREAK; 854 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); 855 856 if (error.Fail()) 857 return error; 858 859 m_max_hbp_supported = dreg_state.dbg_info & 0xff; 860 m_refresh_hwdebug_info = false; 861 862 return error; 863 } 864 865 Error 866 NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) 867 { 868 struct iovec ioVec; 869 struct user_hwdebug_state dreg_state; 870 Error error; 871 872 memset (&dreg_state, 0, sizeof (dreg_state)); 873 ioVec.iov_base = &dreg_state; 874 875 if (hwbType == eDREGTypeWATCH) 876 { 877 hwbType = NT_ARM_HW_WATCH; 878 ioVec.iov_len = sizeof (dreg_state.dbg_info) + sizeof (dreg_state.pad) 879 + (sizeof (dreg_state.dbg_regs [0]) * m_max_hwp_supported); 880 881 for (uint32_t i = 0; i < m_max_hwp_supported; i++) 882 { 883 dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address; 884 dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control; 885 } 886 } 887 else 888 { 889 hwbType = NT_ARM_HW_BREAK; 890 ioVec.iov_len = sizeof (dreg_state.dbg_info) + sizeof (dreg_state.pad) 891 + (sizeof (dreg_state.dbg_regs [0]) * m_max_hbp_supported); 892 893 for (uint32_t i = 0; i < m_max_hbp_supported; i++) 894 { 895 dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address; 896 dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control; 897 } 898 } 899 900 return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &hwbType, &ioVec, ioVec.iov_len); 901 } 902 903 Error 904 NativeRegisterContextLinux_arm64::DoReadRegisterValue(uint32_t offset, 905 const char* reg_name, 906 uint32_t size, 907 RegisterValue &value) 908 { 909 Error error; 910 if (offset > sizeof(struct user_pt_regs)) 911 { 912 uintptr_t offset = offset - sizeof(struct user_pt_regs); 913 if (offset > sizeof(struct user_fpsimd_state)) 914 { 915 error.SetErrorString("invalid offset value"); 916 return error; 917 } 918 elf_fpregset_t regs; 919 int regset = NT_FPREGSET; 920 struct iovec ioVec; 921 922 ioVec.iov_base = ®s; 923 ioVec.iov_len = sizeof regs; 924 error = NativeProcessLinux::PtraceWrapper( 925 PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 926 if (error.Success()) 927 { 928 ArchSpec arch; 929 if (m_thread.GetProcess()->GetArchitecture(arch)) 930 value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, arch.GetByteOrder()); 931 else 932 error.SetErrorString("failed to get architecture"); 933 } 934 } 935 else 936 { 937 elf_gregset_t regs; 938 int regset = NT_PRSTATUS; 939 struct iovec ioVec; 940 941 ioVec.iov_base = ®s; 942 ioVec.iov_len = sizeof regs; 943 error = NativeProcessLinux::PtraceWrapper( 944 PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 945 if (error.Success()) 946 { 947 ArchSpec arch; 948 if (m_thread.GetProcess()->GetArchitecture(arch)) 949 value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder()); 950 else 951 error.SetErrorString("failed to get architecture"); 952 } 953 } 954 return error; 955 } 956 957 Error 958 NativeRegisterContextLinux_arm64::DoWriteRegisterValue(uint32_t offset, 959 const char* reg_name, 960 const RegisterValue &value) 961 { 962 Error error; 963 ::pid_t tid = m_thread.GetID(); 964 if (offset > sizeof(struct user_pt_regs)) 965 { 966 uintptr_t offset = offset - sizeof(struct user_pt_regs); 967 if (offset > sizeof(struct user_fpsimd_state)) 968 { 969 error.SetErrorString("invalid offset value"); 970 return error; 971 } 972 elf_fpregset_t regs; 973 int regset = NT_FPREGSET; 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 980 if (error.Success()) 981 { 982 ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 16); 983 error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, &ioVec, sizeof regs); 984 } 985 } 986 else 987 { 988 elf_gregset_t regs; 989 int regset = NT_PRSTATUS; 990 struct iovec ioVec; 991 992 ioVec.iov_base = ®s; 993 ioVec.iov_len = sizeof regs; 994 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, sizeof regs); 995 if (error.Success()) 996 { 997 ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 8); 998 error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, &ioVec, sizeof regs); 999 } 1000 } 1001 return error; 1002 } 1003 1004 Error 1005 NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size) 1006 { 1007 int regset = NT_PRSTATUS; 1008 struct iovec ioVec; 1009 Error error; 1010 1011 ioVec.iov_base = buf; 1012 ioVec.iov_len = buf_size; 1013 return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1014 } 1015 1016 Error 1017 NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size) 1018 { 1019 int regset = NT_PRSTATUS; 1020 struct iovec ioVec; 1021 Error error; 1022 1023 ioVec.iov_base = buf; 1024 ioVec.iov_len = buf_size; 1025 return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1026 } 1027 1028 Error 1029 NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size) 1030 { 1031 int regset = NT_FPREGSET; 1032 struct iovec ioVec; 1033 Error error; 1034 1035 ioVec.iov_base = buf; 1036 ioVec.iov_len = buf_size; 1037 return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1038 } 1039 1040 Error 1041 NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size) 1042 { 1043 int regset = NT_FPREGSET; 1044 struct iovec ioVec; 1045 Error error; 1046 1047 ioVec.iov_base = buf; 1048 ioVec.iov_len = buf_size; 1049 return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 1050 } 1051 1052 uint32_t 1053 NativeRegisterContextLinux_arm64::CalculateFprOffset(const RegisterInfo* reg_info) const 1054 { 1055 return reg_info->byte_offset - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset; 1056 } 1057 1058 #endif // defined (__arm64__) || defined (__aarch64__) 1059