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 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Target/Target.h"
17 
18 using namespace lldb;
19 using namespace lldb_private;
20 
21 BreakpointList::BreakpointList(bool is_internal)
22     : m_mutex(), m_breakpoints(), m_next_break_id(0),
23       m_is_internal(is_internal) {}
24 
25 BreakpointList::~BreakpointList() {}
26 
27 break_id_t BreakpointList::Add(BreakpointSP &bp_sp, bool notify) {
28   std::lock_guard<std::recursive_mutex> guard(m_mutex);
29   // Internal breakpoint IDs are negative, normal ones are positive
30   bp_sp->SetID(m_is_internal ? --m_next_break_id : ++m_next_break_id);
31 
32   m_breakpoints.push_back(bp_sp);
33   if (notify) {
34     if (bp_sp->GetTarget().EventTypeHasListeners(
35             Target::eBroadcastBitBreakpointChanged))
36       bp_sp->GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged,
37                                         new Breakpoint::BreakpointEventData(
38                                             eBreakpointEventTypeAdded, bp_sp));
39   }
40   return bp_sp->GetID();
41 }
42 
43 bool BreakpointList::Remove(break_id_t break_id, bool notify) {
44   std::lock_guard<std::recursive_mutex> guard(m_mutex);
45   bp_collection::iterator pos = GetBreakpointIDIterator(break_id); // Predicate
46   if (pos != m_breakpoints.end()) {
47     BreakpointSP bp_sp(*pos);
48     m_breakpoints.erase(pos);
49     if (notify) {
50       if (bp_sp->GetTarget().EventTypeHasListeners(
51               Target::eBroadcastBitBreakpointChanged))
52         bp_sp->GetTarget().BroadcastEvent(
53             Target::eBroadcastBitBreakpointChanged,
54             new Breakpoint::BreakpointEventData(eBreakpointEventTypeRemoved,
55                                                 bp_sp));
56     }
57     return true;
58   }
59   return false;
60 }
61 
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 
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 
74 void BreakpointList::RemoveAll(bool notify) {
75   std::lock_guard<std::recursive_mutex> guard(m_mutex);
76   ClearAllBreakpointSites();
77 
78   if (notify) {
79     bp_collection::iterator pos, end = m_breakpoints.end();
80     for (pos = m_breakpoints.begin(); pos != end; ++pos) {
81       if ((*pos)->GetTarget().EventTypeHasListeners(
82               Target::eBroadcastBitBreakpointChanged)) {
83         (*pos)->GetTarget().BroadcastEvent(
84             Target::eBroadcastBitBreakpointChanged,
85             new Breakpoint::BreakpointEventData(eBreakpointEventTypeRemoved,
86                                                 *pos));
87       }
88     }
89   }
90   m_breakpoints.erase(m_breakpoints.begin(), m_breakpoints.end());
91 }
92 
93 class BreakpointIDMatches {
94 public:
95   BreakpointIDMatches(break_id_t break_id) : m_break_id(break_id) {}
96 
97   bool operator()(const BreakpointSP &bp) const {
98     return m_break_id == bp->GetID();
99   }
100 
101 private:
102   const break_id_t m_break_id;
103 };
104 
105 BreakpointList::bp_collection::iterator
106 BreakpointList::GetBreakpointIDIterator(break_id_t break_id) {
107   return std::find_if(m_breakpoints.begin(),
108                       m_breakpoints.end(),            // Search full range
109                       BreakpointIDMatches(break_id)); // Predicate
110 }
111 
112 BreakpointList::bp_collection::const_iterator
113 BreakpointList::GetBreakpointIDConstIterator(break_id_t break_id) const {
114   return std::find_if(m_breakpoints.begin(),
115                       m_breakpoints.end(),            // Search full range
116                       BreakpointIDMatches(break_id)); // Predicate
117 }
118 
119 BreakpointSP BreakpointList::FindBreakpointByID(break_id_t break_id) {
120   std::lock_guard<std::recursive_mutex> guard(m_mutex);
121   BreakpointSP stop_sp;
122   bp_collection::iterator pos = GetBreakpointIDIterator(break_id);
123   if (pos != m_breakpoints.end())
124     stop_sp = *pos;
125 
126   return stop_sp;
127 }
128 
129 const BreakpointSP
130 BreakpointList::FindBreakpointByID(break_id_t break_id) const {
131   std::lock_guard<std::recursive_mutex> guard(m_mutex);
132   BreakpointSP stop_sp;
133   bp_collection::const_iterator pos = GetBreakpointIDConstIterator(break_id);
134   if (pos != m_breakpoints.end())
135     stop_sp = *pos;
136 
137   return stop_sp;
138 }
139 
140 void BreakpointList::Dump(Stream *s) const {
141   std::lock_guard<std::recursive_mutex> guard(m_mutex);
142   s->Printf("%p: ", static_cast<const void *>(this));
143   s->Indent();
144   s->Printf("BreakpointList with %u Breakpoints:\n",
145             (uint32_t)m_breakpoints.size());
146   s->IndentMore();
147   for (const auto &bp_sp : m_breakpoints)
148     bp_sp->Dump(s);
149   s->IndentLess();
150 }
151 
152 BreakpointSP BreakpointList::GetBreakpointAtIndex(size_t i) {
153   std::lock_guard<std::recursive_mutex> guard(m_mutex);
154   BreakpointSP stop_sp;
155   bp_collection::iterator end = m_breakpoints.end();
156   bp_collection::iterator pos;
157   size_t curr_i = 0;
158   for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i) {
159     if (curr_i == i)
160       stop_sp = *pos;
161   }
162   return stop_sp;
163 }
164 
165 const BreakpointSP BreakpointList::GetBreakpointAtIndex(size_t i) const {
166   std::lock_guard<std::recursive_mutex> guard(m_mutex);
167   BreakpointSP stop_sp;
168   bp_collection::const_iterator end = m_breakpoints.end();
169   bp_collection::const_iterator pos;
170   size_t curr_i = 0;
171   for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i) {
172     if (curr_i == i)
173       stop_sp = *pos;
174   }
175   return stop_sp;
176 }
177 
178 void BreakpointList::UpdateBreakpoints(ModuleList &module_list, bool added,
179                                        bool delete_locations) {
180   std::lock_guard<std::recursive_mutex> guard(m_mutex);
181   for (const auto &bp_sp : m_breakpoints)
182     bp_sp->ModulesChanged(module_list, added, delete_locations);
183 }
184 
185 void BreakpointList::UpdateBreakpointsWhenModuleIsReplaced(
186     ModuleSP old_module_sp, ModuleSP new_module_sp) {
187   std::lock_guard<std::recursive_mutex> guard(m_mutex);
188   for (const auto &bp_sp : m_breakpoints)
189     bp_sp->ModuleReplaced(old_module_sp, new_module_sp);
190 }
191 
192 void BreakpointList::ClearAllBreakpointSites() {
193   std::lock_guard<std::recursive_mutex> guard(m_mutex);
194   for (const auto &bp_sp : m_breakpoints)
195     bp_sp->ClearAllBreakpointSites();
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