411 lines · cpp
1//===-- NativeRegisterContextDBReg.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "NativeRegisterContextDBReg.h"10 11#include "lldb/Utility/LLDBLog.h"12#include "lldb/Utility/Log.h"13#include "lldb/Utility/RegisterValue.h"14 15using namespace lldb_private;16 17uint32_t NativeRegisterContextDBReg::NumSupportedHardwareBreakpoints() {18 Log *log = GetLog(LLDBLog::Breakpoints);19 20 // Read hardware breakpoint and watchpoint information.21 llvm::Error error = ReadHardwareDebugInfo();22 23 if (error) {24 LLDB_LOG_ERROR(log, std::move(error),25 "failed to read debug registers: {0}");26 return 0;27 }28 29 LLDB_LOG(log, "{0}", m_max_hbp_supported);30 return m_max_hbp_supported;31}32 33uint32_t NativeRegisterContextDBReg::SetHardwareBreakpoint(lldb::addr_t addr,34 size_t size) {35 Log *log = GetLog(LLDBLog::Breakpoints);36 LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size);37 38 // Read hardware breakpoint and watchpoint information.39 llvm::Error error = ReadHardwareDebugInfo();40 if (error) {41 LLDB_LOG_ERROR(42 log, std::move(error),43 "unable to set breakpoint: failed to read debug registers: {0}");44 return LLDB_INVALID_INDEX32;45 }46 47 if (!ValidateBreakpoint(size, addr))48 return LLDB_INVALID_INDEX32;49 50 uint32_t control_value = MakeBreakControlValue(size);51 auto details = AdjustBreakpoint({size, addr});52 size = details.size;53 addr = details.addr;54 55 // Iterate over stored breakpoints and find a free bp_index56 uint32_t bp_index = LLDB_INVALID_INDEX32;57 for (uint32_t i = 0; i < m_max_hbp_supported; i++) {58 if (!BreakpointIsEnabled(i))59 bp_index = i; // Mark last free slot60 else if (m_hbp_regs[i].address == addr)61 return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints.62 }63 64 if (bp_index == LLDB_INVALID_INDEX32)65 return LLDB_INVALID_INDEX32;66 67 // Update breakpoint in local cache68 m_hbp_regs[bp_index].real_addr = addr;69 m_hbp_regs[bp_index].address = addr;70 m_hbp_regs[bp_index].control = control_value;71 72 // PTRACE call to set corresponding hardware breakpoint register.73 error = WriteHardwareDebugRegs(eDREGTypeBREAK);74 75 if (error) {76 m_hbp_regs[bp_index].address = 0;77 m_hbp_regs[bp_index].control &= ~m_hw_dbg_enable_bit;78 79 LLDB_LOG_ERROR(80 log, std::move(error),81 "unable to set breakpoint: failed to write debug registers: {0}");82 return LLDB_INVALID_INDEX32;83 }84 85 return bp_index;86}87 88bool NativeRegisterContextDBReg::ClearHardwareBreakpoint(uint32_t hw_idx) {89 Log *log = GetLog(LLDBLog::Breakpoints);90 LLDB_LOG(log, "hw_idx: {0}", hw_idx);91 92 // Read hardware breakpoint and watchpoint information.93 llvm::Error error = ReadHardwareDebugInfo();94 if (error) {95 LLDB_LOG_ERROR(96 log, std::move(error),97 "unable to clear breakpoint: failed to read debug registers: {0}");98 return false;99 }100 101 if (hw_idx >= m_max_hbp_supported)102 return false;103 104 // Create a backup we can revert to in case of failure.105 lldb::addr_t tempAddr = m_hbp_regs[hw_idx].address;106 uint32_t tempControl = m_hbp_regs[hw_idx].control;107 108 m_hbp_regs[hw_idx].control &= ~m_hw_dbg_enable_bit;109 m_hbp_regs[hw_idx].address = 0;110 111 // PTRACE call to clear corresponding hardware breakpoint register.112 error = WriteHardwareDebugRegs(eDREGTypeBREAK);113 114 if (error) {115 m_hbp_regs[hw_idx].control = tempControl;116 m_hbp_regs[hw_idx].address = tempAddr;117 118 LLDB_LOG_ERROR(119 log, std::move(error),120 "unable to clear breakpoint: failed to write debug registers: {0}");121 return false;122 }123 124 return true;125}126 127Status128NativeRegisterContextDBReg::GetHardwareBreakHitIndex(uint32_t &bp_index,129 lldb::addr_t trap_addr) {130 Log *log = GetLog(LLDBLog::Breakpoints);131 132 LLDB_LOGF(log, "NativeRegisterContextDBReg::%s()", __FUNCTION__);133 134 lldb::addr_t break_addr;135 136 for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) {137 break_addr = m_hbp_regs[bp_index].address;138 139 if (BreakpointIsEnabled(bp_index) && trap_addr == break_addr) {140 m_hbp_regs[bp_index].hit_addr = trap_addr;141 return Status();142 }143 }144 145 bp_index = LLDB_INVALID_INDEX32;146 return Status();147}148 149Status NativeRegisterContextDBReg::ClearAllHardwareBreakpoints() {150 Log *log = GetLog(LLDBLog::Breakpoints);151 152 LLDB_LOGF(log, "NativeRegisterContextDBReg::%s()", __FUNCTION__);153 154 // Read hardware breakpoint and watchpoint information.155 llvm::Error error = ReadHardwareDebugInfo();156 if (error)157 return Status::FromError(std::move(error));158 159 for (uint32_t i = 0; i < m_max_hbp_supported; i++) {160 if (!BreakpointIsEnabled(i))161 continue;162 // Create a backup we can revert to in case of failure.163 lldb::addr_t tempAddr = m_hbp_regs[i].address;164 uint32_t tempControl = m_hbp_regs[i].control;165 166 // Clear watchpoints in local cache167 m_hbp_regs[i].control &= ~m_hw_dbg_enable_bit;168 m_hbp_regs[i].address = 0;169 170 // Ptrace call to update hardware debug registers171 error = WriteHardwareDebugRegs(eDREGTypeBREAK);172 173 if (error) {174 m_hbp_regs[i].control = tempControl;175 m_hbp_regs[i].address = tempAddr;176 177 return Status::FromError(std::move(error));178 }179 }180 181 return Status();182}183 184bool NativeRegisterContextDBReg::BreakpointIsEnabled(uint32_t bp_index) {185 return ((m_hbp_regs[bp_index].control & m_hw_dbg_enable_bit) != 0);186}187 188uint32_t NativeRegisterContextDBReg::NumSupportedHardwareWatchpoints() {189 Log *log = GetLog(LLDBLog::Watchpoints);190 llvm::Error error = ReadHardwareDebugInfo();191 if (error) {192 LLDB_LOG_ERROR(log, std::move(error),193 "failed to read debug registers: {0}");194 return 0;195 }196 197 return m_max_hwp_supported;198}199 200uint32_t NativeRegisterContextDBReg::SetHardwareWatchpoint(201 lldb::addr_t addr, size_t size, uint32_t watch_flags) {202 Log *log = GetLog(LLDBLog::Watchpoints);203 LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size,204 watch_flags);205 206 // Read hardware breakpoint and watchpoint information.207 llvm::Error error = ReadHardwareDebugInfo();208 if (error) {209 LLDB_LOG_ERROR(210 log, std::move(error),211 "unable to set watchpoint: failed to read debug registers: {0}");212 return LLDB_INVALID_INDEX32;213 }214 215 uint32_t control_value = 0, wp_index = 0;216 lldb::addr_t real_addr = addr;217 WatchpointDetails details{size, addr};218 219 auto adjusted = AdjustWatchpoint(details);220 if (adjusted == std::nullopt)221 return LLDB_INVALID_INDEX32;222 size = adjusted->size;223 addr = adjusted->addr;224 225 // Check if we are setting watchpoint other than read/write/access Also226 // update watchpoint flag to match ARM/AArch64/LoongArch write-read bit227 // configuration.228 switch (watch_flags) {229 case lldb::eWatchpointKindWrite:230 watch_flags = 2;231 break;232 case lldb::eWatchpointKindRead:233 watch_flags = 1;234 break;235 case (lldb::eWatchpointKindRead | lldb::eWatchpointKindWrite):236 break;237 default:238 return LLDB_INVALID_INDEX32;239 }240 241 control_value = MakeWatchControlValue(size, watch_flags);242 243 // Iterate over stored watchpoints and find a free wp_index244 wp_index = LLDB_INVALID_INDEX32;245 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {246 if (!WatchpointIsEnabled(i))247 wp_index = i; // Mark last free slot248 else if (m_hwp_regs[i].address == addr) {249 return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints.250 }251 }252 253 if (wp_index == LLDB_INVALID_INDEX32)254 return LLDB_INVALID_INDEX32;255 256 // Update watchpoint in local cache257 m_hwp_regs[wp_index].real_addr = real_addr;258 m_hwp_regs[wp_index].address = addr;259 m_hwp_regs[wp_index].control = control_value;260 261 // PTRACE call to set corresponding watchpoint register.262 error = WriteHardwareDebugRegs(eDREGTypeWATCH);263 264 if (error) {265 m_hwp_regs[wp_index].address = 0;266 m_hwp_regs[wp_index].control &= ~m_hw_dbg_enable_bit;267 268 LLDB_LOG_ERROR(269 log, std::move(error),270 "unable to set watchpoint: failed to write debug registers: {0}");271 return LLDB_INVALID_INDEX32;272 }273 274 return wp_index;275}276 277bool NativeRegisterContextDBReg::ClearHardwareWatchpoint(uint32_t wp_index) {278 Log *log = GetLog(LLDBLog::Watchpoints);279 LLDB_LOG(log, "wp_index: {0}", wp_index);280 281 // Read hardware breakpoint and watchpoint information.282 llvm::Error error = ReadHardwareDebugInfo();283 if (error) {284 LLDB_LOG_ERROR(285 log, std::move(error),286 "unable to set watchpoint: failed to read debug registers: {0}");287 return false;288 }289 290 if (wp_index >= m_max_hwp_supported)291 return false;292 293 // Create a backup we can revert to in case of failure.294 lldb::addr_t tempAddr = m_hwp_regs[wp_index].address;295 uint32_t tempControl = m_hwp_regs[wp_index].control;296 297 // Update watchpoint in local cache298 m_hwp_regs[wp_index].control &= ~m_hw_dbg_enable_bit;299 m_hwp_regs[wp_index].address = 0;300 301 // Ptrace call to update hardware debug registers302 error = WriteHardwareDebugRegs(eDREGTypeWATCH);303 304 if (error) {305 m_hwp_regs[wp_index].control = tempControl;306 m_hwp_regs[wp_index].address = tempAddr;307 308 LLDB_LOG_ERROR(309 log, std::move(error),310 "unable to clear watchpoint: failed to read debug registers: {0}");311 return false;312 }313 314 return true;315}316 317Status NativeRegisterContextDBReg::ClearAllHardwareWatchpoints() {318 // Read hardware breakpoint and watchpoint information.319 llvm::Error error = ReadHardwareDebugInfo();320 if (error)321 return Status::FromError(std::move(error));322 323 for (uint32_t i = 0; i < m_max_hwp_supported; i++) {324 if (!WatchpointIsEnabled(i))325 continue;326 // Create a backup we can revert to in case of failure.327 lldb::addr_t tempAddr = m_hwp_regs[i].address;328 uint32_t tempControl = m_hwp_regs[i].control;329 330 // Clear watchpoints in local cache331 m_hwp_regs[i].control = 0;332 m_hwp_regs[i].address = 0;333 334 // Ptrace call to update hardware debug registers335 error = WriteHardwareDebugRegs(eDREGTypeWATCH);336 337 if (error) {338 m_hwp_regs[i].control = tempControl;339 m_hwp_regs[i].address = tempAddr;340 341 return Status::FromError(std::move(error));342 }343 }344 345 return Status();346}347 348Status349NativeRegisterContextDBReg::GetWatchpointHitIndex(uint32_t &wp_index,350 lldb::addr_t trap_addr) {351 Log *log = GetLog(LLDBLog::Watchpoints);352 LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr);353 354 // Read hardware breakpoint and watchpoint information.355 llvm::Error error = ReadHardwareDebugInfo();356 if (error)357 return Status::FromError(std::move(error));358 359 // AArch64 need mask off ignored bits from watchpoint trap address.360 trap_addr = FixWatchpointHitAddress(trap_addr);361 362 uint32_t watch_size;363 lldb::addr_t watch_addr;364 365 for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) {366 watch_size = GetWatchpointSize(wp_index);367 watch_addr = m_hwp_regs[wp_index].address;368 369 if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr &&370 trap_addr < watch_addr + watch_size) {371 m_hwp_regs[wp_index].hit_addr = trap_addr;372 return Status();373 }374 }375 376 wp_index = LLDB_INVALID_INDEX32;377 return Status();378}379 380bool NativeRegisterContextDBReg::WatchpointIsEnabled(uint32_t wp_index) {381 Log *log = GetLog(LLDBLog::Watchpoints);382 LLDB_LOG(log, "wp_index: {0}", wp_index);383 return ((m_hwp_regs[wp_index].control & m_hw_dbg_enable_bit) != 0);384}385 386lldb::addr_t387NativeRegisterContextDBReg::GetWatchpointAddress(uint32_t wp_index) {388 Log *log = GetLog(LLDBLog::Watchpoints);389 LLDB_LOG(log, "wp_index: {0}", wp_index);390 391 if (wp_index >= m_max_hwp_supported)392 return LLDB_INVALID_ADDRESS;393 394 if (WatchpointIsEnabled(wp_index))395 return m_hwp_regs[wp_index].real_addr;396 return LLDB_INVALID_ADDRESS;397}398 399lldb::addr_t400NativeRegisterContextDBReg::GetWatchpointHitAddress(uint32_t wp_index) {401 Log *log = GetLog(LLDBLog::Watchpoints);402 LLDB_LOG(log, "wp_index: {0}", wp_index);403 404 if (wp_index >= m_max_hwp_supported)405 return LLDB_INVALID_ADDRESS;406 407 if (WatchpointIsEnabled(wp_index))408 return m_hwp_regs[wp_index].hit_addr;409 return LLDB_INVALID_ADDRESS;410}411