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