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