1//===-- BreakpointSiteList.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#include "lldb/Breakpoint/BreakpointSiteList.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Core/Stream.h"
17#include <algorithm>
18
19using namespace lldb;
20using namespace lldb_private;
21
22BreakpointSiteList::BreakpointSiteList() :
23    m_mutex (Mutex::eMutexTypeRecursive),
24    m_bp_site_list()
25{
26}
27
28BreakpointSiteList::~BreakpointSiteList()
29{
30}
31
32// Add breakpoint site to the list.  However, if the element already exists in the
33// list, then we don't add it, and return LLDB_INVALID_BREAK_ID.
34
35lldb::break_id_t
36BreakpointSiteList::Add(const BreakpointSiteSP &bp)
37{
38    lldb::addr_t bp_site_load_addr = bp->GetLoadAddress();
39    Mutex::Locker locker(m_mutex);
40    collection::iterator iter = m_bp_site_list.find (bp_site_load_addr);
41
42    if (iter == m_bp_site_list.end())
43    {
44        m_bp_site_list.insert (iter, collection::value_type (bp_site_load_addr, bp));
45        return bp->GetID();
46    }
47    else
48    {
49        return LLDB_INVALID_BREAK_ID;
50    }
51}
52
53bool
54BreakpointSiteList::ShouldStop (StoppointCallbackContext *context, lldb::break_id_t site_id)
55{
56    BreakpointSiteSP site_sp (FindByID (site_id));
57    if (site_sp)
58    {
59        // Let the BreakpointSite decide if it should stop here (could not have
60        // reached it's target hit count yet, or it could have a callback
61        // that decided it shouldn't stop (shared library loads/unloads).
62        return site_sp->ShouldStop (context);
63    }
64    // We should stop here since this BreakpointSite isn't valid anymore or it
65    // doesn't exist.
66    return true;
67}
68lldb::break_id_t
69BreakpointSiteList::FindIDByAddress (lldb::addr_t addr)
70{
71    BreakpointSiteSP bp = FindByAddress (addr);
72    if (bp)
73    {
74        //DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8" PRIx64 " ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID());
75        return bp.get()->GetID();
76    }
77    //DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8" PRIx64 " ) => NONE", __FUNCTION__, (uint64_t)addr);
78    return LLDB_INVALID_BREAK_ID;
79}
80
81bool
82BreakpointSiteList::Remove (lldb::break_id_t break_id)
83{
84    Mutex::Locker locker(m_mutex);
85    collection::iterator pos = GetIDIterator(break_id);    // Predicate
86    if (pos != m_bp_site_list.end())
87    {
88        m_bp_site_list.erase(pos);
89        return true;
90    }
91    return false;
92}
93
94bool
95BreakpointSiteList::RemoveByAddress (lldb::addr_t address)
96{
97    Mutex::Locker locker(m_mutex);
98    collection::iterator pos =  m_bp_site_list.find(address);
99    if (pos != m_bp_site_list.end())
100    {
101        m_bp_site_list.erase(pos);
102        return true;
103    }
104    return false;
105}
106
107class BreakpointSiteIDMatches
108{
109public:
110    BreakpointSiteIDMatches (lldb::break_id_t break_id) :
111        m_break_id(break_id)
112    {
113    }
114
115    bool operator() (std::pair <lldb::addr_t, BreakpointSiteSP> val_pair) const
116    {
117        return m_break_id == val_pair.second.get()->GetID();
118    }
119
120private:
121   const lldb::break_id_t m_break_id;
122};
123
124BreakpointSiteList::collection::iterator
125BreakpointSiteList::GetIDIterator (lldb::break_id_t break_id)
126{
127    Mutex::Locker locker(m_mutex);
128    return std::find_if(m_bp_site_list.begin(), m_bp_site_list.end(),   // Search full range
129                        BreakpointSiteIDMatches(break_id));             // Predicate
130}
131
132BreakpointSiteList::collection::const_iterator
133BreakpointSiteList::GetIDConstIterator (lldb::break_id_t break_id) const
134{
135    Mutex::Locker locker(m_mutex);
136    return std::find_if(m_bp_site_list.begin(), m_bp_site_list.end(),   // Search full range
137                        BreakpointSiteIDMatches(break_id));             // Predicate
138}
139
140BreakpointSiteSP
141BreakpointSiteList::FindByID (lldb::break_id_t break_id)
142{
143    Mutex::Locker locker(m_mutex);
144    BreakpointSiteSP stop_sp;
145    collection::iterator pos = GetIDIterator(break_id);
146    if (pos != m_bp_site_list.end())
147        stop_sp = pos->second;
148
149    return stop_sp;
150}
151
152const BreakpointSiteSP
153BreakpointSiteList::FindByID (lldb::break_id_t break_id) const
154{
155    Mutex::Locker locker(m_mutex);
156    BreakpointSiteSP stop_sp;
157    collection::const_iterator pos = GetIDConstIterator(break_id);
158    if (pos != m_bp_site_list.end())
159        stop_sp = pos->second;
160
161    return stop_sp;
162}
163
164BreakpointSiteSP
165BreakpointSiteList::FindByAddress (lldb::addr_t addr)
166{
167    BreakpointSiteSP found_sp;
168    Mutex::Locker locker(m_mutex);
169    collection::iterator iter =  m_bp_site_list.find(addr);
170    if (iter != m_bp_site_list.end())
171        found_sp = iter->second;
172    return found_sp;
173}
174
175bool
176BreakpointSiteList::BreakpointSiteContainsBreakpoint (lldb::break_id_t bp_site_id, lldb::break_id_t bp_id)
177{
178    Mutex::Locker locker(m_mutex);
179    collection::const_iterator pos = GetIDConstIterator(bp_site_id);
180    if (pos != m_bp_site_list.end())
181        return pos->second->IsBreakpointAtThisSite (bp_id);
182
183    return false;
184}
185
186void
187BreakpointSiteList::Dump (Stream *s) const
188{
189    s->Printf("%p: ", this);
190    //s->Indent();
191    s->Printf("BreakpointSiteList with %u BreakpointSites:\n", (uint32_t)m_bp_site_list.size());
192    s->IndentMore();
193    collection::const_iterator pos;
194    collection::const_iterator end = m_bp_site_list.end();
195    for (pos = m_bp_site_list.begin(); pos != end; ++pos)
196        pos->second.get()->Dump(s);
197    s->IndentLess();
198}
199
200void
201BreakpointSiteList::ForEach (std::function <void(BreakpointSite *)> const &callback)
202{
203    Mutex::Locker locker(m_mutex);
204    for (auto pair : m_bp_site_list)
205        callback (pair.second.get());
206}
207
208bool
209BreakpointSiteList::FindInRange (lldb::addr_t lower_bound, lldb::addr_t upper_bound, BreakpointSiteList &bp_site_list) const
210{
211    if (lower_bound > upper_bound)
212        return false;
213
214    Mutex::Locker locker(m_mutex);
215    collection::const_iterator lower, upper, pos;
216    lower = m_bp_site_list.lower_bound(lower_bound);
217    if (lower == m_bp_site_list.end()
218            || (*lower).first >= upper_bound)
219        return false;
220
221    // This is one tricky bit.  The breakpoint might overlap the bottom end of the range.  So we grab the
222    // breakpoint prior to the lower bound, and check that that + its byte size isn't in our range.
223    if (lower != m_bp_site_list.begin())
224    {
225        collection::const_iterator prev_pos = lower;
226        prev_pos--;
227        const BreakpointSiteSP &prev_bp = (*prev_pos).second;
228        if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound)
229            bp_site_list.Add (prev_bp);
230
231    }
232
233    upper = m_bp_site_list.upper_bound(upper_bound);
234
235    for (pos = lower; pos != upper; pos++)
236    {
237        bp_site_list.Add ((*pos).second);
238    }
239    return true;
240}
241