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