brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.1 KiB · e41bf9b Raw
217 lines · cpp
1//===-- DNBBreakpoint.cpp ---------------------------------------*- C++ -*-===//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//  Created by Greg Clayton on 6/29/07.10//11//===----------------------------------------------------------------------===//12 13#include "DNBBreakpoint.h"14#include "DNBLog.h"15#include "MachProcess.h"16#include <algorithm>17#include <cassert>18#include <cinttypes>19 20#pragma mark-- DNBBreakpoint21DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size,22                             bool hardware)23    : m_retain_count(1), m_byte_size(static_cast<uint32_t>(byte_size)),24      m_opcode(), m_addr(addr), m_enabled(0), m_hw_preferred(hardware),25      m_is_watchpoint(0), m_watch_read(0), m_watch_write(0),26      m_hw_index(INVALID_NUB_HW_INDEX) {}27 28DNBBreakpoint::~DNBBreakpoint() = default;29 30void DNBBreakpoint::Dump() const {31  if (IsBreakpoint()) {32    DNBLog("DNBBreakpoint addr = 0x%llx  state = %s  type = %s breakpoint  "33           "hw_index = %i",34           (uint64_t)m_addr, m_enabled ? "enabled " : "disabled",35           IsHardware() ? "hardware" : "software", GetHardwareIndex());36  } else {37    DNBLog("DNBBreakpoint addr = 0x%llx  size = %llu  state = %s  type = %s "38           "watchpoint (%s%s)  hw_index = %i",39           (uint64_t)m_addr, (uint64_t)m_byte_size,40           m_enabled ? "enabled " : "disabled",41           IsHardware() ? "hardware" : "software", m_watch_read ? "r" : "",42           m_watch_write ? "w" : "", GetHardwareIndex());43  }44}45 46#pragma mark-- DNBBreakpointList47 48DNBBreakpointList::DNBBreakpointList() = default;49 50DNBBreakpointList::~DNBBreakpointList() = default;51 52DNBBreakpoint *DNBBreakpointList::Add(nub_addr_t addr, nub_size_t length,53                                      bool hardware) {54  m_breakpoints.insert(55      std::make_pair(addr, DNBBreakpoint(addr, length, hardware)));56  iterator pos = m_breakpoints.find(addr);57  return &pos->second;58}59 60bool DNBBreakpointList::Remove(nub_addr_t addr) {61  iterator pos = m_breakpoints.find(addr);62  if (pos != m_breakpoints.end()) {63    m_breakpoints.erase(pos);64    return true;65  }66  return false;67}68 69DNBBreakpoint *DNBBreakpointList::FindByAddress(nub_addr_t addr) {70  iterator pos = m_breakpoints.find(addr);71  if (pos != m_breakpoints.end())72    return &pos->second;73 74  return NULL;75}76 77const DNBBreakpoint *DNBBreakpointList::FindByAddress(nub_addr_t addr) const {78  const_iterator pos = m_breakpoints.find(addr);79  if (pos != m_breakpoints.end())80    return &pos->second;81 82  return NULL;83}84 85const DNBBreakpoint *86DNBBreakpointList::FindByHardwareIndex(uint32_t idx) const {87  for (const auto &pos : m_breakpoints)88    if (pos.second.GetHardwareIndex() == idx)89      return &pos.second;90 91  return nullptr;92}93 94const DNBBreakpoint *95DNBBreakpointList::FindNearestWatchpoint(nub_addr_t addr) const {96  // Exact match97  for (const auto &pos : m_breakpoints) {98    if (pos.second.IsEnabled()) {99      nub_addr_t start_addr = pos.second.Address();100      nub_addr_t end_addr = start_addr + pos.second.ByteSize();101      if (addr >= start_addr && addr < end_addr)102        return &pos.second;103    }104  }105 106  // Find watchpoint nearest to this address107  // before or after the watched region of memory108  const DNBBreakpoint *closest = nullptr;109  uint32_t best_match = UINT32_MAX;110  for (const auto &pos : m_breakpoints) {111    if (pos.second.IsEnabled()) {112      nub_addr_t start_addr = pos.second.Address();113      nub_addr_t end_addr = start_addr + pos.second.ByteSize();114      uint32_t delta = addr < start_addr ? start_addr - addr : addr - end_addr;115      if (delta < best_match) {116        closest = &pos.second;117        best_match = delta;118      }119    }120  }121  return closest;122}123 124// Finds the next breakpoint at an address greater than or equal to "addr"125size_t DNBBreakpointList::FindBreakpointsThatOverlapRange(126    nub_addr_t addr, nub_addr_t size, std::vector<DNBBreakpoint *> &bps) {127  bps.clear();128  iterator end = m_breakpoints.end();129  // Find the first breakpoint with an address >= to "addr"130  iterator pos = m_breakpoints.lower_bound(addr);131  if (pos != end) {132    if (pos != m_breakpoints.begin()) {133      // Watch out for a breakpoint at an address less than "addr" that might134      // still overlap135      iterator prev_pos = pos;136      --prev_pos;137      if (prev_pos->second.IntersectsRange(addr, size, NULL, NULL, NULL))138        bps.push_back(&pos->second);139    }140 141    while (pos != end) {142      // When we hit a breakpoint whose start address is greater than "addr +143      // size" we are done.144      // Do the math in a way that doesn't risk unsigned overflow with bad145      // input.146      if ((pos->second.Address() - addr) >= size)147        break;148 149      // Check if this breakpoint overlaps, and if it does, add it to the list150      if (pos->second.IntersectsRange(addr, size, NULL, NULL, NULL)) {151        bps.push_back(&pos->second);152        ++pos;153      }154    }155  }156  return bps.size();157}158 159void DNBBreakpointList::Dump() const {160  const_iterator pos;161  const_iterator end = m_breakpoints.end();162  for (pos = m_breakpoints.begin(); pos != end; ++pos)163    pos->second.Dump();164}165 166void DNBBreakpointList::DisableAll() {167  iterator pos, end = m_breakpoints.end();168  for (pos = m_breakpoints.begin(); pos != end; ++pos)169    pos->second.SetEnabled(false);170}171 172void DNBBreakpointList::RemoveTrapsFromBuffer(nub_addr_t addr, nub_size_t size,173                                              void *p) const {174  uint8_t *buf = (uint8_t *)p;175  const_iterator end = m_breakpoints.end();176  const_iterator pos = m_breakpoints.lower_bound(addr);177  while (pos != end && (pos->first < (addr + size))) {178    nub_addr_t intersect_addr;179    nub_size_t intersect_size;180    nub_size_t opcode_offset;181    const DNBBreakpoint &bp = pos->second;182    if (bp.IntersectsRange(addr, size, &intersect_addr, &intersect_size,183                           &opcode_offset)) {184      assert(addr <= intersect_addr && intersect_addr < addr + size);185      assert(addr < intersect_addr + intersect_size &&186             intersect_addr + intersect_size <= addr + size);187      assert(opcode_offset + intersect_size <= bp.ByteSize());188      nub_size_t buf_offset = intersect_addr - addr;189      ::memcpy(buf + buf_offset, bp.SavedOpcodeBytes() + opcode_offset,190               intersect_size);191    }192    ++pos;193  }194}195 196void DNBBreakpointList::DisableAllBreakpoints(MachProcess *process) {197  iterator pos, end = m_breakpoints.end();198  for (pos = m_breakpoints.begin(); pos != end; ++pos)199    process->DisableBreakpoint(pos->second.Address(), false);200}201 202void DNBBreakpointList::DisableAllWatchpoints(MachProcess *process) {203  iterator pos, end = m_breakpoints.end();204  for (pos = m_breakpoints.begin(); pos != end; ++pos)205    process->DisableWatchpoint(pos->second.Address(), false);206}207 208void DNBBreakpointList::RemoveDisabled() {209  iterator pos = m_breakpoints.begin();210  while (pos != m_breakpoints.end()) {211    if (!pos->second.IsEnabled())212      pos = m_breakpoints.erase(pos);213    else214      ++pos;215  }216}217