1 //===-- BreakpointLocationList.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 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 // Project includes
14 #include "lldb/Breakpoint/BreakpointLocationList.h"
15 
16 #include "lldb/Breakpoint/BreakpointLocation.h"
17 #include "lldb/Breakpoint/Breakpoint.h"
18 #include "lldb/Core/ArchSpec.h"
19 #include "lldb/Core/Module.h"
20 #include "lldb/Core/Section.h"
21 #include "lldb/Target/SectionLoadList.h"
22 #include "lldb/Target/Target.h"
23 
24 using namespace lldb;
25 using namespace lldb_private;
26 
27 BreakpointLocationList::BreakpointLocationList(Breakpoint &owner) :
28     m_owner (owner),
29     m_locations(),
30     m_address_to_location (),
31     m_mutex (Mutex::eMutexTypeRecursive),
32     m_next_id (0),
33     m_new_location_recorder (nullptr)
34 {
35 }
36 
37 BreakpointLocationList::~BreakpointLocationList() = default;
38 
39 BreakpointLocationSP
40 BreakpointLocationList::Create (const Address &addr, bool resolve_indirect_symbols)
41 {
42     Mutex::Locker locker (m_mutex);
43     // The location ID is just the size of the location list + 1
44     lldb::break_id_t bp_loc_id = ++m_next_id;
45     BreakpointLocationSP bp_loc_sp (new BreakpointLocation (bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID, m_owner.IsHardware(), resolve_indirect_symbols));
46     m_locations.push_back (bp_loc_sp);
47     m_address_to_location[addr] = bp_loc_sp;
48     return bp_loc_sp;
49 }
50 
51 bool
52 BreakpointLocationList::ShouldStop (StoppointCallbackContext *context, lldb::break_id_t break_id)
53 {
54     BreakpointLocationSP bp = FindByID (break_id);
55     if (bp)
56     {
57         // Let the BreakpointLocation 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 bp->ShouldStop (context);
61     }
62     // We should stop here since this BreakpointLocation isn't valid anymore or it
63     // doesn't exist.
64     return true;
65 }
66 
67 lldb::break_id_t
68 BreakpointLocationList::FindIDByAddress (const Address &addr)
69 {
70     BreakpointLocationSP bp_loc_sp = FindByAddress (addr);
71     if (bp_loc_sp)
72     {
73         return bp_loc_sp->GetID();
74     }
75     return LLDB_INVALID_BREAK_ID;
76 }
77 
78 static bool
79 Compare (BreakpointLocationSP lhs, lldb::break_id_t val)
80 {
81     return lhs->GetID() < val;
82 }
83 
84 BreakpointLocationSP
85 BreakpointLocationList::FindByID (lldb::break_id_t break_id) const
86 {
87     Mutex::Locker locker (m_mutex);
88     collection::const_iterator end = m_locations.end();
89     collection::const_iterator pos = std::lower_bound(m_locations.begin(), end, break_id, Compare);
90     if (pos != end && (*pos)->GetID() == break_id)
91         return *(pos);
92     else
93         return BreakpointLocationSP();
94 }
95 
96 size_t
97 BreakpointLocationList::FindInModule (Module *module,
98                                       BreakpointLocationCollection& bp_loc_list)
99 {
100     Mutex::Locker locker (m_mutex);
101     const size_t orig_size = bp_loc_list.GetSize();
102     collection::iterator pos, end = m_locations.end();
103 
104     for (pos = m_locations.begin(); pos != end; ++pos)
105     {
106         BreakpointLocationSP break_loc = (*pos);
107         SectionSP section_sp (break_loc->GetAddress().GetSection());
108         if (section_sp && section_sp->GetModule().get() == module)
109         {
110             bp_loc_list.Add (break_loc);
111         }
112     }
113     return bp_loc_list.GetSize() - orig_size;
114 }
115 
116 const BreakpointLocationSP
117 BreakpointLocationList::FindByAddress (const Address &addr) const
118 {
119     Mutex::Locker locker (m_mutex);
120     BreakpointLocationSP bp_loc_sp;
121     if (!m_locations.empty())
122     {
123         Address so_addr;
124 
125         if (addr.IsSectionOffset())
126         {
127             so_addr = addr;
128         }
129         else
130         {
131             // Try and resolve as a load address if possible.
132             m_owner.GetTarget().GetSectionLoadList().ResolveLoadAddress (addr.GetOffset(), so_addr);
133             if (!so_addr.IsValid())
134             {
135                 // The address didn't resolve, so just set to passed in addr.
136                 so_addr = addr;
137             }
138         }
139 
140         addr_map::const_iterator pos = m_address_to_location.find (so_addr);
141         if (pos != m_address_to_location.end())
142             bp_loc_sp = pos->second;
143     }
144 
145     return bp_loc_sp;
146 }
147 
148 void
149 BreakpointLocationList::Dump (Stream *s) const
150 {
151     s->Printf("%p: ", static_cast<const void*>(this));
152     //s->Indent();
153     Mutex::Locker locker (m_mutex);
154     s->Printf("BreakpointLocationList with %" PRIu64 " BreakpointLocations:\n", (uint64_t)m_locations.size());
155     s->IndentMore();
156     collection::const_iterator pos, end = m_locations.end();
157     for (pos = m_locations.begin(); pos != end; ++pos)
158         (*pos).get()->Dump(s);
159     s->IndentLess();
160 }
161 
162 BreakpointLocationSP
163 BreakpointLocationList::GetByIndex (size_t i)
164 {
165     Mutex::Locker locker (m_mutex);
166     BreakpointLocationSP bp_loc_sp;
167     if (i < m_locations.size())
168         bp_loc_sp = m_locations[i];
169 
170     return bp_loc_sp;
171 }
172 
173 const BreakpointLocationSP
174 BreakpointLocationList::GetByIndex (size_t i) const
175 {
176     Mutex::Locker locker (m_mutex);
177     BreakpointLocationSP bp_loc_sp;
178     if (i < m_locations.size())
179         bp_loc_sp = m_locations[i];
180 
181     return bp_loc_sp;
182 }
183 
184 void
185 BreakpointLocationList::ClearAllBreakpointSites ()
186 {
187     Mutex::Locker locker (m_mutex);
188     collection::iterator pos, end = m_locations.end();
189     for (pos = m_locations.begin(); pos != end; ++pos)
190         (*pos)->ClearBreakpointSite();
191 }
192 
193 void
194 BreakpointLocationList::ResolveAllBreakpointSites ()
195 {
196     Mutex::Locker locker (m_mutex);
197     collection::iterator pos, end = m_locations.end();
198 
199     for (pos = m_locations.begin(); pos != end; ++pos)
200     {
201         if ((*pos)->IsEnabled())
202             (*pos)->ResolveBreakpointSite();
203     }
204 }
205 
206 uint32_t
207 BreakpointLocationList::GetHitCount () const
208 {
209     uint32_t hit_count = 0;
210     Mutex::Locker locker (m_mutex);
211     collection::const_iterator pos, end = m_locations.end();
212     for (pos = m_locations.begin(); pos != end; ++pos)
213         hit_count += (*pos)->GetHitCount();
214     return hit_count;
215 }
216 
217 size_t
218 BreakpointLocationList::GetNumResolvedLocations() const
219 {
220     Mutex::Locker locker (m_mutex);
221     size_t resolve_count = 0;
222     collection::const_iterator pos, end = m_locations.end();
223     for (pos = m_locations.begin(); pos != end; ++pos)
224     {
225         if ((*pos)->IsResolved())
226             ++resolve_count;
227     }
228     return resolve_count;
229 }
230 
231 void
232 BreakpointLocationList::GetDescription (Stream *s, lldb::DescriptionLevel level)
233 {
234     Mutex::Locker locker (m_mutex);
235     collection::iterator pos, end = m_locations.end();
236 
237     for (pos = m_locations.begin(); pos != end; ++pos)
238     {
239         s->Printf(" ");
240         (*pos)->GetDescription(s, level);
241     }
242 }
243 
244 BreakpointLocationSP
245 BreakpointLocationList::AddLocation (const Address &addr, bool resolve_indirect_symbols, bool *new_location)
246 {
247     Mutex::Locker locker (m_mutex);
248 
249     if (new_location)
250         *new_location = false;
251     BreakpointLocationSP bp_loc_sp (FindByAddress(addr));
252     if (!bp_loc_sp)
253 	{
254 		bp_loc_sp = Create (addr, resolve_indirect_symbols);
255 		if (bp_loc_sp)
256 		{
257 	    	bp_loc_sp->ResolveBreakpointSite();
258 
259 		    if (new_location)
260 	    	    *new_location = true;
261             if(m_new_location_recorder)
262             {
263                 m_new_location_recorder->Add(bp_loc_sp);
264             }
265 		}
266 	}
267     return bp_loc_sp;
268 }
269 
270 void
271 BreakpointLocationList::SwapLocation (BreakpointLocationSP to_location_sp, BreakpointLocationSP from_location_sp)
272 {
273     if (!from_location_sp || !to_location_sp)
274         return;
275 
276     m_address_to_location.erase(to_location_sp->GetAddress());
277     to_location_sp->SwapLocation(from_location_sp);
278     RemoveLocation(from_location_sp);
279     m_address_to_location[to_location_sp->GetAddress()] = to_location_sp;
280     to_location_sp->ResolveBreakpointSite();
281 }
282 
283 bool
284 BreakpointLocationList::RemoveLocation (const lldb::BreakpointLocationSP &bp_loc_sp)
285 {
286     if (bp_loc_sp)
287     {
288         Mutex::Locker locker (m_mutex);
289 
290         m_address_to_location.erase (bp_loc_sp->GetAddress());
291 
292         collection::iterator pos, end = m_locations.end();
293         for (pos = m_locations.begin(); pos != end; ++pos)
294         {
295             if ((*pos).get() == bp_loc_sp.get())
296             {
297                 m_locations.erase (pos);
298                 return true;
299             }
300         }
301     }
302     return false;
303 }
304 
305 void
306 BreakpointLocationList::RemoveInvalidLocations (const ArchSpec &arch)
307 {
308     Mutex::Locker locker (m_mutex);
309     size_t idx = 0;
310     // Don't cache m_location.size() as it will change since we might
311     // remove locations from our vector...
312     while (idx < m_locations.size())
313     {
314         BreakpointLocation *bp_loc = m_locations[idx].get();
315         if (bp_loc->GetAddress().SectionWasDeleted())
316         {
317             // Section was deleted which means this breakpoint comes from a module
318             // that is no longer valid, so we should remove it.
319             m_locations.erase(m_locations.begin() + idx);
320             continue;
321         }
322         if (arch.IsValid())
323         {
324             ModuleSP module_sp (bp_loc->GetAddress().GetModule());
325             if (module_sp)
326             {
327                 if (!arch.IsCompatibleMatch(module_sp->GetArchitecture()))
328                 {
329                     // The breakpoint was in a module whose architecture is no longer
330                     // compatible with "arch", so we need to remove it
331                     m_locations.erase(m_locations.begin() + idx);
332                     continue;
333                 }
334             }
335         }
336         // Only increment the index if we didn't remove the locations at index "idx"
337         ++idx;
338     }
339 }
340 
341 void
342 BreakpointLocationList::StartRecordingNewLocations (BreakpointLocationCollection &new_locations)
343 {
344     Mutex::Locker locker (m_mutex);
345     assert(m_new_location_recorder == nullptr);
346     m_new_location_recorder = &new_locations;
347 }
348 
349 void
350 BreakpointLocationList::StopRecordingNewLocations ()
351 {
352     Mutex::Locker locker (m_mutex);
353     m_new_location_recorder = nullptr;
354 }
355 
356 void
357 BreakpointLocationList::Compact()
358 {
359     lldb::break_id_t highest_id = 0;
360 
361     for (BreakpointLocationSP loc_sp : m_locations)
362     {
363         lldb::break_id_t cur_id = loc_sp->GetID();
364         if (cur_id > highest_id)
365             highest_id = cur_id;
366     }
367     m_next_id = highest_id;
368 }
369