1 //===-- WatchpointList.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 
11 // C Includes
12 // C++ Includes
13 // Other libraries and framework includes
14 // Project includes
15 #include "lldb/Breakpoint/WatchpointList.h"
16 #include "lldb/Breakpoint/Watchpoint.h"
17 
18 using namespace lldb;
19 using namespace lldb_private;
20 
WatchpointList()21 WatchpointList::WatchpointList() :
22     m_watchpoints (),
23     m_mutex (Mutex::eMutexTypeRecursive),
24     m_next_wp_id (0)
25 {
26 }
27 
~WatchpointList()28 WatchpointList::~WatchpointList()
29 {
30 }
31 
32 // Add a watchpoint to the list.
33 lldb::watch_id_t
Add(const WatchpointSP & wp_sp,bool notify)34 WatchpointList::Add (const WatchpointSP &wp_sp, bool notify)
35 {
36     Mutex::Locker locker (m_mutex);
37     wp_sp->SetID(++m_next_wp_id);
38     m_watchpoints.push_back(wp_sp);
39     if (notify)
40     {
41         if (wp_sp->GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
42             wp_sp->GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged,
43                                                new Watchpoint::WatchpointEventData (eWatchpointEventTypeAdded, wp_sp));
44     }
45     return wp_sp->GetID();
46 }
47 
48 void
Dump(Stream * s) const49 WatchpointList::Dump (Stream *s) const
50 {
51     DumpWithLevel(s, lldb::eDescriptionLevelBrief);
52 }
53 
54 void
DumpWithLevel(Stream * s,lldb::DescriptionLevel description_level) const55 WatchpointList::DumpWithLevel (Stream *s, lldb::DescriptionLevel description_level) const
56 {
57     Mutex::Locker locker (m_mutex);
58     s->Printf("%p: ", this);
59     //s->Indent();
60     s->Printf("WatchpointList with %" PRIu64 " Watchpoints:\n",
61               (uint64_t)m_watchpoints.size());
62     s->IndentMore();
63     wp_collection::const_iterator pos, end = m_watchpoints.end();
64     for (pos = m_watchpoints.begin(); pos != end; ++pos)
65         (*pos)->DumpWithLevel(s, description_level);
66     s->IndentLess();
67 }
68 
69 const WatchpointSP
FindByAddress(lldb::addr_t addr) const70 WatchpointList::FindByAddress (lldb::addr_t addr) const
71 {
72     WatchpointSP wp_sp;
73     Mutex::Locker locker (m_mutex);
74     if (!m_watchpoints.empty())
75     {
76         wp_collection::const_iterator pos, end = m_watchpoints.end();
77         for (pos = m_watchpoints.begin(); pos != end; ++pos)
78             if ((*pos)->GetLoadAddress() == addr) {
79                 wp_sp = *pos;
80                 break;
81             }
82     }
83 
84     return wp_sp;
85 }
86 
87 const WatchpointSP
FindBySpec(std::string spec) const88 WatchpointList::FindBySpec (std::string spec) const
89 {
90     WatchpointSP wp_sp;
91     Mutex::Locker locker (m_mutex);
92     if (!m_watchpoints.empty())
93     {
94         wp_collection::const_iterator pos, end = m_watchpoints.end();
95         for (pos = m_watchpoints.begin(); pos != end; ++pos)
96             if ((*pos)->GetWatchSpec() == spec) {
97                 wp_sp = *pos;
98                 break;
99             }
100     }
101 
102     return wp_sp;
103 }
104 
105 class WatchpointIDMatches
106 {
107 public:
WatchpointIDMatches(lldb::watch_id_t watch_id)108     WatchpointIDMatches (lldb::watch_id_t watch_id) :
109         m_watch_id(watch_id)
110     {
111     }
112 
operator ()(const WatchpointSP & wp) const113     bool operator() (const WatchpointSP &wp) const
114     {
115         return m_watch_id == wp->GetID();
116     }
117 
118 private:
119    const lldb::watch_id_t m_watch_id;
120 };
121 
122 WatchpointList::wp_collection::iterator
GetIDIterator(lldb::watch_id_t watch_id)123 WatchpointList::GetIDIterator (lldb::watch_id_t watch_id)
124 {
125     return std::find_if(m_watchpoints.begin(), m_watchpoints.end(), // Search full range
126                         WatchpointIDMatches(watch_id));             // Predicate
127 }
128 
129 WatchpointList::wp_collection::const_iterator
GetIDConstIterator(lldb::watch_id_t watch_id) const130 WatchpointList::GetIDConstIterator (lldb::watch_id_t watch_id) const
131 {
132     return std::find_if(m_watchpoints.begin(), m_watchpoints.end(), // Search full range
133                         WatchpointIDMatches(watch_id));             // Predicate
134 }
135 
136 WatchpointSP
FindByID(lldb::watch_id_t watch_id) const137 WatchpointList::FindByID (lldb::watch_id_t watch_id) const
138 {
139     WatchpointSP wp_sp;
140     Mutex::Locker locker (m_mutex);
141     wp_collection::const_iterator pos = GetIDConstIterator(watch_id);
142     if (pos != m_watchpoints.end())
143         wp_sp = *pos;
144 
145     return wp_sp;
146 }
147 
148 lldb::watch_id_t
FindIDByAddress(lldb::addr_t addr)149 WatchpointList::FindIDByAddress (lldb::addr_t addr)
150 {
151     WatchpointSP wp_sp = FindByAddress (addr);
152     if (wp_sp)
153     {
154         return wp_sp->GetID();
155     }
156     return LLDB_INVALID_WATCH_ID;
157 }
158 
159 lldb::watch_id_t
FindIDBySpec(std::string spec)160 WatchpointList::FindIDBySpec (std::string spec)
161 {
162     WatchpointSP wp_sp = FindBySpec (spec);
163     if (wp_sp)
164     {
165         return wp_sp->GetID();
166     }
167     return LLDB_INVALID_WATCH_ID;
168 }
169 
170 WatchpointSP
GetByIndex(uint32_t i)171 WatchpointList::GetByIndex (uint32_t i)
172 {
173     Mutex::Locker locker (m_mutex);
174     WatchpointSP wp_sp;
175     if (i < m_watchpoints.size())
176     {
177         wp_collection::const_iterator pos = m_watchpoints.begin();
178         std::advance(pos, i);
179         wp_sp = *pos;
180     }
181     return wp_sp;
182 }
183 
184 const WatchpointSP
GetByIndex(uint32_t i) const185 WatchpointList::GetByIndex (uint32_t i) const
186 {
187     Mutex::Locker locker (m_mutex);
188     WatchpointSP wp_sp;
189     if (i < m_watchpoints.size())
190     {
191         wp_collection::const_iterator pos = m_watchpoints.begin();
192         std::advance(pos, i);
193         wp_sp = *pos;
194     }
195     return wp_sp;
196 }
197 
198 std::vector<lldb::watch_id_t>
GetWatchpointIDs() const199 WatchpointList::GetWatchpointIDs() const
200 {
201     std::vector<lldb::watch_id_t> IDs;
202     wp_collection::const_iterator pos, end = m_watchpoints.end();
203     for (pos = m_watchpoints.begin(); pos != end; ++pos)
204         IDs.push_back((*pos)->GetID());
205     return IDs;
206 }
207 
208 bool
Remove(lldb::watch_id_t watch_id,bool notify)209 WatchpointList::Remove (lldb::watch_id_t watch_id, bool notify)
210 {
211     Mutex::Locker locker (m_mutex);
212     wp_collection::iterator pos = GetIDIterator(watch_id);
213     if (pos != m_watchpoints.end())
214     {
215         WatchpointSP wp_sp = *pos;
216         if (notify)
217         {
218             if (wp_sp->GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
219                 wp_sp->GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged,
220                                                    new Watchpoint::WatchpointEventData (eWatchpointEventTypeRemoved, wp_sp));
221         }
222         m_watchpoints.erase(pos);
223         return true;
224     }
225     return false;
226 }
227 
228 uint32_t
GetHitCount() const229 WatchpointList::GetHitCount () const
230 {
231     uint32_t hit_count = 0;
232     Mutex::Locker locker (m_mutex);
233     wp_collection::const_iterator pos, end = m_watchpoints.end();
234     for (pos = m_watchpoints.begin(); pos != end; ++pos)
235         hit_count += (*pos)->GetHitCount();
236     return hit_count;
237 }
238 
239 bool
ShouldStop(StoppointCallbackContext * context,lldb::watch_id_t watch_id)240 WatchpointList::ShouldStop (StoppointCallbackContext *context, lldb::watch_id_t watch_id)
241 {
242 
243     WatchpointSP wp_sp = FindByID (watch_id);
244     if (wp_sp)
245     {
246         // Let the Watchpoint decide if it should stop here (could not have
247         // reached it's target hit count yet, or it could have a callback
248         // that decided it shouldn't stop.
249         return wp_sp->ShouldStop (context);
250     }
251     // We should stop here since this Watchpoint isn't valid anymore or it
252     // doesn't exist.
253     return true;
254 }
255 
256 void
GetDescription(Stream * s,lldb::DescriptionLevel level)257 WatchpointList::GetDescription (Stream *s, lldb::DescriptionLevel level)
258 {
259     Mutex::Locker locker (m_mutex);
260     wp_collection::iterator pos, end = m_watchpoints.end();
261 
262     for (pos = m_watchpoints.begin(); pos != end; ++pos)
263     {
264         s->Printf(" ");
265         (*pos)->Dump(s);
266     }
267 }
268 
269 void
SetEnabledAll(bool enabled)270 WatchpointList::SetEnabledAll (bool enabled)
271 {
272     Mutex::Locker locker(m_mutex);
273 
274     wp_collection::iterator pos, end = m_watchpoints.end();
275     for (pos = m_watchpoints.begin(); pos != end; ++pos)
276         (*pos)->SetEnabled (enabled);
277 }
278 
279 void
RemoveAll(bool notify)280 WatchpointList::RemoveAll (bool notify)
281 {
282     Mutex::Locker locker(m_mutex);
283     if (notify)
284     {
285 
286         {
287             wp_collection::iterator pos, end = m_watchpoints.end();
288             for (pos = m_watchpoints.begin(); pos != end; ++pos)
289             {
290                 if ((*pos)->GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
291                 {
292                     (*pos)->GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged,
293                                                         new Watchpoint::WatchpointEventData (eWatchpointEventTypeRemoved,
294                                                                                              *pos));
295                 }
296             }
297         }
298     }
299     m_watchpoints.clear();
300 }
301 
302 void
GetListMutex(Mutex::Locker & locker)303 WatchpointList::GetListMutex (Mutex::Locker &locker)
304 {
305     return locker.Lock (m_mutex);
306 }
307