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_address_to_watchpoint (),
23     m_mutex (Mutex::eMutexTypeRecursive)
24 {
25 }
26 
27 WatchpointList::~WatchpointList()
28 {
29 }
30 
31 // Add watchpoint loc to the list.  However, if the element already exists in the
32 // list, then replace it with the input one.
33 
34 lldb::watch_id_t
35 WatchpointList::Add (const WatchpointSP &wp_sp)
36 {
37     Mutex::Locker locker (m_mutex);
38     lldb::addr_t wp_addr = wp_sp->GetLoadAddress();
39     addr_map::iterator iter = m_address_to_watchpoint.find(wp_addr);
40 
41     if (iter == m_address_to_watchpoint.end())
42         m_address_to_watchpoint.insert(iter, addr_map::value_type(wp_addr, wp_sp));
43     else
44         m_address_to_watchpoint[wp_addr] = wp_sp;
45 
46     return wp_sp->GetID();
47 }
48 
49 void
50 WatchpointList::Dump (Stream *s) const
51 {
52     DumpWithLevel(s, lldb::eDescriptionLevelBrief);
53 }
54 
55 void
56 WatchpointList::DumpWithLevel (Stream *s, lldb::DescriptionLevel description_level) const
57 {
58     Mutex::Locker locker (m_mutex);
59     s->Printf("%p: ", this);
60     //s->Indent();
61     s->Printf("WatchpointList with %zu Watchpoints:\n",
62               m_address_to_watchpoint.size());
63     s->IndentMore();
64     addr_map::const_iterator pos, end = m_address_to_watchpoint.end();
65     for (pos = m_address_to_watchpoint.begin(); pos != end; ++pos)
66         pos->second->DumpWithLevel(s, description_level);
67     s->IndentLess();
68 }
69 
70 const WatchpointSP
71 WatchpointList::FindByAddress (lldb::addr_t addr) const
72 {
73     WatchpointSP wp_sp;
74     Mutex::Locker locker (m_mutex);
75     if (!m_address_to_watchpoint.empty())
76     {
77         addr_map::const_iterator pos = m_address_to_watchpoint.find (addr);
78         if (pos != m_address_to_watchpoint.end())
79             wp_sp = pos->second;
80     }
81 
82     return wp_sp;
83 }
84 
85 class WatchpointIDMatches
86 {
87 public:
88     WatchpointIDMatches (lldb::watch_id_t watch_id) :
89         m_watch_id(watch_id)
90     {
91     }
92 
93     bool operator() (std::pair <lldb::addr_t, WatchpointSP> val_pair) const
94     {
95         return m_watch_id == val_pair.second.get()->GetID();
96     }
97 
98 private:
99    const lldb::watch_id_t m_watch_id;
100 };
101 
102 WatchpointList::addr_map::iterator
103 WatchpointList::GetIDIterator (lldb::watch_id_t watch_id)
104 {
105     return std::find_if(m_address_to_watchpoint.begin(), m_address_to_watchpoint.end(), // Search full range
106                         WatchpointIDMatches(watch_id));                                 // Predicate
107 }
108 
109 WatchpointList::addr_map::const_iterator
110 WatchpointList::GetIDConstIterator (lldb::watch_id_t watch_id) const
111 {
112     return std::find_if(m_address_to_watchpoint.begin(), m_address_to_watchpoint.end(), // Search full range
113                         WatchpointIDMatches(watch_id));                                 // Predicate
114 }
115 
116 WatchpointSP
117 WatchpointList::FindByID (lldb::watch_id_t watch_id) const
118 {
119     WatchpointSP wp_sp;
120     Mutex::Locker locker (m_mutex);
121     addr_map::const_iterator pos = GetIDConstIterator(watch_id);
122     if (pos != m_address_to_watchpoint.end())
123         wp_sp = pos->second;
124 
125     return wp_sp;
126 }
127 
128 lldb::watch_id_t
129 WatchpointList::FindIDByAddress (lldb::addr_t addr)
130 {
131     WatchpointSP wp_sp = FindByAddress (addr);
132     if (wp_sp)
133     {
134         return wp_sp->GetID();
135     }
136     return LLDB_INVALID_WATCH_ID;
137 }
138 
139 WatchpointSP
140 WatchpointList::GetByIndex (uint32_t i)
141 {
142     Mutex::Locker locker (m_mutex);
143     WatchpointSP wp_sp;
144     if (i < m_address_to_watchpoint.size())
145     {
146         addr_map::const_iterator pos = m_address_to_watchpoint.begin();
147         std::advance(pos, i);
148         wp_sp = pos->second;
149     }
150     return wp_sp;
151 }
152 
153 const WatchpointSP
154 WatchpointList::GetByIndex (uint32_t i) const
155 {
156     Mutex::Locker locker (m_mutex);
157     WatchpointSP wp_sp;
158     if (i < m_address_to_watchpoint.size())
159     {
160         addr_map::const_iterator pos = m_address_to_watchpoint.begin();
161         std::advance(pos, i);
162         wp_sp = pos->second;
163     }
164     return wp_sp;
165 }
166 
167 bool
168 WatchpointList::Remove (lldb::watch_id_t watch_id)
169 {
170     Mutex::Locker locker (m_mutex);
171     addr_map::iterator pos = GetIDIterator(watch_id);
172     if (pos != m_address_to_watchpoint.end())
173     {
174         m_address_to_watchpoint.erase(pos);
175         return true;
176     }
177     return false;
178 }
179 
180 uint32_t
181 WatchpointList::GetHitCount () const
182 {
183     uint32_t hit_count = 0;
184     Mutex::Locker locker (m_mutex);
185     addr_map::const_iterator pos, end = m_address_to_watchpoint.end();
186     for (pos = m_address_to_watchpoint.begin(); pos != end; ++pos)
187         hit_count += pos->second->GetHitCount();
188     return hit_count;
189 }
190 
191 bool
192 WatchpointList::ShouldStop (StoppointCallbackContext *context, lldb::watch_id_t watch_id)
193 {
194 
195     WatchpointSP wp_sp = FindByID (watch_id);
196     if (wp_sp)
197     {
198         // Let the Watchpoint decide if it should stop here (could not have
199         // reached it's target hit count yet, or it could have a callback
200         // that decided it shouldn't stop.
201         return wp_sp->ShouldStop (context);
202     }
203     // We should stop here since this Watchpoint isn't valid anymore or it
204     // doesn't exist.
205     return true;
206 }
207 
208 void
209 WatchpointList::GetDescription (Stream *s, lldb::DescriptionLevel level)
210 {
211     Mutex::Locker locker (m_mutex);
212     addr_map::iterator pos, end = m_address_to_watchpoint.end();
213 
214     for (pos = m_address_to_watchpoint.begin(); pos != end; ++pos)
215     {
216         s->Printf(" ");
217         pos->second->Dump(s);
218     }
219 }
220 
221 void
222 WatchpointList::SetEnabledAll (bool enabled)
223 {
224     Mutex::Locker locker(m_mutex);
225 
226     addr_map::iterator pos, end = m_address_to_watchpoint.end();
227     for (pos = m_address_to_watchpoint.begin(); pos != end; ++pos)
228         pos->second->SetEnabled (enabled);
229 }
230 
231 void
232 WatchpointList::RemoveAll ()
233 {
234     Mutex::Locker locker(m_mutex);
235     m_address_to_watchpoint.clear();
236 }
237 
238 void
239 WatchpointList::GetListMutex (Mutex::Locker &locker)
240 {
241     return locker.Reset (m_mutex.GetMutex());
242 }
243