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 assert (reg_info->byte_offset < sizeof m_fpr); 253 uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; 254 reg_value.SetFromMemoryData(reg_info, src, reg_info->byte_size, eByteOrderLittle, error); 255 256 return error; 257 } 258 259 Error 260 NativeRegisterContextLinux_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) 261 { 262 if (!reg_info) 263 return Error ("reg_info NULL"); 264 265 const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; 266 if (reg_index == LLDB_INVALID_REGNUM) 267 return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : "<unknown register>"); 268 269 if (IsGPR(reg_index)) 270 return WriteRegisterRaw(reg_index, reg_value); 271 272 if (IsFPR(reg_index)) 273 { 274 // Get pointer to m_fpr variable and set the data to it. 275 assert (reg_info->byte_offset < sizeof(m_fpr)); 276 uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset; 277 switch (reg_info->byte_size) 278 { 279 case 2: 280 *(uint16_t *)dst = reg_value.GetAsUInt16(); 281 break; 282 case 4: 283 *(uint32_t *)dst = reg_value.GetAsUInt32(); 284 break; 285 case 8: 286 *(uint64_t *)dst = reg_value.GetAsUInt64(); 287 break; 288 default: 289 assert(false && "Unhandled data size."); 290 return Error ("unhandled register data size %" PRIu32, reg_info->byte_size); 291 } 292 293 Error error = WriteFPR(); 294 if (error.Fail()) 295 return error; 296 297 return Error (); 298 } 299 300 return Error ("failed - register wasn't recognized to be a GPR or an FPR, write strategy unknown"); 301 } 302 303 Error 304 NativeRegisterContextLinux_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) 305 { 306 Error error; 307 308 data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); 309 if (!data_sp) 310 return Error ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE); 311 312 error = ReadGPR(); 313 if (error.Fail()) 314 return error; 315 316 error = ReadFPR(); 317 if (error.Fail()) 318 return error; 319 320 uint8_t *dst = data_sp->GetBytes (); 321 if (dst == nullptr) 322 { 323 error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE); 324 return error; 325 } 326 327 ::memcpy (dst, &m_gpr_arm64, GetGPRSize()); 328 dst += GetGPRSize(); 329 ::memcpy (dst, &m_fpr, sizeof(m_fpr)); 330 331 return error; 332 } 333 334 Error 335 NativeRegisterContextLinux_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) 336 { 337 Error error; 338 339 if (!data_sp) 340 { 341 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", __FUNCTION__); 342 return error; 343 } 344 345 if (data_sp->GetByteSize () != REG_CONTEXT_SIZE) 346 { 347 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ()); 348 return error; 349 } 350 351 352 uint8_t *src = data_sp->GetBytes (); 353 if (src == nullptr) 354 { 355 error.SetErrorStringWithFormat ("NativeRegisterContextLinux_x86_64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__); 356 return error; 357 } 358 ::memcpy (&m_gpr_arm64, src, GetRegisterInfoInterface ().GetGPRSize ()); 359 360 error = WriteGPR(); 361 if (error.Fail()) 362 return error; 363 364 src += GetRegisterInfoInterface ().GetGPRSize (); 365 ::memcpy (&m_fpr, src, sizeof(m_fpr)); 366 367 error = WriteFPR(); 368 if (error.Fail()) 369 return error; 370 371 return error; 372 } 373 374 bool 375 NativeRegisterContextLinux_arm64::IsGPR(unsigned reg) const 376 { 377 return reg <= m_reg_info.last_gpr; // GPR's come first. 378 } 379 380 bool 381 NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const 382 { 383 return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); 384 } 385 386 uint32_t 387 NativeRegisterContextLinux_arm64::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) 388 { 389 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 390 391 if (log) 392 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 393 394 Error error; 395 396 // Read hardware breakpoint and watchpoint information. 397 error = ReadHardwareDebugInfo (); 398 399 if (error.Fail()) 400 return LLDB_INVALID_INDEX32; 401 402 uint32_t control_value = 0, bp_index = 0; 403 404 // Check if size has a valid hardware breakpoint length. 405 if (size != 4) 406 return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware breakpoint 407 408 // Check 4-byte alignment for hardware breakpoint target address. 409 if (addr & 0x03) 410 return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned. 411 412 // Setup control value 413 control_value = 0; 414 control_value |= ((1 << size) - 1) << 5; 415 control_value |= (2 << 1) | 1; 416 417 // Iterate over stored hardware breakpoints 418 // Find a free bp_index or update reference count if duplicate. 419 bp_index = LLDB_INVALID_INDEX32; 420 for (uint32_t i = 0; i < m_max_hbp_supported; i++) 421 { 422 if ((m_hbr_regs[i].control & 1) == 0) 423 { 424 bp_index = i; // Mark last free slot 425 } 426 else if (m_hbr_regs[i].address == addr && m_hbr_regs[i].control == control_value) 427 { 428 bp_index = i; // Mark duplicate index 429 break; // Stop searching here 430 } 431 } 432 433 if (bp_index == LLDB_INVALID_INDEX32) 434 return LLDB_INVALID_INDEX32; 435 436 // Add new or update existing watchpoint 437 if ((m_hbr_regs[bp_index].control & 1) == 0) 438 { 439 m_hbr_regs[bp_index].address = addr; 440 m_hbr_regs[bp_index].control = control_value; 441 m_hbr_regs[bp_index].refcount = 1; 442 443 // PTRACE call to set corresponding hardware breakpoint register. 444 error = WriteHardwareDebugRegs(eDREGTypeBREAK); 445 446 if (error.Fail()) 447 return LLDB_INVALID_INDEX32; 448 } 449 else 450 m_hbr_regs[bp_index].refcount++; 451 452 return bp_index; 453 } 454 455 bool 456 NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint (uint32_t hw_idx) 457 { 458 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 459 460 if (log) 461 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 462 463 Error error; 464 465 // Read hardware breakpoint and watchpoint information. 466 error = ReadHardwareDebugInfo (); 467 468 if (error.Fail()) 469 return false; 470 471 if (hw_idx >= m_max_hbp_supported) 472 return false; 473 474 // Update reference count if multiple references. 475 if (m_hbr_regs[hw_idx].refcount > 1) 476 { 477 m_hbr_regs[hw_idx].refcount--; 478 return true; 479 } 480 else if (m_hbr_regs[hw_idx].refcount == 1) 481 { 482 m_hbr_regs[hw_idx].control &= ~1; 483 m_hbr_regs[hw_idx].address = 0; 484 m_hbr_regs[hw_idx].refcount = 0; 485 486 // PTRACE call to clear corresponding hardware breakpoint register. 487 WriteHardwareDebugRegs(eDREGTypeBREAK); 488 489 if (error.Fail()) 490 return false; 491 492 return true; 493 } 494 495 return false; 496 } 497 498 uint32_t 499 NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints () 500 { 501 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 502 503 if (log) 504 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 505 506 Error error; 507 508 // Read hardware breakpoint and watchpoint information. 509 error = ReadHardwareDebugInfo (); 510 511 if (error.Fail()) 512 return LLDB_INVALID_INDEX32; 513 514 return m_max_hwp_supported; 515 } 516 517 uint32_t 518 NativeRegisterContextLinux_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags) 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 uint32_t control_value = 0, wp_index = 0; 534 535 // Check if we are setting watchpoint other than read/write/access 536 // Also update watchpoint flag to match AArch64 write-read bit configuration. 537 switch (watch_flags) 538 { 539 case 1: 540 watch_flags = 2; 541 break; 542 case 2: 543 watch_flags = 1; 544 break; 545 case 3: 546 break; 547 default: 548 return LLDB_INVALID_INDEX32; 549 } 550 551 // Check if size has a valid hardware watchpoint length. 552 if (size != 1 && size != 2 && size != 4 && size != 8) 553 return LLDB_INVALID_INDEX32; 554 555 // Check 8-byte alignment for hardware watchpoint target address. 556 // TODO: Add support for watching un-aligned addresses 557 if (addr & 0x07) 558 return LLDB_INVALID_INDEX32; 559 560 // Setup control value 561 control_value = watch_flags << 3; 562 control_value |= ((1 << size) - 1) << 5; 563 control_value |= (2 << 1) | 1; 564 565 // Iterate over stored watchpoints 566 // Find a free wp_index or update reference count if duplicate. 567 wp_index = LLDB_INVALID_INDEX32; 568 for (uint32_t i = 0; i < m_max_hwp_supported; i++) 569 { 570 if ((m_hwp_regs[i].control & 1) == 0) 571 { 572 wp_index = i; // Mark last free slot 573 } 574 else if (m_hwp_regs[i].address == addr && m_hwp_regs[i].control == control_value) 575 { 576 wp_index = i; // Mark duplicate index 577 break; // Stop searching here 578 } 579 } 580 581 if (wp_index == LLDB_INVALID_INDEX32) 582 return LLDB_INVALID_INDEX32; 583 584 // Add new or update existing watchpoint 585 if ((m_hwp_regs[wp_index].control & 1) == 0) 586 { 587 // Update watchpoint in local cache 588 m_hwp_regs[wp_index].address = addr; 589 m_hwp_regs[wp_index].control = control_value; 590 m_hwp_regs[wp_index].refcount = 1; 591 592 // PTRACE call to set corresponding watchpoint register. 593 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 594 595 if (error.Fail()) 596 return LLDB_INVALID_INDEX32; 597 } 598 else 599 m_hwp_regs[wp_index].refcount++; 600 601 return wp_index; 602 } 603 604 bool 605 NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint (uint32_t wp_index) 606 { 607 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 608 609 if (log) 610 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 611 612 Error error; 613 614 // Read hardware breakpoint and watchpoint information. 615 error = ReadHardwareDebugInfo (); 616 617 if (error.Fail()) 618 return false; 619 620 if (wp_index >= m_max_hwp_supported) 621 return false; 622 623 // Update reference count if multiple references. 624 if (m_hwp_regs[wp_index].refcount > 1) 625 { 626 m_hwp_regs[wp_index].refcount--; 627 return true; 628 } 629 else if (m_hwp_regs[wp_index].refcount == 1) 630 { 631 // Update watchpoint in local cache 632 m_hwp_regs[wp_index].control &= ~1; 633 m_hwp_regs[wp_index].address = 0; 634 m_hwp_regs[wp_index].refcount = 0; 635 636 // Ptrace call to update hardware debug registers 637 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 638 639 if (error.Fail()) 640 return false; 641 642 return true; 643 } 644 645 return false; 646 } 647 648 Error 649 NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints () 650 { 651 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 652 653 if (log) 654 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 655 656 Error error; 657 658 // Read hardware breakpoint and watchpoint information. 659 error = ReadHardwareDebugInfo (); 660 661 if (error.Fail()) 662 return error; 663 664 for (uint32_t i = 0; i < m_max_hwp_supported; i++) 665 { 666 if (m_hwp_regs[i].control & 0x01) 667 { 668 // Clear watchpoints in local cache 669 m_hwp_regs[i].control &= ~1; 670 m_hwp_regs[i].address = 0; 671 m_hwp_regs[i].refcount = 0; 672 673 // Ptrace call to update hardware debug registers 674 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 675 676 if (error.Fail()) 677 return error; 678 } 679 } 680 681 return Error(); 682 } 683 684 uint32_t 685 NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) 686 { 687 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 688 689 if (log) 690 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 691 switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) 692 { 693 case 0x01: 694 return 1; 695 case 0x03: 696 return 2; 697 case 0x0f: 698 return 4; 699 case 0xff: 700 return 8; 701 default: 702 return 0; 703 } 704 } 705 bool 706 NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) 707 { 708 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 709 710 if (log) 711 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 712 713 if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) 714 return true; 715 else 716 return false; 717 } 718 719 Error 720 NativeRegisterContextLinux_arm64::GetWatchpointHitIndex(uint32_t &wp_index, lldb::addr_t trap_addr) 721 { 722 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 723 724 if (log) 725 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 726 727 uint32_t watch_size; 728 lldb::addr_t watch_addr; 729 730 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) 731 { 732 watch_size = GetWatchpointSize (wp_index); 733 watch_addr = m_hwp_regs[wp_index].address; 734 735 if (m_hwp_regs[wp_index].refcount >= 1 && WatchpointIsEnabled(wp_index) 736 && trap_addr >= watch_addr && trap_addr < watch_addr + watch_size) 737 { 738 return Error(); 739 } 740 } 741 742 wp_index = LLDB_INVALID_INDEX32; 743 return Error(); 744 } 745 746 lldb::addr_t 747 NativeRegisterContextLinux_arm64::GetWatchpointAddress (uint32_t wp_index) 748 { 749 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); 750 751 if (log) 752 log->Printf ("NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); 753 754 if (wp_index >= m_max_hwp_supported) 755 return LLDB_INVALID_ADDRESS; 756 757 if (WatchpointIsEnabled(wp_index)) 758 return m_hwp_regs[wp_index].address; 759 else 760 return LLDB_INVALID_ADDRESS; 761 } 762 763 Error 764 NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() 765 { 766 if (!m_refresh_hwdebug_info) 767 { 768 return Error(); 769 } 770 771 ::pid_t tid = m_thread.GetID(); 772 773 int regset = NT_ARM_HW_WATCH; 774 struct iovec ioVec; 775 struct user_hwdebug_state dreg_state; 776 Error error; 777 778 ioVec.iov_base = &dreg_state; 779 ioVec.iov_len = sizeof (dreg_state); 780 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); 781 782 if (error.Fail()) 783 return error; 784 785 m_max_hwp_supported = dreg_state.dbg_info & 0xff; 786 787 regset = NT_ARM_HW_BREAK; 788 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, ioVec.iov_len); 789 790 if (error.Fail()) 791 return error; 792 793 m_max_hbp_supported = dreg_state.dbg_info & 0xff; 794 m_refresh_hwdebug_info = false; 795 796 return error; 797 } 798 799 Error 800 NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) 801 { 802 struct iovec ioVec; 803 struct user_hwdebug_state dreg_state; 804 Error error; 805 806 memset (&dreg_state, 0, sizeof (dreg_state)); 807 ioVec.iov_base = &dreg_state; 808 ioVec.iov_len = sizeof (dreg_state); 809 810 if (hwbType == eDREGTypeWATCH) 811 { 812 hwbType = NT_ARM_HW_WATCH; 813 814 for (uint32_t i = 0; i < m_max_hwp_supported; i++) 815 { 816 dreg_state.dbg_regs[i].addr = m_hwp_regs[i].address; 817 dreg_state.dbg_regs[i].ctrl = m_hwp_regs[i].control; 818 } 819 } 820 else 821 { 822 hwbType = NT_ARM_HW_BREAK; 823 824 for (uint32_t i = 0; i < m_max_hbp_supported; i++) 825 { 826 dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address; 827 dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control; 828 } 829 } 830 831 return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), &hwbType, &ioVec, ioVec.iov_len); 832 } 833 834 Error 835 NativeRegisterContextLinux_arm64::DoReadRegisterValue(uint32_t offset, 836 const char* reg_name, 837 uint32_t size, 838 RegisterValue &value) 839 { 840 Error error; 841 if (offset > sizeof(struct user_pt_regs)) 842 { 843 uintptr_t offset = offset - sizeof(struct user_pt_regs); 844 if (offset > sizeof(struct user_fpsimd_state)) 845 { 846 error.SetErrorString("invalid offset value"); 847 return error; 848 } 849 elf_fpregset_t regs; 850 int regset = NT_FPREGSET; 851 struct iovec ioVec; 852 853 ioVec.iov_base = ®s; 854 ioVec.iov_len = sizeof regs; 855 error = NativeProcessLinux::PtraceWrapper( 856 PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 857 if (error.Success()) 858 { 859 ArchSpec arch; 860 if (m_thread.GetProcess()->GetArchitecture(arch)) 861 value.SetBytes((void *)(((unsigned char *)(®s)) + offset), 16, arch.GetByteOrder()); 862 else 863 error.SetErrorString("failed to get architecture"); 864 } 865 } 866 else 867 { 868 elf_gregset_t regs; 869 int regset = NT_PRSTATUS; 870 struct iovec ioVec; 871 872 ioVec.iov_base = ®s; 873 ioVec.iov_len = sizeof regs; 874 error = NativeProcessLinux::PtraceWrapper( 875 PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, sizeof regs); 876 if (error.Success()) 877 { 878 ArchSpec arch; 879 if (m_thread.GetProcess()->GetArchitecture(arch)) 880 value.SetBytes((void *)(((unsigned char *)(regs)) + offset), 8, arch.GetByteOrder()); 881 else 882 error.SetErrorString("failed to get architecture"); 883 } 884 } 885 return error; 886 } 887 888 Error 889 NativeRegisterContextLinux_arm64::DoWriteRegisterValue(uint32_t offset, 890 const char* reg_name, 891 const RegisterValue &value) 892 { 893 Error error; 894 ::pid_t tid = m_thread.GetID(); 895 if (offset > sizeof(struct user_pt_regs)) 896 { 897 uintptr_t offset = offset - sizeof(struct user_pt_regs); 898 if (offset > sizeof(struct user_fpsimd_state)) 899 { 900 error.SetErrorString("invalid offset value"); 901 return error; 902 } 903 elf_fpregset_t regs; 904 int regset = NT_FPREGSET; 905 struct iovec ioVec; 906 907 ioVec.iov_base = ®s; 908 ioVec.iov_len = sizeof regs; 909 error = NativeProcessLinux::PtraceWrapper( PTRACE_GETREGSET, tid, ®set, &ioVec, sizeof regs); 910 911 if (error.Success()) 912 { 913 ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 16); 914 error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, &ioVec, sizeof regs); 915 } 916 } 917 else 918 { 919 elf_gregset_t regs; 920 int regset = NT_PRSTATUS; 921 struct iovec ioVec; 922 923 ioVec.iov_base = ®s; 924 ioVec.iov_len = sizeof regs; 925 error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, &ioVec, sizeof regs); 926 if (error.Success()) 927 { 928 ::memcpy((void *)(((unsigned char *)(®s)) + offset), value.GetBytes(), 8); 929 error = NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, tid, ®set, &ioVec, sizeof regs); 930 } 931 } 932 return error; 933 } 934 935 Error 936 NativeRegisterContextLinux_arm64::DoReadGPR(void *buf, size_t buf_size) 937 { 938 int regset = NT_PRSTATUS; 939 struct iovec ioVec; 940 Error error; 941 942 ioVec.iov_base = buf; 943 ioVec.iov_len = buf_size; 944 return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 945 } 946 947 Error 948 NativeRegisterContextLinux_arm64::DoWriteGPR(void *buf, size_t buf_size) 949 { 950 int regset = NT_PRSTATUS; 951 struct iovec ioVec; 952 Error error; 953 954 ioVec.iov_base = buf; 955 ioVec.iov_len = buf_size; 956 return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 957 } 958 959 Error 960 NativeRegisterContextLinux_arm64::DoReadFPR(void *buf, size_t buf_size) 961 { 962 int regset = NT_FPREGSET; 963 struct iovec ioVec; 964 Error error; 965 966 ioVec.iov_base = buf; 967 ioVec.iov_len = buf_size; 968 return NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 969 } 970 971 Error 972 NativeRegisterContextLinux_arm64::DoWriteFPR(void *buf, size_t buf_size) 973 { 974 int regset = NT_FPREGSET; 975 struct iovec ioVec; 976 Error error; 977 978 ioVec.iov_base = buf; 979 ioVec.iov_len = buf_size; 980 return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), ®set, &ioVec, buf_size); 981 } 982 983 #endif // defined (__arm64__) || defined (__aarch64__) 984