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 | |