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