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