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