reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
//===-- BreakpointSiteList.cpp ----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "lldb/Breakpoint/BreakpointSiteList.h"

#include "lldb/Utility/Stream.h"
#include <algorithm>

using namespace lldb;
using namespace lldb_private;

BreakpointSiteList::BreakpointSiteList() : m_mutex(), m_bp_site_list() {}

BreakpointSiteList::~BreakpointSiteList() {}

// Add breakpoint site to the list.  However, if the element already exists in
// the list, then we don't add it, and return LLDB_INVALID_BREAK_ID.

lldb::break_id_t BreakpointSiteList::Add(const BreakpointSiteSP &bp) {
  lldb::addr_t bp_site_load_addr = bp->GetLoadAddress();
  std::lock_guard<std::recursive_mutex> guard(m_mutex);
  collection::iterator iter = m_bp_site_list.find(bp_site_load_addr);

  if (iter == m_bp_site_list.end()) {
    m_bp_site_list.insert(iter, collection::value_type(bp_site_load_addr, bp));
    return bp->GetID();
  } else {
    return LLDB_INVALID_BREAK_ID;
  }
}

bool BreakpointSiteList::ShouldStop(StoppointCallbackContext *context,
                                    lldb::break_id_t site_id) {
  BreakpointSiteSP site_sp(FindByID(site_id));
  if (site_sp) {
    // Let the BreakpointSite decide if it should stop here (could not have
    // reached it's target hit count yet, or it could have a callback that
    // decided it shouldn't stop (shared library loads/unloads).
    return site_sp->ShouldStop(context);
  }
  // We should stop here since this BreakpointSite isn't valid anymore or it
  // doesn't exist.
  return true;
}
lldb::break_id_t BreakpointSiteList::FindIDByAddress(lldb::addr_t addr) {
  BreakpointSiteSP bp = FindByAddress(addr);
  if (bp) {
    // DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8"
    // PRIx64 " ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID());
    return bp.get()->GetID();
  }
  // DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8"
  // PRIx64
  // " ) => NONE", __FUNCTION__, (uint64_t)addr);
  return LLDB_INVALID_BREAK_ID;
}

bool BreakpointSiteList::Remove(lldb::break_id_t break_id) {
  std::lock_guard<std::recursive_mutex> guard(m_mutex);
  collection::iterator pos = GetIDIterator(break_id); // Predicate
  if (pos != m_bp_site_list.end()) {
    m_bp_site_list.erase(pos);
    return true;
  }
  return false;
}

bool BreakpointSiteList::RemoveByAddress(lldb::addr_t address) {
  std::lock_guard<std::recursive_mutex> guard(m_mutex);
  collection::iterator pos = m_bp_site_list.find(address);
  if (pos != m_bp_site_list.end()) {
    m_bp_site_list.erase(pos);
    return true;
  }
  return false;
}

class BreakpointSiteIDMatches {
public:
  BreakpointSiteIDMatches(lldb::break_id_t break_id) : m_break_id(break_id) {}

  bool operator()(std::pair<lldb::addr_t, BreakpointSiteSP> val_pair) const {
    return m_break_id == val_pair.second->GetID();
  }

private:
  const lldb::break_id_t m_break_id;
};

BreakpointSiteList::collection::iterator
BreakpointSiteList::GetIDIterator(lldb::break_id_t break_id) {
  std::lock_guard<std::recursive_mutex> guard(m_mutex);
  return std::find_if(m_bp_site_list.begin(),
                      m_bp_site_list.end(),               // Search full range
                      BreakpointSiteIDMatches(break_id)); // Predicate
}

BreakpointSiteList::collection::const_iterator
BreakpointSiteList::GetIDConstIterator(lldb::break_id_t break_id) const {
  std::lock_guard<std::recursive_mutex> guard(m_mutex);
  return std::find_if(m_bp_site_list.begin(),
                      m_bp_site_list.end(),               // Search full range
                      BreakpointSiteIDMatches(break_id)); // Predicate
}

BreakpointSiteSP BreakpointSiteList::FindByID(lldb::break_id_t break_id) {
  std::lock_guard<std::recursive_mutex> guard(m_mutex);
  BreakpointSiteSP stop_sp;
  collection::iterator pos = GetIDIterator(break_id);
  if (pos != m_bp_site_list.end())
    stop_sp = pos->second;

  return stop_sp;
}

const BreakpointSiteSP
BreakpointSiteList::FindByID(lldb::break_id_t break_id) const {
  std::lock_guard<std::recursive_mutex> guard(m_mutex);
  BreakpointSiteSP stop_sp;
  collection::const_iterator pos = GetIDConstIterator(break_id);
  if (pos != m_bp_site_list.end())
    stop_sp = pos->second;

  return stop_sp;
}

BreakpointSiteSP BreakpointSiteList::FindByAddress(lldb::addr_t addr) {
  BreakpointSiteSP found_sp;
  std::lock_guard<std::recursive_mutex> guard(m_mutex);
  collection::iterator iter = m_bp_site_list.find(addr);
  if (iter != m_bp_site_list.end())
    found_sp = iter->second;
  return found_sp;
}

bool BreakpointSiteList::BreakpointSiteContainsBreakpoint(
    lldb::break_id_t bp_site_id, lldb::break_id_t bp_id) {
  std::lock_guard<std::recursive_mutex> guard(m_mutex);
  collection::const_iterator pos = GetIDConstIterator(bp_site_id);
  if (pos != m_bp_site_list.end())
    return pos->second->IsBreakpointAtThisSite(bp_id);

  return false;
}

void BreakpointSiteList::Dump(Stream *s) const {
  s->Printf("%p: ", static_cast<const void *>(this));
  // s->Indent();
  s->Printf("BreakpointSiteList with %u BreakpointSites:\n",
            (uint32_t)m_bp_site_list.size());
  s->IndentMore();
  collection::const_iterator pos;
  collection::const_iterator end = m_bp_site_list.end();
  for (pos = m_bp_site_list.begin(); pos != end; ++pos)
    pos->second->Dump(s);
  s->IndentLess();
}

void BreakpointSiteList::ForEach(
    std::function<void(BreakpointSite *)> const &callback) {
  std::lock_guard<std::recursive_mutex> guard(m_mutex);
  for (auto pair : m_bp_site_list)
    callback(pair.second.get());
}

bool BreakpointSiteList::FindInRange(lldb::addr_t lower_bound,
                                     lldb::addr_t upper_bound,
                                     BreakpointSiteList &bp_site_list) const {
  if (lower_bound > upper_bound)
    return false;

  std::lock_guard<std::recursive_mutex> guard(m_mutex);
  collection::const_iterator lower, upper, pos;
  lower = m_bp_site_list.lower_bound(lower_bound);
  if (lower == m_bp_site_list.end() || (*lower).first >= upper_bound)
    return false;

  // This is one tricky bit.  The breakpoint might overlap the bottom end of
  // the range.  So we grab the breakpoint prior to the lower bound, and check
  // that that + its byte size isn't in our range.
  if (lower != m_bp_site_list.begin()) {
    collection::const_iterator prev_pos = lower;
    prev_pos--;
    const BreakpointSiteSP &prev_bp = (*prev_pos).second;
    if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound)
      bp_site_list.Add(prev_bp);
  }

  upper = m_bp_site_list.upper_bound(upper_bound);

  for (pos = lower; pos != upper; pos++) {
    bp_site_list.Add((*pos).second);
  }
  return true;
}