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 std::find_if( |
64 | first: m_break_loc_collection.begin(), |
65 | last: m_break_loc_collection.end(), // Search full range |
66 | pred: BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate |
67 | } |
68 | |
69 | BreakpointLocationCollection::collection::const_iterator |
70 | BreakpointLocationCollection::GetIDPairConstIterator( |
71 | lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const { |
72 | return std::find_if( |
73 | first: m_break_loc_collection.begin(), |
74 | last: m_break_loc_collection.end(), // Search full range |
75 | pred: BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate |
76 | } |
77 | |
78 | BreakpointLocationSP |
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 | |
89 | 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 | |
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 |
110 | 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 | |
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 | |
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 | |
151 | 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 | |
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(ch: ' '); |
176 | (*pos)->GetDescription(s, level); |
177 | } |
178 | } |
179 | |
180 | BreakpointLocationCollection &BreakpointLocationCollection::operator=( |
181 | const BreakpointLocationCollection &rhs) { |
182 | if (this != &rhs) { |
183 | std::lock(l1&: m_collection_mutex, l2&: 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 | |