xref: /llvm-project/lldb/source/Breakpoint/BreakpointLocationList.cpp (revision c4fb7180cbbe977f1ab1ce945a691550f8fdd1fb)
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       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 
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().ResolveLoadAddress(addr.GetOffset(), so_addr);
107       if (!so_addr.IsValid()) {
108         // The address didn't resolve, so just set to passed in addr.
109         so_addr = addr;
110       }
111     }
112 
113     addr_map::const_iterator pos = m_address_to_location.find(so_addr);
114     if (pos != m_address_to_location.end())
115       bp_loc_sp = pos->second;
116   }
117 
118   return bp_loc_sp;
119 }
120 
121 void BreakpointLocationList::Dump(Stream *s) const {
122   s->Printf("%p: ", static_cast<const void *>(this));
123   // s->Indent();
124   std::lock_guard<std::recursive_mutex> guard(m_mutex);
125   s->Printf("BreakpointLocationList with %" PRIu64 " BreakpointLocations:\n",
126             (uint64_t)m_locations.size());
127   s->IndentMore();
128   collection::const_iterator pos, end = m_locations.end();
129   for (pos = m_locations.begin(); pos != end; ++pos)
130     (*pos)->Dump(s);
131   s->IndentLess();
132 }
133 
134 BreakpointLocationSP BreakpointLocationList::GetByIndex(size_t i) {
135   std::lock_guard<std::recursive_mutex> guard(m_mutex);
136   BreakpointLocationSP bp_loc_sp;
137   if (i < m_locations.size())
138     bp_loc_sp = m_locations[i];
139 
140   return bp_loc_sp;
141 }
142 
143 const BreakpointLocationSP BreakpointLocationList::GetByIndex(size_t i) const {
144   std::lock_guard<std::recursive_mutex> guard(m_mutex);
145   BreakpointLocationSP bp_loc_sp;
146   if (i < m_locations.size())
147     bp_loc_sp = m_locations[i];
148 
149   return bp_loc_sp;
150 }
151 
152 void BreakpointLocationList::ClearAllBreakpointSites() {
153   std::lock_guard<std::recursive_mutex> guard(m_mutex);
154   collection::iterator pos, end = m_locations.end();
155   for (pos = m_locations.begin(); pos != end; ++pos)
156     (*pos)->ClearBreakpointSite();
157 }
158 
159 void BreakpointLocationList::ResolveAllBreakpointSites() {
160   std::lock_guard<std::recursive_mutex> guard(m_mutex);
161   collection::iterator pos, end = m_locations.end();
162 
163   for (pos = m_locations.begin(); pos != end; ++pos) {
164     if ((*pos)->IsEnabled())
165       (*pos)->ResolveBreakpointSite();
166   }
167 }
168 
169 uint32_t BreakpointLocationList::GetHitCount() const {
170   uint32_t hit_count = 0;
171   std::lock_guard<std::recursive_mutex> guard(m_mutex);
172   collection::const_iterator pos, end = m_locations.end();
173   for (pos = m_locations.begin(); pos != end; ++pos)
174     hit_count += (*pos)->GetHitCount();
175   return hit_count;
176 }
177 
178 void BreakpointLocationList::ResetHitCount() {
179   std::lock_guard<std::recursive_mutex> guard(m_mutex);
180   for (auto &loc : m_locations)
181     loc->ResetHitCount();
182 }
183 
184 size_t BreakpointLocationList::GetNumResolvedLocations() const {
185   std::lock_guard<std::recursive_mutex> guard(m_mutex);
186   size_t resolve_count = 0;
187   collection::const_iterator pos, end = m_locations.end();
188   for (pos = m_locations.begin(); pos != end; ++pos) {
189     if ((*pos)->IsResolved())
190       ++resolve_count;
191   }
192   return resolve_count;
193 }
194 
195 void BreakpointLocationList::GetDescription(Stream *s,
196                                             lldb::DescriptionLevel level) {
197   std::lock_guard<std::recursive_mutex> guard(m_mutex);
198   collection::iterator pos, end = m_locations.end();
199 
200   for (pos = m_locations.begin(); pos != end; ++pos) {
201     s->Printf(" ");
202     (*pos)->GetDescription(s, level);
203   }
204 }
205 
206 BreakpointLocationSP BreakpointLocationList::AddLocation(
207     const Address &addr, bool resolve_indirect_symbols, bool *new_location) {
208   std::lock_guard<std::recursive_mutex> guard(m_mutex);
209 
210   if (new_location)
211     *new_location = false;
212   BreakpointLocationSP bp_loc_sp(FindByAddress(addr));
213   if (!bp_loc_sp) {
214     bp_loc_sp = Create(addr, resolve_indirect_symbols);
215     if (bp_loc_sp) {
216       bp_loc_sp->ResolveBreakpointSite();
217 
218       if (new_location)
219         *new_location = true;
220       if (m_new_location_recorder) {
221         m_new_location_recorder->Add(bp_loc_sp);
222       }
223     }
224   }
225   return bp_loc_sp;
226 }
227 
228 void BreakpointLocationList::SwapLocation(
229     BreakpointLocationSP to_location_sp,
230     BreakpointLocationSP from_location_sp) {
231   if (!from_location_sp || !to_location_sp)
232     return;
233 
234   m_address_to_location.erase(to_location_sp->GetAddress());
235   to_location_sp->SwapLocation(from_location_sp);
236   RemoveLocation(from_location_sp);
237   m_address_to_location[to_location_sp->GetAddress()] = to_location_sp;
238   to_location_sp->ResolveBreakpointSite();
239 }
240 
241 bool BreakpointLocationList::RemoveLocation(
242     const lldb::BreakpointLocationSP &bp_loc_sp) {
243   if (bp_loc_sp) {
244     std::lock_guard<std::recursive_mutex> guard(m_mutex);
245 
246     m_address_to_location.erase(bp_loc_sp->GetAddress());
247 
248     size_t num_locations = m_locations.size();
249     for (size_t idx = 0; idx < num_locations; idx++) {
250       if (m_locations[idx].get() == bp_loc_sp.get()) {
251         RemoveLocationByIndex(idx);
252         return true;
253       }
254     }
255   }
256   return false;
257 }
258 
259 void BreakpointLocationList::RemoveLocationByIndex(size_t idx) {
260   assert (idx < m_locations.size());
261   m_address_to_location.erase(m_locations[idx]->GetAddress());
262   m_locations.erase(m_locations.begin() + idx);
263 }
264 
265 void BreakpointLocationList::RemoveInvalidLocations(const ArchSpec &arch) {
266   std::lock_guard<std::recursive_mutex> guard(m_mutex);
267   size_t idx = 0;
268   // Don't cache m_location.size() as it will change since we might remove
269   // locations from our vector...
270   while (idx < m_locations.size()) {
271     BreakpointLocation *bp_loc = m_locations[idx].get();
272     if (bp_loc->GetAddress().SectionWasDeleted()) {
273       // Section was deleted which means this breakpoint comes from a module
274       // that is no longer valid, so we should remove it.
275       RemoveLocationByIndex(idx);
276       continue;
277     }
278     if (arch.IsValid()) {
279       ModuleSP module_sp(bp_loc->GetAddress().GetModule());
280       if (module_sp) {
281         if (!arch.IsCompatibleMatch(module_sp->GetArchitecture())) {
282           // The breakpoint was in a module whose architecture is no longer
283           // compatible with "arch", so we need to remove it
284           RemoveLocationByIndex(idx);
285           continue;
286         }
287       }
288     }
289     // Only increment the index if we didn't remove the locations at index
290     // "idx"
291     ++idx;
292   }
293 }
294 
295 void BreakpointLocationList::StartRecordingNewLocations(
296     BreakpointLocationCollection &new_locations) {
297   std::lock_guard<std::recursive_mutex> guard(m_mutex);
298   assert(m_new_location_recorder == nullptr);
299   m_new_location_recorder = &new_locations;
300 }
301 
302 void BreakpointLocationList::StopRecordingNewLocations() {
303   std::lock_guard<std::recursive_mutex> guard(m_mutex);
304   m_new_location_recorder = nullptr;
305 }
306 
307 void BreakpointLocationList::Compact() {
308   lldb::break_id_t highest_id = 0;
309 
310   for (BreakpointLocationSP loc_sp : m_locations) {
311     lldb::break_id_t cur_id = loc_sp->GetID();
312     if (cur_id > highest_id)
313       highest_id = cur_id;
314   }
315   m_next_id = highest_id;
316 }
317