• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
19 using namespace lldb;
20 using namespace lldb_private;
21 
BreakpointSiteList()22 BreakpointSiteList::BreakpointSiteList() :
23     m_mutex (Mutex::eMutexTypeRecursive),
24     m_bp_site_list()
25 {
26 }
27 
~BreakpointSiteList()28 BreakpointSiteList::~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 
35 lldb::break_id_t
Add(const BreakpointSiteSP & bp)36 BreakpointSiteList::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 
53 bool
ShouldStop(StoppointCallbackContext * context,lldb::break_id_t site_id)54 BreakpointSiteList::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 }
68 lldb::break_id_t
FindIDByAddress(lldb::addr_t addr)69 BreakpointSiteList::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 
81 bool
Remove(lldb::break_id_t break_id)82 BreakpointSiteList::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 
94 bool
RemoveByAddress(lldb::addr_t address)95 BreakpointSiteList::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 
107 class BreakpointSiteIDMatches
108 {
109 public:
BreakpointSiteIDMatches(lldb::break_id_t break_id)110     BreakpointSiteIDMatches (lldb::break_id_t break_id) :
111         m_break_id(break_id)
112     {
113     }
114 
operator ()(std::pair<lldb::addr_t,BreakpointSiteSP> val_pair) const115     bool operator() (std::pair <lldb::addr_t, BreakpointSiteSP> val_pair) const
116     {
117         return m_break_id == val_pair.second.get()->GetID();
118     }
119 
120 private:
121    const lldb::break_id_t m_break_id;
122 };
123 
124 BreakpointSiteList::collection::iterator
GetIDIterator(lldb::break_id_t break_id)125 BreakpointSiteList::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 
132 BreakpointSiteList::collection::const_iterator
GetIDConstIterator(lldb::break_id_t break_id) const133 BreakpointSiteList::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 
140 BreakpointSiteSP
FindByID(lldb::break_id_t break_id)141 BreakpointSiteList::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 
152 const BreakpointSiteSP
FindByID(lldb::break_id_t break_id) const153 BreakpointSiteList::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 
164 BreakpointSiteSP
FindByAddress(lldb::addr_t addr)165 BreakpointSiteList::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 
175 bool
BreakpointSiteContainsBreakpoint(lldb::break_id_t bp_site_id,lldb::break_id_t bp_id)176 BreakpointSiteList::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 
186 void
Dump(Stream * s) const187 BreakpointSiteList::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 
200 void
ForEach(std::function<void (BreakpointSite *)> const & callback)201 BreakpointSiteList::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 
208 bool
FindInRange(lldb::addr_t lower_bound,lldb::addr_t upper_bound,BreakpointSiteList & bp_site_list) const209 BreakpointSiteList::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