1 //===-- BreakpointList.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/BreakpointList.h"
10
11 #include "lldb/Target/Target.h"
12
13 #include "llvm/Support/Errc.h"
14
15 using namespace lldb;
16 using namespace lldb_private;
17
NotifyChange(const BreakpointSP & bp,BreakpointEventType event)18 static void NotifyChange(const BreakpointSP &bp, BreakpointEventType event) {
19 Target &target = bp->GetTarget();
20 if (target.EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
21 target.BroadcastEvent(Target::eBroadcastBitBreakpointChanged,
22 new Breakpoint::BreakpointEventData(event, bp));
23 }
24
BreakpointList(bool is_internal)25 BreakpointList::BreakpointList(bool is_internal)
26 : m_next_break_id(0), m_is_internal(is_internal) {}
27
28 BreakpointList::~BreakpointList() = default;
29
Add(BreakpointSP & bp_sp,bool notify)30 break_id_t BreakpointList::Add(BreakpointSP &bp_sp, bool notify) {
31 std::lock_guard<std::recursive_mutex> guard(m_mutex);
32
33 // Internal breakpoint IDs are negative, normal ones are positive
34 bp_sp->SetID(m_is_internal ? --m_next_break_id : ++m_next_break_id);
35
36 m_breakpoints.push_back(bp_sp);
37
38 if (notify)
39 NotifyChange(bp_sp, eBreakpointEventTypeAdded);
40
41 return bp_sp->GetID();
42 }
43
Remove(break_id_t break_id,bool notify)44 bool BreakpointList::Remove(break_id_t break_id, bool notify) {
45 std::lock_guard<std::recursive_mutex> guard(m_mutex);
46
47 auto it = std::find_if(
48 m_breakpoints.begin(), m_breakpoints.end(),
49 [&](const BreakpointSP &bp) { return bp->GetID() == break_id; });
50
51 if (it == m_breakpoints.end())
52 return false;
53
54 if (notify)
55 NotifyChange(*it, eBreakpointEventTypeRemoved);
56
57 m_breakpoints.erase(it);
58
59 return true;
60 }
61
RemoveInvalidLocations(const ArchSpec & arch)62 void BreakpointList::RemoveInvalidLocations(const ArchSpec &arch) {
63 std::lock_guard<std::recursive_mutex> guard(m_mutex);
64 for (const auto &bp_sp : m_breakpoints)
65 bp_sp->RemoveInvalidLocations(arch);
66 }
67
SetEnabledAll(bool enabled)68 void BreakpointList::SetEnabledAll(bool enabled) {
69 std::lock_guard<std::recursive_mutex> guard(m_mutex);
70 for (const auto &bp_sp : m_breakpoints)
71 bp_sp->SetEnabled(enabled);
72 }
73
SetEnabledAllowed(bool enabled)74 void BreakpointList::SetEnabledAllowed(bool enabled) {
75 std::lock_guard<std::recursive_mutex> guard(m_mutex);
76 for (const auto &bp_sp : m_breakpoints)
77 if (bp_sp->AllowDisable())
78 bp_sp->SetEnabled(enabled);
79 }
80
RemoveAll(bool notify)81 void BreakpointList::RemoveAll(bool notify) {
82 std::lock_guard<std::recursive_mutex> guard(m_mutex);
83 ClearAllBreakpointSites();
84
85 if (notify) {
86 for (const auto &bp_sp : m_breakpoints)
87 NotifyChange(bp_sp, eBreakpointEventTypeRemoved);
88 }
89
90 m_breakpoints.clear();
91 }
92
RemoveAllowed(bool notify)93 void BreakpointList::RemoveAllowed(bool notify) {
94 std::lock_guard<std::recursive_mutex> guard(m_mutex);
95
96 for (const auto &bp_sp : m_breakpoints) {
97 if (bp_sp->AllowDelete())
98 bp_sp->ClearAllBreakpointSites();
99 if (notify)
100 NotifyChange(bp_sp, eBreakpointEventTypeRemoved);
101 }
102
103 llvm::erase_if(m_breakpoints,
104 [&](const BreakpointSP &bp) { return bp->AllowDelete(); });
105 }
106
107 BreakpointList::bp_collection::iterator
GetBreakpointIDIterator(break_id_t break_id)108 BreakpointList::GetBreakpointIDIterator(break_id_t break_id) {
109 return std::find_if(
110 m_breakpoints.begin(), m_breakpoints.end(),
111 [&](const BreakpointSP &bp) { return bp->GetID() == break_id; });
112 }
113
114 BreakpointList::bp_collection::const_iterator
GetBreakpointIDConstIterator(break_id_t break_id) const115 BreakpointList::GetBreakpointIDConstIterator(break_id_t break_id) const {
116 return std::find_if(
117 m_breakpoints.begin(), m_breakpoints.end(),
118 [&](const BreakpointSP &bp) { return bp->GetID() == break_id; });
119 }
120
FindBreakpointByID(break_id_t break_id) const121 BreakpointSP BreakpointList::FindBreakpointByID(break_id_t break_id) const {
122 std::lock_guard<std::recursive_mutex> guard(m_mutex);
123
124 auto it = GetBreakpointIDConstIterator(break_id);
125 if (it != m_breakpoints.end())
126 return *it;
127 return {};
128 }
129
130 llvm::Expected<std::vector<lldb::BreakpointSP>>
FindBreakpointsByName(const char * name)131 BreakpointList::FindBreakpointsByName(const char *name) {
132 if (!name)
133 return llvm::createStringError(llvm::errc::invalid_argument,
134 "FindBreakpointsByName requires a name");
135
136 Status error;
137 if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(name), error))
138 return error.ToError();
139
140 std::vector<lldb::BreakpointSP> matching_bps;
141 for (BreakpointSP bkpt_sp : Breakpoints()) {
142 if (bkpt_sp->MatchesName(name)) {
143 matching_bps.push_back(bkpt_sp);
144 }
145 }
146
147 return matching_bps;
148 }
149
Dump(Stream * s) const150 void BreakpointList::Dump(Stream *s) const {
151 std::lock_guard<std::recursive_mutex> guard(m_mutex);
152 s->Printf("%p: ", static_cast<const void *>(this));
153 s->Indent();
154 s->Printf("BreakpointList with %u Breakpoints:\n",
155 (uint32_t)m_breakpoints.size());
156 s->IndentMore();
157 for (const auto &bp_sp : m_breakpoints)
158 bp_sp->Dump(s);
159 s->IndentLess();
160 }
161
GetBreakpointAtIndex(size_t i) const162 BreakpointSP BreakpointList::GetBreakpointAtIndex(size_t i) const {
163 std::lock_guard<std::recursive_mutex> guard(m_mutex);
164 if (i < m_breakpoints.size())
165 return m_breakpoints[i];
166 return {};
167 }
168
UpdateBreakpoints(ModuleList & module_list,bool added,bool delete_locations)169 void BreakpointList::UpdateBreakpoints(ModuleList &module_list, bool added,
170 bool delete_locations) {
171 std::lock_guard<std::recursive_mutex> guard(m_mutex);
172 for (const auto &bp_sp : m_breakpoints)
173 bp_sp->ModulesChanged(module_list, added, delete_locations);
174 }
175
UpdateBreakpointsWhenModuleIsReplaced(ModuleSP old_module_sp,ModuleSP new_module_sp)176 void BreakpointList::UpdateBreakpointsWhenModuleIsReplaced(
177 ModuleSP old_module_sp, ModuleSP new_module_sp) {
178 std::lock_guard<std::recursive_mutex> guard(m_mutex);
179 for (const auto &bp_sp : m_breakpoints)
180 bp_sp->ModuleReplaced(old_module_sp, new_module_sp);
181 }
182
ClearAllBreakpointSites()183 void BreakpointList::ClearAllBreakpointSites() {
184 std::lock_guard<std::recursive_mutex> guard(m_mutex);
185 for (const auto &bp_sp : m_breakpoints)
186 bp_sp->ClearAllBreakpointSites();
187 }
188
ResetHitCounts()189 void BreakpointList::ResetHitCounts() {
190 std::lock_guard<std::recursive_mutex> guard(m_mutex);
191 for (const auto &bp_sp : m_breakpoints)
192 bp_sp->ResetHitCount();
193 }
194
GetListMutex(std::unique_lock<std::recursive_mutex> & lock)195 void BreakpointList::GetListMutex(
196 std::unique_lock<std::recursive_mutex> &lock) {
197 lock = std::unique_lock<std::recursive_mutex>(m_mutex);
198 }
199