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