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
18using namespace lldb;
19using namespace lldb_private;
20
21WatchpointList::WatchpointList() :
22    m_watchpoints (),
23    m_mutex (Mutex::eMutexTypeRecursive),
24    m_next_wp_id (0)
25{
26}
27
28WatchpointList::~WatchpointList()
29{
30}
31
32// Add a watchpoint to the list.
33lldb::watch_id_t
34WatchpointList::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
48void
49WatchpointList::Dump (Stream *s) const
50{
51    DumpWithLevel(s, lldb::eDescriptionLevelBrief);
52}
53
54void
55WatchpointList::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
69const WatchpointSP
70WatchpointList::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
87const WatchpointSP
88WatchpointList::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
105class WatchpointIDMatches
106{
107public:
108    WatchpointIDMatches (lldb::watch_id_t watch_id) :
109        m_watch_id(watch_id)
110    {
111    }
112
113    bool operator() (const WatchpointSP &wp) const
114    {
115        return m_watch_id == wp->GetID();
116    }
117
118private:
119   const lldb::watch_id_t m_watch_id;
120};
121
122WatchpointList::wp_collection::iterator
123WatchpointList::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
129WatchpointList::wp_collection::const_iterator
130WatchpointList::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
136WatchpointSP
137WatchpointList::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
148lldb::watch_id_t
149WatchpointList::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
159lldb::watch_id_t
160WatchpointList::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
170WatchpointSP
171WatchpointList::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
184const WatchpointSP
185WatchpointList::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
198std::vector<lldb::watch_id_t>
199WatchpointList::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
208bool
209WatchpointList::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
228uint32_t
229WatchpointList::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
239bool
240WatchpointList::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
256void
257WatchpointList::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
269void
270WatchpointList::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
279void
280WatchpointList::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
302void
303WatchpointList::GetListMutex (Mutex::Locker &locker)
304{
305    return locker.Lock (m_mutex);
306}
307