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