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