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 
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
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 
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 
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 
63 static bool Compare(BreakpointLocationSP lhs, lldb::break_id_t val) {
64   return lhs->GetID() < val;
65 }
66 
67 BreakpointLocationSP
68 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       std::lower_bound(m_locations.begin(), end, break_id, Compare);
73   if (pos != end && (*pos)->GetID() == break_id)
74     return *(pos);
75   else
76     return BreakpointLocationSP();
77 }
78 
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
96 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 
122 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 
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 
144 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 
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 
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 
170 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 
179 size_t BreakpointLocationList::GetNumResolvedLocations() const {
180   std::lock_guard<std::recursive_mutex> guard(m_mutex);
181   size_t resolve_count = 0;
182   collection::const_iterator pos, end = m_locations.end();
183   for (pos = m_locations.begin(); pos != end; ++pos) {
184     if ((*pos)->IsResolved())
185       ++resolve_count;
186   }
187   return resolve_count;
188 }
189 
190 void BreakpointLocationList::GetDescription(Stream *s,
191                                             lldb::DescriptionLevel level) {
192   std::lock_guard<std::recursive_mutex> guard(m_mutex);
193   collection::iterator pos, end = m_locations.end();
194 
195   for (pos = m_locations.begin(); pos != end; ++pos) {
196     s->Printf(" ");
197     (*pos)->GetDescription(s, level);
198   }
199 }
200 
201 BreakpointLocationSP BreakpointLocationList::AddLocation(
202     const Address &addr, bool resolve_indirect_symbols, bool *new_location) {
203   std::lock_guard<std::recursive_mutex> guard(m_mutex);
204 
205   if (new_location)
206     *new_location = false;
207   BreakpointLocationSP bp_loc_sp(FindByAddress(addr));
208   if (!bp_loc_sp) {
209     bp_loc_sp = Create(addr, resolve_indirect_symbols);
210     if (bp_loc_sp) {
211       bp_loc_sp->ResolveBreakpointSite();
212 
213       if (new_location)
214         *new_location = true;
215       if (m_new_location_recorder) {
216         m_new_location_recorder->Add(bp_loc_sp);
217       }
218     }
219   }
220   return bp_loc_sp;
221 }
222 
223 void BreakpointLocationList::SwapLocation(
224     BreakpointLocationSP to_location_sp,
225     BreakpointLocationSP from_location_sp) {
226   if (!from_location_sp || !to_location_sp)
227     return;
228 
229   m_address_to_location.erase(to_location_sp->GetAddress());
230   to_location_sp->SwapLocation(from_location_sp);
231   RemoveLocation(from_location_sp);
232   m_address_to_location[to_location_sp->GetAddress()] = to_location_sp;
233   to_location_sp->ResolveBreakpointSite();
234 }
235 
236 bool BreakpointLocationList::RemoveLocation(
237     const lldb::BreakpointLocationSP &bp_loc_sp) {
238   if (bp_loc_sp) {
239     std::lock_guard<std::recursive_mutex> guard(m_mutex);
240 
241     m_address_to_location.erase(bp_loc_sp->GetAddress());
242 
243     size_t num_locations = m_locations.size();
244     for (size_t idx = 0; idx < num_locations; idx++) {
245       if (m_locations[idx].get() == bp_loc_sp.get()) {
246         RemoveLocationByIndex(idx);
247         return true;
248       }
249     }
250   }
251   return false;
252 }
253 
254 void BreakpointLocationList::RemoveLocationByIndex(size_t idx) {
255   assert (idx < m_locations.size());
256   m_address_to_location.erase(m_locations[idx]->GetAddress());
257   m_locations.erase(m_locations.begin() + idx);
258 }
259 
260 void BreakpointLocationList::RemoveInvalidLocations(const ArchSpec &arch) {
261   std::lock_guard<std::recursive_mutex> guard(m_mutex);
262   size_t idx = 0;
263   // Don't cache m_location.size() as it will change since we might remove
264   // locations from our vector...
265   while (idx < m_locations.size()) {
266     BreakpointLocation *bp_loc = m_locations[idx].get();
267     if (bp_loc->GetAddress().SectionWasDeleted()) {
268       // Section was deleted which means this breakpoint comes from a module
269       // that is no longer valid, so we should remove it.
270       RemoveLocationByIndex(idx);
271       continue;
272     }
273     if (arch.IsValid()) {
274       ModuleSP module_sp(bp_loc->GetAddress().GetModule());
275       if (module_sp) {
276         if (!arch.IsCompatibleMatch(module_sp->GetArchitecture())) {
277           // The breakpoint was in a module whose architecture is no longer
278           // compatible with "arch", so we need to remove it
279           RemoveLocationByIndex(idx);
280           continue;
281         }
282       }
283     }
284     // Only increment the index if we didn't remove the locations at index
285     // "idx"
286     ++idx;
287   }
288 }
289 
290 void BreakpointLocationList::StartRecordingNewLocations(
291     BreakpointLocationCollection &new_locations) {
292   std::lock_guard<std::recursive_mutex> guard(m_mutex);
293   assert(m_new_location_recorder == nullptr);
294   m_new_location_recorder = &new_locations;
295 }
296 
297 void BreakpointLocationList::StopRecordingNewLocations() {
298   std::lock_guard<std::recursive_mutex> guard(m_mutex);
299   m_new_location_recorder = nullptr;
300 }
301 
302 void BreakpointLocationList::Compact() {
303   lldb::break_id_t highest_id = 0;
304 
305   for (BreakpointLocationSP loc_sp : m_locations) {
306     lldb::break_id_t cur_id = loc_sp->GetID();
307     if (cur_id > highest_id)
308       highest_id = cur_id;
309   }
310   m_next_id = highest_id;
311 }
312