1 //===-- BreakpointList.cpp --------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Breakpoint/BreakpointList.h"
11 
12 #include "lldb/Target/Target.h"
13 
14 using namespace lldb;
15 using namespace lldb_private;
16 
17 BreakpointList::BreakpointList(bool is_internal)
18     : m_mutex(), m_breakpoints(), m_next_break_id(0),
19       m_is_internal(is_internal) {}
20 
21 BreakpointList::~BreakpointList() {}
22 
23 break_id_t BreakpointList::Add(BreakpointSP &bp_sp, bool notify) {
24   std::lock_guard<std::recursive_mutex> guard(m_mutex);
25   // Internal breakpoint IDs are negative, normal ones are positive
26   bp_sp->SetID(m_is_internal ? --m_next_break_id : ++m_next_break_id);
27 
28   m_breakpoints.push_back(bp_sp);
29   if (notify) {
30     if (bp_sp->GetTarget().EventTypeHasListeners(
31             Target::eBroadcastBitBreakpointChanged))
32       bp_sp->GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged,
33                                         new Breakpoint::BreakpointEventData(
34                                             eBreakpointEventTypeAdded, bp_sp));
35   }
36   return bp_sp->GetID();
37 }
38 
39 bool BreakpointList::Remove(break_id_t break_id, bool notify) {
40   std::lock_guard<std::recursive_mutex> guard(m_mutex);
41   bp_collection::iterator pos = GetBreakpointIDIterator(break_id); // Predicate
42   if (pos != m_breakpoints.end()) {
43     BreakpointSP bp_sp(*pos);
44     m_breakpoints.erase(pos);
45     if (notify) {
46       if (bp_sp->GetTarget().EventTypeHasListeners(
47               Target::eBroadcastBitBreakpointChanged))
48         bp_sp->GetTarget().BroadcastEvent(
49             Target::eBroadcastBitBreakpointChanged,
50             new Breakpoint::BreakpointEventData(eBreakpointEventTypeRemoved,
51                                                 bp_sp));
52     }
53     return true;
54   }
55   return false;
56 }
57 
58 void BreakpointList::RemoveInvalidLocations(const ArchSpec &arch) {
59   std::lock_guard<std::recursive_mutex> guard(m_mutex);
60   for (const auto &bp_sp : m_breakpoints)
61     bp_sp->RemoveInvalidLocations(arch);
62 }
63 
64 void BreakpointList::SetEnabledAll(bool enabled) {
65   std::lock_guard<std::recursive_mutex> guard(m_mutex);
66   for (const auto &bp_sp : m_breakpoints)
67     bp_sp->SetEnabled(enabled);
68 }
69 
70 void BreakpointList::SetEnabledAllowed(bool enabled) {
71   std::lock_guard<std::recursive_mutex> guard(m_mutex);
72   for (const auto &bp_sp : m_breakpoints)
73     if (bp_sp->AllowDisable())
74       bp_sp->SetEnabled(enabled);
75 }
76 
77 void BreakpointList::RemoveAll(bool notify) {
78   std::lock_guard<std::recursive_mutex> guard(m_mutex);
79   ClearAllBreakpointSites();
80 
81   if (notify) {
82     bp_collection::iterator pos, end = m_breakpoints.end();
83     for (pos = m_breakpoints.begin(); pos != end; ++pos) {
84       if ((*pos)->GetTarget().EventTypeHasListeners(
85               Target::eBroadcastBitBreakpointChanged)) {
86         (*pos)->GetTarget().BroadcastEvent(
87             Target::eBroadcastBitBreakpointChanged,
88             new Breakpoint::BreakpointEventData(eBreakpointEventTypeRemoved,
89                                                 *pos));
90       }
91     }
92   }
93   m_breakpoints.erase(m_breakpoints.begin(), m_breakpoints.end());
94 }
95 
96 void BreakpointList::RemoveAllowed(bool notify) {
97   std::lock_guard<std::recursive_mutex> guard(m_mutex);
98 
99   bp_collection::iterator pos, end = m_breakpoints.end();
100   if (notify) {
101     for (pos = m_breakpoints.begin(); pos != end; ++pos) {
102       if(!(*pos)->AllowDelete())
103         continue;
104       if ((*pos)->GetTarget().EventTypeHasListeners(
105               Target::eBroadcastBitBreakpointChanged)) {
106         (*pos)->GetTarget().BroadcastEvent(
107             Target::eBroadcastBitBreakpointChanged,
108             new Breakpoint::BreakpointEventData(eBreakpointEventTypeRemoved,
109                                                 *pos));
110       }
111     }
112   }
113   pos = m_breakpoints.begin();
114   while ( pos != end) {
115     auto bp = *pos;
116     if (bp->AllowDelete()) {
117       bp->ClearAllBreakpointSites();
118       pos = m_breakpoints.erase(pos);
119     } else
120       pos++;
121   }
122 }
123 
124 class BreakpointIDMatches {
125 public:
126   BreakpointIDMatches(break_id_t break_id) : m_break_id(break_id) {}
127 
128   bool operator()(const BreakpointSP &bp) const {
129     return m_break_id == bp->GetID();
130   }
131 
132 private:
133   const break_id_t m_break_id;
134 };
135 
136 BreakpointList::bp_collection::iterator
137 BreakpointList::GetBreakpointIDIterator(break_id_t break_id) {
138   return std::find_if(m_breakpoints.begin(),
139                       m_breakpoints.end(),            // Search full range
140                       BreakpointIDMatches(break_id)); // Predicate
141 }
142 
143 BreakpointList::bp_collection::const_iterator
144 BreakpointList::GetBreakpointIDConstIterator(break_id_t break_id) const {
145   return std::find_if(m_breakpoints.begin(),
146                       m_breakpoints.end(),            // Search full range
147                       BreakpointIDMatches(break_id)); // Predicate
148 }
149 
150 BreakpointSP BreakpointList::FindBreakpointByID(break_id_t break_id) {
151   std::lock_guard<std::recursive_mutex> guard(m_mutex);
152   BreakpointSP stop_sp;
153   bp_collection::iterator pos = GetBreakpointIDIterator(break_id);
154   if (pos != m_breakpoints.end())
155     stop_sp = *pos;
156 
157   return stop_sp;
158 }
159 
160 const BreakpointSP
161 BreakpointList::FindBreakpointByID(break_id_t break_id) const {
162   std::lock_guard<std::recursive_mutex> guard(m_mutex);
163   BreakpointSP stop_sp;
164   bp_collection::const_iterator pos = GetBreakpointIDConstIterator(break_id);
165   if (pos != m_breakpoints.end())
166     stop_sp = *pos;
167 
168   return stop_sp;
169 }
170 
171 bool BreakpointList::FindBreakpointsByName(const char *name,
172                                            BreakpointList &matching_bps) {
173   Status error;
174   if (!name)
175     return false;
176 
177   if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(name), error))
178     return false;
179 
180   for (BreakpointSP bkpt_sp : Breakpoints()) {
181     if (bkpt_sp->MatchesName(name)) {
182       matching_bps.Add(bkpt_sp, false);
183     }
184   }
185   return true;
186 }
187 
188 void BreakpointList::Dump(Stream *s) const {
189   std::lock_guard<std::recursive_mutex> guard(m_mutex);
190   s->Printf("%p: ", static_cast<const void *>(this));
191   s->Indent();
192   s->Printf("BreakpointList with %u Breakpoints:\n",
193             (uint32_t)m_breakpoints.size());
194   s->IndentMore();
195   for (const auto &bp_sp : m_breakpoints)
196     bp_sp->Dump(s);
197   s->IndentLess();
198 }
199 
200 BreakpointSP BreakpointList::GetBreakpointAtIndex(size_t i) {
201   std::lock_guard<std::recursive_mutex> guard(m_mutex);
202   BreakpointSP stop_sp;
203   bp_collection::iterator end = m_breakpoints.end();
204   bp_collection::iterator pos;
205   size_t curr_i = 0;
206   for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i) {
207     if (curr_i == i)
208       stop_sp = *pos;
209   }
210   return stop_sp;
211 }
212 
213 const BreakpointSP BreakpointList::GetBreakpointAtIndex(size_t i) const {
214   std::lock_guard<std::recursive_mutex> guard(m_mutex);
215   BreakpointSP stop_sp;
216   bp_collection::const_iterator end = m_breakpoints.end();
217   bp_collection::const_iterator pos;
218   size_t curr_i = 0;
219   for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i) {
220     if (curr_i == i)
221       stop_sp = *pos;
222   }
223   return stop_sp;
224 }
225 
226 void BreakpointList::UpdateBreakpoints(ModuleList &module_list, bool added,
227                                        bool delete_locations) {
228   std::lock_guard<std::recursive_mutex> guard(m_mutex);
229   for (const auto &bp_sp : m_breakpoints)
230     bp_sp->ModulesChanged(module_list, added, delete_locations);
231 }
232 
233 void BreakpointList::UpdateBreakpointsWhenModuleIsReplaced(
234     ModuleSP old_module_sp, ModuleSP new_module_sp) {
235   std::lock_guard<std::recursive_mutex> guard(m_mutex);
236   for (const auto &bp_sp : m_breakpoints)
237     bp_sp->ModuleReplaced(old_module_sp, new_module_sp);
238 }
239 
240 void BreakpointList::ClearAllBreakpointSites() {
241   std::lock_guard<std::recursive_mutex> guard(m_mutex);
242   for (const auto &bp_sp : m_breakpoints)
243     bp_sp->ClearAllBreakpointSites();
244 }
245 
246 void BreakpointList::GetListMutex(
247     std::unique_lock<std::recursive_mutex> &lock) {
248   lock = std::unique_lock<std::recursive_mutex>(m_mutex);
249 }
250