brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.1 KiB · f35027e Raw
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