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