xref: /freebsd/contrib/llvm-project/lldb/source/Breakpoint/BreakpointList.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
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 
18 static void NotifyChange(const BreakpointSP &bp, BreakpointEventType event) {
19   Target &target = bp->GetTarget();
20   if (target.EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged)) {
21     auto event_data_sp =
22         std::make_shared<Breakpoint::BreakpointEventData>(event, bp);
23     target.BroadcastEvent(Target::eBroadcastBitBreakpointChanged,
24                           event_data_sp);
25   }
26 }
27 
28 BreakpointList::BreakpointList(bool is_internal)
29     : m_next_break_id(0), m_is_internal(is_internal) {}
30 
31 BreakpointList::~BreakpointList() = default;
32 
33 break_id_t BreakpointList::Add(BreakpointSP &bp_sp, bool notify) {
34   std::lock_guard<std::recursive_mutex> guard(m_mutex);
35 
36   // Internal breakpoint IDs are negative, normal ones are positive
37   bp_sp->SetID(m_is_internal ? --m_next_break_id : ++m_next_break_id);
38 
39   m_breakpoints.push_back(bp_sp);
40 
41   if (notify)
42     NotifyChange(bp_sp, eBreakpointEventTypeAdded);
43 
44   return bp_sp->GetID();
45 }
46 
47 bool BreakpointList::Remove(break_id_t break_id, bool notify) {
48   std::lock_guard<std::recursive_mutex> guard(m_mutex);
49 
50   auto it = std::find_if(
51       m_breakpoints.begin(), m_breakpoints.end(),
52       [&](const BreakpointSP &bp) { return bp->GetID() == break_id; });
53 
54   if (it == m_breakpoints.end())
55     return false;
56 
57   if (notify)
58     NotifyChange(*it, eBreakpointEventTypeRemoved);
59 
60   m_breakpoints.erase(it);
61 
62   return true;
63 }
64 
65 void BreakpointList::RemoveInvalidLocations(const ArchSpec &arch) {
66   std::lock_guard<std::recursive_mutex> guard(m_mutex);
67   for (const auto &bp_sp : m_breakpoints)
68     bp_sp->RemoveInvalidLocations(arch);
69 }
70 
71 void BreakpointList::SetEnabledAll(bool enabled) {
72   std::lock_guard<std::recursive_mutex> guard(m_mutex);
73   for (const auto &bp_sp : m_breakpoints)
74     bp_sp->SetEnabled(enabled);
75 }
76 
77 void BreakpointList::SetEnabledAllowed(bool enabled) {
78   std::lock_guard<std::recursive_mutex> guard(m_mutex);
79   for (const auto &bp_sp : m_breakpoints)
80     if (bp_sp->AllowDisable())
81       bp_sp->SetEnabled(enabled);
82 }
83 
84 void BreakpointList::RemoveAll(bool notify) {
85   std::lock_guard<std::recursive_mutex> guard(m_mutex);
86   ClearAllBreakpointSites();
87 
88   if (notify) {
89     for (const auto &bp_sp : m_breakpoints)
90       NotifyChange(bp_sp, eBreakpointEventTypeRemoved);
91   }
92 
93   m_breakpoints.clear();
94 }
95 
96 void BreakpointList::RemoveAllowed(bool notify) {
97   std::lock_guard<std::recursive_mutex> guard(m_mutex);
98 
99   for (const auto &bp_sp : m_breakpoints) {
100     if (bp_sp->AllowDelete())
101       bp_sp->ClearAllBreakpointSites();
102     if (notify)
103       NotifyChange(bp_sp, eBreakpointEventTypeRemoved);
104   }
105 
106   llvm::erase_if(m_breakpoints,
107                  [&](const BreakpointSP &bp) { return bp->AllowDelete(); });
108 }
109 
110 BreakpointList::bp_collection::iterator
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
118 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 
124 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>>
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 
153 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 
165 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 
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 
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 
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 
192 void BreakpointList::ResetHitCounts() {
193   std::lock_guard<std::recursive_mutex> guard(m_mutex);
194   for (const auto &bp_sp : m_breakpoints)
195     bp_sp->ResetHitCount();
196 }
197 
198 void BreakpointList::GetListMutex(
199     std::unique_lock<std::recursive_mutex> &lock) {
200   lock = std::unique_lock<std::recursive_mutex>(m_mutex);
201 }
202