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