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