BreakpointLocationList.cpp revision 296417
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
24using namespace lldb;
25using namespace lldb_private;
26
27BreakpointLocationList::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
37BreakpointLocationList::~BreakpointLocationList() = default;
38
39BreakpointLocationSP
40BreakpointLocationList::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
51bool
52BreakpointLocationList::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
67lldb::break_id_t
68BreakpointLocationList::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
78static bool
79Compare (BreakpointLocationSP lhs, lldb::break_id_t val)
80{
81    return lhs->GetID() < val;
82}
83
84BreakpointLocationSP
85BreakpointLocationList::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
96size_t
97BreakpointLocationList::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
116const BreakpointLocationSP
117BreakpointLocationList::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
148void
149BreakpointLocationList::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
162BreakpointLocationSP
163BreakpointLocationList::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
173const BreakpointLocationSP
174BreakpointLocationList::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
184void
185BreakpointLocationList::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
193void
194BreakpointLocationList::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
206uint32_t
207BreakpointLocationList::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
217size_t
218BreakpointLocationList::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
231void
232BreakpointLocationList::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
244BreakpointLocationSP
245BreakpointLocationList::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
270void
271BreakpointLocationList::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
283bool
284BreakpointLocationList::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
305void
306BreakpointLocationList::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
341void
342BreakpointLocationList::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
349void
350BreakpointLocationList::StopRecordingNewLocations ()
351{
352    Mutex::Locker locker (m_mutex);
353    m_new_location_recorder = nullptr;
354}
355
356void
357BreakpointLocationList::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