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 
22 BreakpointSiteList::BreakpointSiteList() :
23     m_bp_site_list()
24 {
25 }
26 
27 BreakpointSiteList::~BreakpointSiteList()
28 {
29 }
30 
31 // Add breakpoint site to the list.  However, if the element already exists in the
32 // list, then we don't add it, and return LLDB_INVALID_BREAK_ID.
33 
34 lldb::break_id_t
35 BreakpointSiteList::Add(const BreakpointSiteSP &bp)
36 {
37     lldb::addr_t bp_site_load_addr = bp->GetLoadAddress();
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 
51 bool
52 BreakpointSiteList::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 }
66 lldb::break_id_t
67 BreakpointSiteList::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 
79 bool
80 BreakpointSiteList::Remove (lldb::break_id_t break_id)
81 {
82     collection::iterator pos = GetIDIterator(break_id);    // Predicate
83     if (pos != m_bp_site_list.end())
84     {
85         m_bp_site_list.erase(pos);
86         return true;
87     }
88     return false;
89 }
90 
91 bool
92 BreakpointSiteList::RemoveByAddress (lldb::addr_t address)
93 {
94     collection::iterator pos =  m_bp_site_list.find(address);
95     if (pos != m_bp_site_list.end())
96     {
97         m_bp_site_list.erase(pos);
98         return true;
99     }
100     return false;
101 }
102 
103 class BreakpointSiteIDMatches
104 {
105 public:
106     BreakpointSiteIDMatches (lldb::break_id_t break_id) :
107         m_break_id(break_id)
108     {
109     }
110 
111     bool operator() (std::pair <lldb::addr_t, BreakpointSiteSP> val_pair) const
112     {
113         return m_break_id == val_pair.second.get()->GetID();
114     }
115 
116 private:
117    const lldb::break_id_t m_break_id;
118 };
119 
120 BreakpointSiteList::collection::iterator
121 BreakpointSiteList::GetIDIterator (lldb::break_id_t break_id)
122 {
123     return std::find_if(m_bp_site_list.begin(), m_bp_site_list.end(),   // Search full range
124                         BreakpointSiteIDMatches(break_id));             // Predicate
125 }
126 
127 BreakpointSiteList::collection::const_iterator
128 BreakpointSiteList::GetIDConstIterator (lldb::break_id_t break_id) const
129 {
130     return std::find_if(m_bp_site_list.begin(), m_bp_site_list.end(),   // Search full range
131                         BreakpointSiteIDMatches(break_id));             // Predicate
132 }
133 
134 BreakpointSiteSP
135 BreakpointSiteList::FindByID (lldb::break_id_t break_id)
136 {
137     BreakpointSiteSP stop_sp;
138     collection::iterator pos = GetIDIterator(break_id);
139     if (pos != m_bp_site_list.end())
140         stop_sp = pos->second;
141 
142     return stop_sp;
143 }
144 
145 const BreakpointSiteSP
146 BreakpointSiteList::FindByID (lldb::break_id_t break_id) const
147 {
148     BreakpointSiteSP stop_sp;
149     collection::const_iterator pos = GetIDConstIterator(break_id);
150     if (pos != m_bp_site_list.end())
151         stop_sp = pos->second;
152 
153     return stop_sp;
154 }
155 
156 BreakpointSiteSP
157 BreakpointSiteList::FindByAddress (lldb::addr_t addr)
158 {
159     BreakpointSiteSP found_sp;
160 
161     collection::iterator iter =  m_bp_site_list.find(addr);
162     if (iter != m_bp_site_list.end())
163         found_sp = iter->second;
164     return found_sp;
165 }
166 
167 bool
168 BreakpointSiteList::BreakpointSiteContainsBreakpoint (lldb::break_id_t bp_site_id, lldb::break_id_t bp_id)
169 {
170     collection::const_iterator pos = GetIDConstIterator(bp_site_id);
171     if (pos != m_bp_site_list.end())
172         pos->second->IsBreakpointAtThisSite (bp_id);
173 
174     return false;
175 }
176 
177 void
178 BreakpointSiteList::Dump (Stream *s) const
179 {
180     s->Printf("%p: ", this);
181     //s->Indent();
182     s->Printf("BreakpointSiteList with %u BreakpointSites:\n", (uint32_t)m_bp_site_list.size());
183     s->IndentMore();
184     collection::const_iterator pos;
185     collection::const_iterator end = m_bp_site_list.end();
186     for (pos = m_bp_site_list.begin(); pos != end; ++pos)
187         pos->second.get()->Dump(s);
188     s->IndentLess();
189 }
190 
191 
192 BreakpointSiteSP
193 BreakpointSiteList::GetByIndex (uint32_t i)
194 {
195     BreakpointSiteSP stop_sp;
196     collection::iterator end = m_bp_site_list.end();
197     collection::iterator pos;
198     uint32_t curr_i = 0;
199     for (pos = m_bp_site_list.begin(), curr_i = 0; pos != end; ++pos, ++curr_i)
200     {
201         if (curr_i == i)
202             stop_sp = pos->second;
203     }
204     return stop_sp;
205 }
206 
207 const BreakpointSiteSP
208 BreakpointSiteList::GetByIndex (uint32_t i) const
209 {
210     BreakpointSiteSP stop_sp;
211     collection::const_iterator end = m_bp_site_list.end();
212     collection::const_iterator pos;
213     uint32_t curr_i = 0;
214     for (pos = m_bp_site_list.begin(), curr_i = 0; pos != end; ++pos, ++curr_i)
215     {
216         if (curr_i == i)
217             stop_sp = pos->second;
218     }
219     return stop_sp;
220 }
221 
222 bool
223 BreakpointSiteList::FindInRange (lldb::addr_t lower_bound, lldb::addr_t upper_bound, BreakpointSiteList &bp_site_list) const
224 {
225 
226     if (lower_bound > upper_bound)
227         return false;
228 
229     collection::const_iterator lower, upper, pos;
230     lower = m_bp_site_list.lower_bound(lower_bound);
231     if (lower == m_bp_site_list.end()
232             || (*lower).first >= upper_bound)
233         return false;
234 
235     // This is one tricky bit.  The breakpoint might overlap the bottom end of the range.  So we grab the
236     // breakpoint prior to the lower bound, and check that that + its byte size isn't in our range.
237     if (lower != m_bp_site_list.begin())
238     {
239         collection::const_iterator prev_pos = lower;
240         prev_pos--;
241         const BreakpointSiteSP &prev_bp = (*prev_pos).second;
242         if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound)
243             bp_site_list.Add (prev_bp);
244 
245     }
246 
247     upper = m_bp_site_list.upper_bound(upper_bound);
248 
249     for (pos = lower; pos != upper; pos++)
250     {
251         bp_site_list.Add ((*pos).second);
252     }
253     return true;
254 }
255 
256 
257 void
258 BreakpointSiteList::SetEnabledForAll (const bool enabled, const lldb::break_id_t except_id)
259 {
260     collection::iterator end = m_bp_site_list.end();
261     collection::iterator pos;
262     for (pos = m_bp_site_list.begin(); pos != end; ++pos)
263     {
264         if (except_id != LLDB_INVALID_BREAK_ID && except_id != pos->second->GetID())
265             pos->second->SetEnabled (enabled);
266         else
267             pos->second->SetEnabled (!enabled);
268     }
269 }
270 
271 const BreakpointSiteList::collection *
272 BreakpointSiteList::GetMap ()
273 {
274     return &m_bp_site_list;
275 }
276