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.8llx ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID());
73         return bp.get()->GetID();
74     }
75     //DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8llx ) => 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 void
168 BreakpointSiteList::Dump (Stream *s) const
169 {
170     s->Printf("%p: ", this);
171     //s->Indent();
172     s->Printf("BreakpointSiteList with %u BreakpointSites:\n", (uint32_t)m_bp_site_list.size());
173     s->IndentMore();
174     collection::const_iterator pos;
175     collection::const_iterator end = m_bp_site_list.end();
176     for (pos = m_bp_site_list.begin(); pos != end; ++pos)
177         pos->second.get()->Dump(s);
178     s->IndentLess();
179 }
180 
181 
182 BreakpointSiteSP
183 BreakpointSiteList::GetByIndex (uint32_t i)
184 {
185     BreakpointSiteSP stop_sp;
186     collection::iterator end = m_bp_site_list.end();
187     collection::iterator pos;
188     uint32_t curr_i = 0;
189     for (pos = m_bp_site_list.begin(), curr_i = 0; pos != end; ++pos, ++curr_i)
190     {
191         if (curr_i == i)
192             stop_sp = pos->second;
193     }
194     return stop_sp;
195 }
196 
197 const BreakpointSiteSP
198 BreakpointSiteList::GetByIndex (uint32_t i) const
199 {
200     BreakpointSiteSP stop_sp;
201     collection::const_iterator end = m_bp_site_list.end();
202     collection::const_iterator pos;
203     uint32_t curr_i = 0;
204     for (pos = m_bp_site_list.begin(), curr_i = 0; pos != end; ++pos, ++curr_i)
205     {
206         if (curr_i == i)
207             stop_sp = pos->second;
208     }
209     return stop_sp;
210 }
211 
212 bool
213 BreakpointSiteList::FindInRange (lldb::addr_t lower_bound, lldb::addr_t upper_bound, BreakpointSiteList &bp_site_list) const
214 {
215 
216     if (lower_bound > upper_bound)
217         return false;
218 
219     collection::const_iterator lower, upper, pos;
220     lower = m_bp_site_list.lower_bound(lower_bound);
221     if (lower == m_bp_site_list.end()
222             || (*lower).first >= upper_bound)
223         return false;
224 
225     // This is one tricky bit.  The breakpoint might overlap the bottom end of the range.  So we grab the
226     // breakpoint prior to the lower bound, and check that that + its byte size isn't in our range.
227     if (lower != m_bp_site_list.begin())
228     {
229         collection::const_iterator prev_pos = lower;
230         prev_pos--;
231         const BreakpointSiteSP &prev_bp = (*prev_pos).second;
232         if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound)
233             bp_site_list.Add (prev_bp);
234 
235     }
236 
237     upper = m_bp_site_list.upper_bound(upper_bound);
238 
239     for (pos = lower; pos != upper; pos++)
240     {
241         bp_site_list.Add ((*pos).second);
242     }
243     return true;
244 }
245 
246 
247 void
248 BreakpointSiteList::SetEnabledForAll (const bool enabled, const lldb::break_id_t except_id)
249 {
250     collection::iterator end = m_bp_site_list.end();
251     collection::iterator pos;
252     for (pos = m_bp_site_list.begin(); pos != end; ++pos)
253     {
254         if (except_id != LLDB_INVALID_BREAK_ID && except_id != pos->second->GetID())
255             pos->second->SetEnabled (enabled);
256         else
257             pos->second->SetEnabled (!enabled);
258     }
259 }
260 
261 const BreakpointSiteList::collection *
262 BreakpointSiteList::GetMap ()
263 {
264     return &m_bp_site_list;
265 }
266