223 lines · cpp
1//===-- BreakpointLocationCollection.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 "lldb/Breakpoint/BreakpointLocationCollection.h"10#include "lldb/Breakpoint/Breakpoint.h"11#include "lldb/Breakpoint/BreakpointLocation.h"12#include "lldb/Core/ModuleList.h"13#include "lldb/Target/Thread.h"14#include "lldb/Target/ThreadSpec.h"15 16using namespace lldb;17using namespace lldb_private;18 19// BreakpointLocationCollection constructor20BreakpointLocationCollection::BreakpointLocationCollection(bool preserving)21 : m_preserving_bkpts(preserving) {}22 23// Destructor24BreakpointLocationCollection::~BreakpointLocationCollection() = default;25 26void BreakpointLocationCollection::Add(const BreakpointLocationSP &bp_loc) {27 std::lock_guard<std::recursive_mutex> guard(m_collection_mutex);28 BreakpointLocationSP old_bp_loc =29 FindByIDPair(bp_loc->GetBreakpoint().GetID(), bp_loc->GetID());30 if (!old_bp_loc.get()) {31 m_break_loc_collection.push_back(bp_loc);32 if (m_preserving_bkpts) {33 lldb::break_id_t bp_loc_id = bp_loc->GetID();34 Breakpoint &bkpt = bp_loc->GetBreakpoint();35 lldb::break_id_t bp_id = bkpt.GetID();36 std::pair<lldb::break_id_t, lldb::break_id_t> key =37 std::make_pair(bp_id, bp_loc_id);38 auto entry = m_preserved_bps.find(key);39 if (entry == m_preserved_bps.end())40 m_preserved_bps.emplace(key, bkpt.shared_from_this());41 }42 }43}44 45bool BreakpointLocationCollection::Remove(lldb::break_id_t bp_id,46 lldb::break_id_t bp_loc_id) {47 std::lock_guard<std::recursive_mutex> guard(m_collection_mutex);48 collection::iterator pos = GetIDPairIterator(bp_id, bp_loc_id); // Predicate49 if (pos != m_break_loc_collection.end()) {50 if (m_preserving_bkpts) {51 std::pair<lldb::break_id_t, lldb::break_id_t> key =52 std::make_pair(bp_id, bp_loc_id);53 auto entry = m_preserved_bps.find(key);54 if (entry == m_preserved_bps.end())55 assert(0 && "Breakpoint added to collection but not preserving map.");56 else57 m_preserved_bps.erase(entry);58 }59 m_break_loc_collection.erase(pos);60 return true;61 }62 return false;63}64 65class BreakpointIDPairMatches {66public:67 BreakpointIDPairMatches(lldb::break_id_t break_id,68 lldb::break_id_t break_loc_id)69 : m_break_id(break_id), m_break_loc_id(break_loc_id) {}70 71 bool operator()(const BreakpointLocationSP &bp_loc) const {72 return m_break_id == bp_loc->GetBreakpoint().GetID() &&73 m_break_loc_id == bp_loc->GetID();74 }75 76private:77 const lldb::break_id_t m_break_id;78 const lldb::break_id_t m_break_loc_id;79};80 81BreakpointLocationCollection::collection::iterator82BreakpointLocationCollection::GetIDPairIterator(lldb::break_id_t break_id,83 lldb::break_id_t break_loc_id) {84 return llvm::find_if(85 m_break_loc_collection, // Search full range86 BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate87}88 89BreakpointLocationCollection::collection::const_iterator90BreakpointLocationCollection::GetIDPairConstIterator(91 lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const {92 return llvm::find_if(93 m_break_loc_collection, // Search full range94 BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate95}96 97BreakpointLocationSP98BreakpointLocationCollection::FindByIDPair(lldb::break_id_t break_id,99 lldb::break_id_t break_loc_id) {100 BreakpointLocationSP stop_sp;101 collection::iterator pos = GetIDPairIterator(break_id, break_loc_id);102 if (pos != m_break_loc_collection.end())103 stop_sp = *pos;104 105 return stop_sp;106}107 108const BreakpointLocationSP BreakpointLocationCollection::FindByIDPair(109 lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const {110 BreakpointLocationSP stop_sp;111 collection::const_iterator pos =112 GetIDPairConstIterator(break_id, break_loc_id);113 if (pos != m_break_loc_collection.end())114 stop_sp = *pos;115 116 return stop_sp;117}118 119BreakpointLocationSP BreakpointLocationCollection::GetByIndex(size_t i) {120 std::lock_guard<std::recursive_mutex> guard(m_collection_mutex);121 BreakpointLocationSP stop_sp;122 if (i < m_break_loc_collection.size())123 stop_sp = m_break_loc_collection[i];124 125 return stop_sp;126}127 128const BreakpointLocationSP129BreakpointLocationCollection::GetByIndex(size_t i) const {130 std::lock_guard<std::recursive_mutex> guard(m_collection_mutex);131 BreakpointLocationSP stop_sp;132 if (i < m_break_loc_collection.size())133 stop_sp = m_break_loc_collection[i];134 135 return stop_sp;136}137 138bool BreakpointLocationCollection::ShouldStop(139 StoppointCallbackContext *context,140 BreakpointLocationCollection &stopped_bp_locs) {141 bool shouldStop = false;142 size_t i = 0;143 size_t prev_size = GetSize();144 while (i < prev_size) {145 // ShouldStop can remove the breakpoint from the list, or even delete146 // it, so we should147 BreakpointLocationSP cur_loc_sp = GetByIndex(i);148 BreakpointLocationSP reported_loc_sp;149 BreakpointSP keep_bkpt_alive_sp = cur_loc_sp->GetBreakpoint().shared_from_this();150 // We're building up the list or which locations claim responsibility for151 // this stop. If the location's ShouldStop defers to a facade location by152 // returning a non-null reported location, we want to use that. Otherwise153 // use the original location.154 if (cur_loc_sp->ShouldStop(context, reported_loc_sp)) {155 if (reported_loc_sp)156 stopped_bp_locs.Add(reported_loc_sp);157 else158 stopped_bp_locs.Add(cur_loc_sp);159 160 shouldStop = true;161 }162 163 if (prev_size == GetSize())164 i++;165 prev_size = GetSize();166 }167 return shouldStop;168}169 170bool BreakpointLocationCollection::ValidForThisThread(Thread &thread) {171 std::lock_guard<std::recursive_mutex> guard(m_collection_mutex);172 collection::iterator pos, begin = m_break_loc_collection.begin(),173 end = m_break_loc_collection.end();174 175 for (pos = begin; pos != end; ++pos) {176 if ((*pos)->ValidForThisThread(thread))177 return true;178 }179 return false;180}181 182bool BreakpointLocationCollection::IsInternal() const {183 std::lock_guard<std::recursive_mutex> guard(m_collection_mutex);184 collection::const_iterator pos, begin = m_break_loc_collection.begin(),185 end = m_break_loc_collection.end();186 187 bool is_internal = true;188 189 for (pos = begin; pos != end; ++pos) {190 if (!(*pos)->GetBreakpoint().IsInternal()) {191 is_internal = false;192 break;193 }194 }195 return is_internal;196}197 198void BreakpointLocationCollection::GetDescription(199 Stream *s, lldb::DescriptionLevel level) {200 std::lock_guard<std::recursive_mutex> guard(m_collection_mutex);201 collection::iterator pos, begin = m_break_loc_collection.begin(),202 end = m_break_loc_collection.end();203 204 for (pos = begin; pos != end; ++pos) {205 if (pos != begin)206 s->PutChar(' ');207 (*pos)->GetDescription(s, level);208 }209}210 211BreakpointLocationCollection &BreakpointLocationCollection::operator=(212 const BreakpointLocationCollection &rhs) {213 if (this != &rhs) {214 std::lock(m_collection_mutex, rhs.m_collection_mutex);215 std::lock_guard<std::recursive_mutex> lhs_guard(m_collection_mutex,216 std::adopt_lock);217 std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_collection_mutex,218 std::adopt_lock);219 m_break_loc_collection = rhs.m_break_loc_collection;220 }221 return *this;222}223