| 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-exception |
| 6 | // |
| 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 | |
| 16 | using namespace lldb; |
| 17 | using namespace lldb_private; |
| 18 | |
| 19 | // BreakpointLocationCollection constructor |
| 20 | BreakpointLocationCollection::BreakpointLocationCollection() = default; |
| 21 | |
| 22 | // Destructor |
| 23 | BreakpointLocationCollection::~BreakpointLocationCollection() = default; |
| 24 | |
| 25 | void BreakpointLocationCollection::Add(const BreakpointLocationSP &bp_loc) { |
| 26 | std::lock_guard<std::mutex> guard(m_collection_mutex); |
| 27 | BreakpointLocationSP old_bp_loc = |
| 28 | FindByIDPair(break_id: bp_loc->GetBreakpoint().GetID(), break_loc_id: bp_loc->GetID()); |
| 29 | if (!old_bp_loc.get()) |
| 30 | m_break_loc_collection.push_back(x: bp_loc); |
| 31 | } |
| 32 | |
| 33 | bool BreakpointLocationCollection::Remove(lldb::break_id_t bp_id, |
| 34 | lldb::break_id_t bp_loc_id) { |
| 35 | std::lock_guard<std::mutex> guard(m_collection_mutex); |
| 36 | collection::iterator pos = GetIDPairIterator(break_id: bp_id, break_loc_id: bp_loc_id); // Predicate |
| 37 | if (pos != m_break_loc_collection.end()) { |
| 38 | m_break_loc_collection.erase(position: pos); |
| 39 | return true; |
| 40 | } |
| 41 | return false; |
| 42 | } |
| 43 | |
| 44 | class BreakpointIDPairMatches { |
| 45 | public: |
| 46 | BreakpointIDPairMatches(lldb::break_id_t break_id, |
| 47 | lldb::break_id_t break_loc_id) |
| 48 | : m_break_id(break_id), m_break_loc_id(break_loc_id) {} |
| 49 | |
| 50 | bool operator()(const BreakpointLocationSP &bp_loc) const { |
| 51 | return m_break_id == bp_loc->GetBreakpoint().GetID() && |
| 52 | m_break_loc_id == bp_loc->GetID(); |
| 53 | } |
| 54 | |
| 55 | private: |
| 56 | const lldb::break_id_t m_break_id; |
| 57 | const lldb::break_id_t m_break_loc_id; |
| 58 | }; |
| 59 | |
| 60 | BreakpointLocationCollection::collection::iterator |
| 61 | BreakpointLocationCollection::GetIDPairIterator(lldb::break_id_t break_id, |
| 62 | lldb::break_id_t break_loc_id) { |
| 63 | return llvm::find_if( |
| 64 | Range&: m_break_loc_collection, // Search full range |
| 65 | P: BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate |
| 66 | } |
| 67 | |
| 68 | BreakpointLocationCollection::collection::const_iterator |
| 69 | BreakpointLocationCollection::GetIDPairConstIterator( |
| 70 | lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const { |
| 71 | return llvm::find_if( |
| 72 | Range: m_break_loc_collection, // Search full range |
| 73 | P: BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate |
| 74 | } |
| 75 | |
| 76 | BreakpointLocationSP |
| 77 | BreakpointLocationCollection::FindByIDPair(lldb::break_id_t break_id, |
| 78 | lldb::break_id_t break_loc_id) { |
| 79 | BreakpointLocationSP stop_sp; |
| 80 | collection::iterator pos = GetIDPairIterator(break_id, break_loc_id); |
| 81 | if (pos != m_break_loc_collection.end()) |
| 82 | stop_sp = *pos; |
| 83 | |
| 84 | return stop_sp; |
| 85 | } |
| 86 | |
| 87 | const BreakpointLocationSP BreakpointLocationCollection::FindByIDPair( |
| 88 | lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const { |
| 89 | BreakpointLocationSP stop_sp; |
| 90 | collection::const_iterator pos = |
| 91 | GetIDPairConstIterator(break_id, break_loc_id); |
| 92 | if (pos != m_break_loc_collection.end()) |
| 93 | stop_sp = *pos; |
| 94 | |
| 95 | return stop_sp; |
| 96 | } |
| 97 | |
| 98 | BreakpointLocationSP BreakpointLocationCollection::GetByIndex(size_t i) { |
| 99 | std::lock_guard<std::mutex> guard(m_collection_mutex); |
| 100 | BreakpointLocationSP stop_sp; |
| 101 | if (i < m_break_loc_collection.size()) |
| 102 | stop_sp = m_break_loc_collection[i]; |
| 103 | |
| 104 | return stop_sp; |
| 105 | } |
| 106 | |
| 107 | const BreakpointLocationSP |
| 108 | BreakpointLocationCollection::GetByIndex(size_t i) const { |
| 109 | std::lock_guard<std::mutex> guard(m_collection_mutex); |
| 110 | BreakpointLocationSP stop_sp; |
| 111 | if (i < m_break_loc_collection.size()) |
| 112 | stop_sp = m_break_loc_collection[i]; |
| 113 | |
| 114 | return stop_sp; |
| 115 | } |
| 116 | |
| 117 | bool BreakpointLocationCollection::ShouldStop( |
| 118 | StoppointCallbackContext *context) { |
| 119 | bool shouldStop = false; |
| 120 | size_t i = 0; |
| 121 | size_t prev_size = GetSize(); |
| 122 | while (i < prev_size) { |
| 123 | // ShouldStop can remove the breakpoint from the list, or even delete |
| 124 | // it, so we should |
| 125 | BreakpointLocationSP cur_loc_sp = GetByIndex(i); |
| 126 | BreakpointSP keep_bkpt_alive_sp = cur_loc_sp->GetBreakpoint().shared_from_this(); |
| 127 | if (cur_loc_sp->ShouldStop(context)) |
| 128 | shouldStop = true; |
| 129 | |
| 130 | if (prev_size == GetSize()) |
| 131 | i++; |
| 132 | prev_size = GetSize(); |
| 133 | } |
| 134 | return shouldStop; |
| 135 | } |
| 136 | |
| 137 | bool BreakpointLocationCollection::ValidForThisThread(Thread &thread) { |
| 138 | std::lock_guard<std::mutex> guard(m_collection_mutex); |
| 139 | collection::iterator pos, begin = m_break_loc_collection.begin(), |
| 140 | end = m_break_loc_collection.end(); |
| 141 | |
| 142 | for (pos = begin; pos != end; ++pos) { |
| 143 | if ((*pos)->ValidForThisThread(thread)) |
| 144 | return true; |
| 145 | } |
| 146 | return false; |
| 147 | } |
| 148 | |
| 149 | bool BreakpointLocationCollection::IsInternal() const { |
| 150 | std::lock_guard<std::mutex> guard(m_collection_mutex); |
| 151 | collection::const_iterator pos, begin = m_break_loc_collection.begin(), |
| 152 | end = m_break_loc_collection.end(); |
| 153 | |
| 154 | bool is_internal = true; |
| 155 | |
| 156 | for (pos = begin; pos != end; ++pos) { |
| 157 | if (!(*pos)->GetBreakpoint().IsInternal()) { |
| 158 | is_internal = false; |
| 159 | break; |
| 160 | } |
| 161 | } |
| 162 | return is_internal; |
| 163 | } |
| 164 | |
| 165 | void BreakpointLocationCollection::GetDescription( |
| 166 | Stream *s, lldb::DescriptionLevel level) { |
| 167 | std::lock_guard<std::mutex> guard(m_collection_mutex); |
| 168 | collection::iterator pos, begin = m_break_loc_collection.begin(), |
| 169 | end = m_break_loc_collection.end(); |
| 170 | |
| 171 | for (pos = begin; pos != end; ++pos) { |
| 172 | if (pos != begin) |
| 173 | s->PutChar(ch: ' '); |
| 174 | (*pos)->GetDescription(s, level); |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | BreakpointLocationCollection &BreakpointLocationCollection::operator=( |
| 179 | const BreakpointLocationCollection &rhs) { |
| 180 | if (this != &rhs) { |
| 181 | std::lock(l1&: m_collection_mutex, l2&: rhs.m_collection_mutex); |
| 182 | std::lock_guard<std::mutex> lhs_guard(m_collection_mutex, std::adopt_lock); |
| 183 | std::lock_guard<std::mutex> rhs_guard(rhs.m_collection_mutex, std::adopt_lock); |
| 184 | m_break_loc_collection = rhs.m_break_loc_collection; |
| 185 | } |
| 186 | return *this; |
| 187 | } |
| 188 | |