1 //===-- NativeRegisterContextDBReg_arm64.cpp ------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "NativeRegisterContextDBReg_arm64.h" 10 11 #include "lldb/Utility/LLDBLog.h" 12 #include "lldb/Utility/Log.h" 13 #include "lldb/Utility/RegisterValue.h" 14 15 using namespace lldb_private; 16 17 // E (bit 0), used to enable breakpoint/watchpoint 18 constexpr uint32_t g_enable_bit = 1; 19 // PAC (bits 2:1): 0b10 20 constexpr uint32_t g_pac_bits = (2 << 1); 21 22 // Returns appropriate control register bits for the specified size 23 static constexpr inline uint64_t GetSizeBits(int size) { 24 // BAS (bits 12:5) hold a bit-mask of addresses to watch 25 // e.g. 0b00000001 means 1 byte at address 26 // 0b00000011 means 2 bytes (addr..addr+1) 27 // ... 28 // 0b11111111 means 8 bytes (addr..addr+7) 29 return ((1 << size) - 1) << 5; 30 } 31 32 uint32_t NativeRegisterContextDBReg_arm64::NumSupportedHardwareBreakpoints() { 33 Log *log = GetLog(LLDBLog::Breakpoints); 34 llvm::Error error = ReadHardwareDebugInfo(); 35 if (error) { 36 LLDB_LOG_ERROR(log, std::move(error), 37 "failed to read debug registers: {0}"); 38 return 0; 39 } 40 41 return m_max_hbp_supported; 42 } 43 44 uint32_t 45 NativeRegisterContextDBReg_arm64::SetHardwareBreakpoint(lldb::addr_t addr, 46 size_t size) { 47 Log *log = GetLog(LLDBLog::Breakpoints); 48 LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size); 49 50 // Read hardware breakpoint and watchpoint information. 51 llvm::Error error = ReadHardwareDebugInfo(); 52 if (error) { 53 LLDB_LOG_ERROR( 54 log, std::move(error), 55 "unable to set breakpoint: failed to read debug registers: {0}"); 56 return LLDB_INVALID_INDEX32; 57 } 58 59 uint32_t control_value = 0, bp_index = 0; 60 61 // Check if size has a valid hardware breakpoint length. 62 if (size != 4) 63 return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware 64 // breakpoint 65 66 // Check 4-byte alignment for hardware breakpoint target address. 67 if (addr & 0x03) 68 return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned. 69 70 // Setup control value 71 control_value = g_enable_bit | g_pac_bits | GetSizeBits(size); 72 73 // Iterate over stored breakpoints and find a free bp_index 74 bp_index = LLDB_INVALID_INDEX32; 75 for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 76 if (!BreakpointIsEnabled(i)) 77 bp_index = i; // Mark last free slot 78 else if (m_hbp_regs[i].address == addr) 79 return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints. 80 } 81 82 if (bp_index == LLDB_INVALID_INDEX32) 83 return LLDB_INVALID_INDEX32; 84 85 // Update breakpoint in local cache 86 m_hbp_regs[bp_index].real_addr = addr; 87 m_hbp_regs[bp_index].address = addr; 88 m_hbp_regs[bp_index].control = control_value; 89 90 // PTRACE call to set corresponding hardware breakpoint register. 91 error = WriteHardwareDebugRegs(eDREGTypeBREAK); 92 93 if (error) { 94 m_hbp_regs[bp_index].address = 0; 95 m_hbp_regs[bp_index].control &= ~1; 96 97 LLDB_LOG_ERROR( 98 log, std::move(error), 99 "unable to set breakpoint: failed to write debug registers: {0}"); 100 return LLDB_INVALID_INDEX32; 101 } 102 103 return bp_index; 104 } 105 106 bool NativeRegisterContextDBReg_arm64::ClearHardwareBreakpoint( 107 uint32_t hw_idx) { 108 Log *log = GetLog(LLDBLog::Breakpoints); 109 LLDB_LOG(log, "hw_idx: {0}", hw_idx); 110 111 // Read hardware breakpoint and watchpoint information. 112 llvm::Error error = ReadHardwareDebugInfo(); 113 if (error) { 114 LLDB_LOG_ERROR( 115 log, std::move(error), 116 "unable to clear breakpoint: failed to read debug registers: {0}"); 117 return false; 118 } 119 120 if (hw_idx >= m_max_hbp_supported) 121 return false; 122 123 // Create a backup we can revert to in case of failure. 124 lldb::addr_t tempAddr = m_hbp_regs[hw_idx].address; 125 uint32_t tempControl = m_hbp_regs[hw_idx].control; 126 127 m_hbp_regs[hw_idx].control &= ~g_enable_bit; 128 m_hbp_regs[hw_idx].address = 0; 129 130 // PTRACE call to clear corresponding hardware breakpoint register. 131 error = WriteHardwareDebugRegs(eDREGTypeBREAK); 132 133 if (error) { 134 m_hbp_regs[hw_idx].control = tempControl; 135 m_hbp_regs[hw_idx].address = tempAddr; 136 137 LLDB_LOG_ERROR( 138 log, std::move(error), 139 "unable to clear breakpoint: failed to write debug registers: {0}"); 140 return false; 141 } 142 143 return true; 144 } 145 146 Status NativeRegisterContextDBReg_arm64::GetHardwareBreakHitIndex( 147 uint32_t &bp_index, lldb::addr_t trap_addr) { 148 Log *log = GetLog(LLDBLog::Breakpoints); 149 150 LLDB_LOGF(log, "NativeRegisterContextDBReg_arm64::%s()", __FUNCTION__); 151 152 lldb::addr_t break_addr; 153 154 for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) { 155 break_addr = m_hbp_regs[bp_index].address; 156 157 if (BreakpointIsEnabled(bp_index) && trap_addr == break_addr) { 158 m_hbp_regs[bp_index].hit_addr = trap_addr; 159 return Status(); 160 } 161 } 162 163 bp_index = LLDB_INVALID_INDEX32; 164 return Status(); 165 } 166 167 Status NativeRegisterContextDBReg_arm64::ClearAllHardwareBreakpoints() { 168 Log *log = GetLog(LLDBLog::Breakpoints); 169 170 LLDB_LOGF(log, "NativeRegisterContextDBReg_arm64::%s()", __FUNCTION__); 171 172 // Read hardware breakpoint and watchpoint information. 173 llvm::Error error = ReadHardwareDebugInfo(); 174 if (error) 175 return Status(std::move(error)); 176 177 for (uint32_t i = 0; i < m_max_hbp_supported; i++) { 178 if (BreakpointIsEnabled(i)) { 179 // Create a backup we can revert to in case of failure. 180 lldb::addr_t tempAddr = m_hbp_regs[i].address; 181 uint32_t tempControl = m_hbp_regs[i].control; 182 183 // Clear watchpoints in local cache 184 m_hbp_regs[i].control &= ~g_enable_bit; 185 m_hbp_regs[i].address = 0; 186 187 // Ptrace call to update hardware debug registers 188 error = WriteHardwareDebugRegs(eDREGTypeBREAK); 189 190 if (error) { 191 m_hbp_regs[i].control = tempControl; 192 m_hbp_regs[i].address = tempAddr; 193 194 return Status(std::move(error)); 195 } 196 } 197 } 198 199 return Status(); 200 } 201 202 bool NativeRegisterContextDBReg_arm64::BreakpointIsEnabled(uint32_t bp_index) { 203 if ((m_hbp_regs[bp_index].control & g_enable_bit) != 0) 204 return true; 205 else 206 return false; 207 } 208 209 uint32_t NativeRegisterContextDBReg_arm64::NumSupportedHardwareWatchpoints() { 210 Log *log = GetLog(LLDBLog::Watchpoints); 211 llvm::Error error = ReadHardwareDebugInfo(); 212 if (error) { 213 LLDB_LOG_ERROR(log, std::move(error), 214 "failed to read debug registers: {0}"); 215 return 0; 216 } 217 218 return m_max_hwp_supported; 219 } 220 221 uint32_t NativeRegisterContextDBReg_arm64::SetHardwareWatchpoint( 222 lldb::addr_t addr, size_t size, uint32_t watch_flags) { 223 Log *log = GetLog(LLDBLog::Watchpoints); 224 LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, 225 watch_flags); 226 227 // Read hardware breakpoint and watchpoint information. 228 llvm::Error error = ReadHardwareDebugInfo(); 229 if (error) { 230 LLDB_LOG_ERROR( 231 log, std::move(error), 232 "unable to set watchpoint: failed to read debug registers: {0}"); 233 return LLDB_INVALID_INDEX32; 234 } 235 236 uint32_t control_value = 0, wp_index = 0; 237 lldb::addr_t real_addr = addr; 238 239 // Check if we are setting watchpoint other than read/write/access Also 240 // update watchpoint flag to match AArch64 write-read bit configuration. 241 switch (watch_flags) { 242 case 1: 243 watch_flags = 2; 244 break; 245 case 2: 246 watch_flags = 1; 247 break; 248 case 3: 249 break; 250 default: 251 return LLDB_INVALID_INDEX32; 252 } 253 254 // Check if size has a valid hardware watchpoint length. 255 if (size != 1 && size != 2 && size != 4 && size != 8) 256 return LLDB_INVALID_INDEX32; 257 258 // Check 8-byte alignment for hardware watchpoint target address. Below is a 259 // hack to recalculate address and size in order to make sure we can watch 260 // non 8-byte aligned addresses as well. 261 if (addr & 0x07) { 262 uint8_t watch_mask = (addr & 0x07) + size; 263 264 if (watch_mask > 0x08) 265 return LLDB_INVALID_INDEX32; 266 else if (watch_mask <= 0x02) 267 size = 2; 268 else if (watch_mask <= 0x04) 269 size = 4; 270 else 271 size = 8; 272 273 addr = addr & (~0x07); 274 } 275 276 // Setup control value 277 control_value = g_enable_bit | g_pac_bits | GetSizeBits(size); 278 control_value |= watch_flags << 3; 279 280 // Iterate over stored watchpoints and find a free wp_index 281 wp_index = LLDB_INVALID_INDEX32; 282 for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 283 if (!WatchpointIsEnabled(i)) 284 wp_index = i; // Mark last free slot 285 else if (m_hwp_regs[i].address == addr) { 286 return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. 287 } 288 } 289 290 if (wp_index == LLDB_INVALID_INDEX32) 291 return LLDB_INVALID_INDEX32; 292 293 // Update watchpoint in local cache 294 m_hwp_regs[wp_index].real_addr = real_addr; 295 m_hwp_regs[wp_index].address = addr; 296 m_hwp_regs[wp_index].control = control_value; 297 298 // PTRACE call to set corresponding watchpoint register. 299 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 300 301 if (error) { 302 m_hwp_regs[wp_index].address = 0; 303 m_hwp_regs[wp_index].control &= ~g_enable_bit; 304 305 LLDB_LOG_ERROR( 306 log, std::move(error), 307 "unable to set watchpoint: failed to write debug registers: {0}"); 308 return LLDB_INVALID_INDEX32; 309 } 310 311 return wp_index; 312 } 313 314 bool NativeRegisterContextDBReg_arm64::ClearHardwareWatchpoint( 315 uint32_t wp_index) { 316 Log *log = GetLog(LLDBLog::Watchpoints); 317 LLDB_LOG(log, "wp_index: {0}", wp_index); 318 319 // Read hardware breakpoint and watchpoint information. 320 llvm::Error error = ReadHardwareDebugInfo(); 321 if (error) { 322 LLDB_LOG_ERROR( 323 log, std::move(error), 324 "unable to clear watchpoint: failed to read debug registers: {0}"); 325 return false; 326 } 327 328 if (wp_index >= m_max_hwp_supported) 329 return false; 330 331 // Create a backup we can revert to in case of failure. 332 lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; 333 uint32_t tempControl = m_hwp_regs[wp_index].control; 334 335 // Update watchpoint in local cache 336 m_hwp_regs[wp_index].control &= ~g_enable_bit; 337 m_hwp_regs[wp_index].address = 0; 338 339 // Ptrace call to update hardware debug registers 340 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 341 342 if (error) { 343 m_hwp_regs[wp_index].control = tempControl; 344 m_hwp_regs[wp_index].address = tempAddr; 345 346 LLDB_LOG_ERROR( 347 log, std::move(error), 348 "unable to clear watchpoint: failed to write debug registers: {0}"); 349 return false; 350 } 351 352 return true; 353 } 354 355 Status NativeRegisterContextDBReg_arm64::ClearAllHardwareWatchpoints() { 356 // Read hardware breakpoint and watchpoint information. 357 llvm::Error error = ReadHardwareDebugInfo(); 358 if (error) 359 return Status(std::move(error)); 360 361 for (uint32_t i = 0; i < m_max_hwp_supported; i++) { 362 if (WatchpointIsEnabled(i)) { 363 // Create a backup we can revert to in case of failure. 364 lldb::addr_t tempAddr = m_hwp_regs[i].address; 365 uint32_t tempControl = m_hwp_regs[i].control; 366 367 // Clear watchpoints in local cache 368 m_hwp_regs[i].control &= ~g_enable_bit; 369 m_hwp_regs[i].address = 0; 370 371 // Ptrace call to update hardware debug registers 372 error = WriteHardwareDebugRegs(eDREGTypeWATCH); 373 374 if (error) { 375 m_hwp_regs[i].control = tempControl; 376 m_hwp_regs[i].address = tempAddr; 377 378 return Status(std::move(error)); 379 } 380 } 381 } 382 383 return Status(); 384 } 385 386 uint32_t 387 NativeRegisterContextDBReg_arm64::GetWatchpointSize(uint32_t wp_index) { 388 Log *log = GetLog(LLDBLog::Watchpoints); 389 LLDB_LOG(log, "wp_index: {0}", wp_index); 390 391 switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) { 392 case 0x01: 393 return 1; 394 case 0x03: 395 return 2; 396 case 0x0f: 397 return 4; 398 case 0xff: 399 return 8; 400 default: 401 return 0; 402 } 403 } 404 405 bool NativeRegisterContextDBReg_arm64::WatchpointIsEnabled(uint32_t wp_index) { 406 Log *log = GetLog(LLDBLog::Watchpoints); 407 LLDB_LOG(log, "wp_index: {0}", wp_index); 408 409 if ((m_hwp_regs[wp_index].control & g_enable_bit) != 0) 410 return true; 411 else 412 return false; 413 } 414 415 Status NativeRegisterContextDBReg_arm64::GetWatchpointHitIndex( 416 uint32_t &wp_index, lldb::addr_t trap_addr) { 417 Log *log = GetLog(LLDBLog::Watchpoints); 418 LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); 419 420 // Read hardware breakpoint and watchpoint information. 421 llvm::Error error = ReadHardwareDebugInfo(); 422 if (error) 423 return Status(std::move(error)); 424 425 // Mask off ignored bits from watchpoint trap address. 426 trap_addr = FixWatchpointHitAddress(trap_addr); 427 428 uint32_t watch_size; 429 lldb::addr_t watch_addr; 430 431 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { 432 watch_size = GetWatchpointSize(wp_index); 433 watch_addr = m_hwp_regs[wp_index].address; 434 435 if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && 436 trap_addr < watch_addr + watch_size) { 437 m_hwp_regs[wp_index].hit_addr = trap_addr; 438 return Status(); 439 } 440 } 441 442 wp_index = LLDB_INVALID_INDEX32; 443 return Status(); 444 } 445 446 lldb::addr_t 447 NativeRegisterContextDBReg_arm64::GetWatchpointAddress(uint32_t wp_index) { 448 Log *log = GetLog(LLDBLog::Watchpoints); 449 LLDB_LOG(log, "wp_index: {0}", wp_index); 450 451 if (wp_index >= m_max_hwp_supported) 452 return LLDB_INVALID_ADDRESS; 453 454 if (WatchpointIsEnabled(wp_index)) 455 return m_hwp_regs[wp_index].real_addr; 456 return LLDB_INVALID_ADDRESS; 457 } 458 459 lldb::addr_t 460 NativeRegisterContextDBReg_arm64::GetWatchpointHitAddress(uint32_t wp_index) { 461 Log *log = GetLog(LLDBLog::Watchpoints); 462 LLDB_LOG(log, "wp_index: {0}", wp_index); 463 464 if (wp_index >= m_max_hwp_supported) 465 return LLDB_INVALID_ADDRESS; 466 467 if (WatchpointIsEnabled(wp_index)) 468 return m_hwp_regs[wp_index].hit_addr; 469 return LLDB_INVALID_ADDRESS; 470 } 471