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