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