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 
11 // C Includes
12 // C++ Includes
13 // Other libraries and framework includes
14 // Project includes
15 #include "lldb/Breakpoint/BreakpointLocationList.h"
16 
17 #include "lldb/Breakpoint/BreakpointLocation.h"
18 #include "lldb/Breakpoint/Breakpoint.h"
19 #include "lldb/Core/ArchSpec.h"
20 #include "lldb/Core/Module.h"
21 #include "lldb/Core/Section.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 (NULL)
34 {
35 }
36 
37 BreakpointLocationList::~BreakpointLocationList()
38 {
39 }
40 
41 BreakpointLocationSP
42 BreakpointLocationList::Create (const Address &addr)
43 {
44     Mutex::Locker locker (m_mutex);
45     // The location ID is just the size of the location list + 1
46     lldb::break_id_t bp_loc_id = ++m_next_id;
47     BreakpointLocationSP bp_loc_sp (new BreakpointLocation (bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID, m_owner.IsHardware()));
48     m_locations.push_back (bp_loc_sp);
49     m_address_to_location[addr] = bp_loc_sp;
50     return bp_loc_sp;
51 }
52 
53 bool
54 BreakpointLocationList::ShouldStop (StoppointCallbackContext *context, lldb::break_id_t break_id)
55 {
56     BreakpointLocationSP bp = FindByID (break_id);
57     if (bp)
58     {
59         // Let the BreakpointLocation 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 bp->ShouldStop (context);
63     }
64     // We should stop here since this BreakpointLocation isn't valid anymore or it
65     // doesn't exist.
66     return true;
67 }
68 
69 lldb::break_id_t
70 BreakpointLocationList::FindIDByAddress (const Address &addr)
71 {
72     BreakpointLocationSP bp_loc_sp = FindByAddress (addr);
73     if (bp_loc_sp)
74     {
75         return bp_loc_sp->GetID();
76     }
77     return LLDB_INVALID_BREAK_ID;
78 }
79 
80 BreakpointLocationSP
81 BreakpointLocationList::FindByID (lldb::break_id_t break_id) const
82 {
83     BreakpointLocationSP bp_loc_sp;
84     Mutex::Locker locker (m_mutex);
85     // We never remove a breakpoint locations, so the ID can be translated into
86     // the location index by subtracting 1
87     uint32_t idx = break_id - 1;
88     if (idx <= m_locations.size())
89     {
90         bp_loc_sp = m_locations[idx];
91     }
92     return bp_loc_sp;
93 }
94 
95 size_t
96 BreakpointLocationList::FindInModule (Module *module,
97                                       BreakpointLocationCollection& bp_loc_list)
98 {
99     Mutex::Locker locker (m_mutex);
100     const size_t orig_size = bp_loc_list.GetSize();
101     collection::iterator pos, end = m_locations.end();
102 
103     for (pos = m_locations.begin(); pos != end; ++pos)
104     {
105         BreakpointLocationSP break_loc = (*pos);
106         SectionSP section_sp (break_loc->GetAddress().GetSection());
107         if (section_sp && section_sp->GetModule().get() == module)
108         {
109             bp_loc_list.Add (break_loc);
110         }
111     }
112     return bp_loc_list.GetSize() - orig_size;
113 }
114 
115 const BreakpointLocationSP
116 BreakpointLocationList::FindByAddress (const Address &addr) const
117 {
118     Mutex::Locker locker (m_mutex);
119     BreakpointLocationSP bp_loc_sp;
120     if (!m_locations.empty())
121     {
122         Address so_addr;
123 
124         if (addr.IsSectionOffset())
125         {
126             so_addr = addr;
127         }
128         else
129         {
130             // Try and resolve as a load address if possible.
131             m_owner.GetTarget().GetSectionLoadList().ResolveLoadAddress (addr.GetOffset(), so_addr);
132             if (!so_addr.IsValid())
133             {
134                 // The address didn't resolve, so just set to passed in addr.
135                 so_addr = addr;
136             }
137         }
138 
139         addr_map::const_iterator pos = m_address_to_location.find (so_addr);
140         if (pos != m_address_to_location.end())
141             bp_loc_sp = pos->second;
142     }
143 
144     return bp_loc_sp;
145 }
146 
147 void
148 BreakpointLocationList::Dump (Stream *s) const
149 {
150     s->Printf("%p: ", this);
151     //s->Indent();
152     Mutex::Locker locker (m_mutex);
153     s->Printf("BreakpointLocationList with %" PRIu64 " BreakpointLocations:\n", (uint64_t)m_locations.size());
154     s->IndentMore();
155     collection::const_iterator pos, end = m_locations.end();
156     for (pos = m_locations.begin(); pos != end; ++pos)
157         (*pos).get()->Dump(s);
158     s->IndentLess();
159 }
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 *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);
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 bool
271 BreakpointLocationList::RemoveLocation (const lldb::BreakpointLocationSP &bp_loc_sp)
272 {
273     if (bp_loc_sp)
274     {
275         Mutex::Locker locker (m_mutex);
276 
277         m_address_to_location.erase (bp_loc_sp->GetAddress());
278 
279         collection::iterator pos, end = m_locations.end();
280         for (pos = m_locations.begin(); pos != end; ++pos)
281         {
282             if ((*pos).get() == bp_loc_sp.get())
283             {
284                 m_locations.erase (pos);
285                 return true;
286             }
287         }
288 	}
289     return false;
290 }
291 
292 void
293 BreakpointLocationList::RemoveInvalidLocations (const ArchSpec &arch)
294 {
295     Mutex::Locker locker (m_mutex);
296     size_t idx = 0;
297     // Don't cache m_location.size() as it will change since we might
298     // remove locations from our vector...
299     while (idx < m_locations.size())
300     {
301         BreakpointLocation *bp_loc = m_locations[idx].get();
302         if (bp_loc->GetAddress().SectionWasDeleted())
303         {
304             // Section was deleted which means this breakpoint comes from a module
305             // that is no longer valid, so we should remove it.
306             m_locations.erase(m_locations.begin() + idx);
307             continue;
308         }
309         if (arch.IsValid())
310         {
311             ModuleSP module_sp (bp_loc->GetAddress().GetModule());
312             if (module_sp)
313             {
314                 if (!arch.IsCompatibleMatch(module_sp->GetArchitecture()))
315                 {
316                     // The breakpoint was in a module whose architecture is no longer
317                     // compatible with "arch", so we need to remove it
318                     m_locations.erase(m_locations.begin() + idx);
319                     continue;
320                 }
321             }
322         }
323         // Only increment the index if we didn't remove the locations at index "idx"
324         ++idx;
325     }
326 }
327 
328 void
329 BreakpointLocationList::StartRecordingNewLocations (BreakpointLocationCollection &new_locations)
330 {
331     Mutex::Locker locker (m_mutex);
332     assert (m_new_location_recorder == NULL);
333     m_new_location_recorder = &new_locations;
334 }
335 
336 void
337 BreakpointLocationList::StopRecordingNewLocations ()
338 {
339     Mutex::Locker locker (m_mutex);
340     m_new_location_recorder = NULL;
341 }
342 
343