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