xref: /openbsd-src/gnu/llvm/lldb/source/Breakpoint/BreakpointLocationList.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- BreakpointLocationList.cpp ----------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "lldb/Breakpoint/BreakpointLocationList.h"
10061da546Spatrick 
11061da546Spatrick #include "lldb/Breakpoint/Breakpoint.h"
12061da546Spatrick #include "lldb/Breakpoint/BreakpointLocation.h"
13061da546Spatrick #include "lldb/Core/Module.h"
14061da546Spatrick #include "lldb/Core/Section.h"
15061da546Spatrick #include "lldb/Target/SectionLoadList.h"
16061da546Spatrick #include "lldb/Target/Target.h"
17061da546Spatrick #include "lldb/Utility/ArchSpec.h"
18061da546Spatrick 
19061da546Spatrick using namespace lldb;
20061da546Spatrick using namespace lldb_private;
21061da546Spatrick 
BreakpointLocationList(Breakpoint & owner)22061da546Spatrick BreakpointLocationList::BreakpointLocationList(Breakpoint &owner)
23*f6aab3d8Srobert     : m_owner(owner), m_next_id(0), m_new_location_recorder(nullptr) {}
24061da546Spatrick 
25061da546Spatrick BreakpointLocationList::~BreakpointLocationList() = default;
26061da546Spatrick 
27061da546Spatrick BreakpointLocationSP
Create(const Address & addr,bool resolve_indirect_symbols)28061da546Spatrick BreakpointLocationList::Create(const Address &addr,
29061da546Spatrick                                bool resolve_indirect_symbols) {
30061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
31061da546Spatrick   // The location ID is just the size of the location list + 1
32061da546Spatrick   lldb::break_id_t bp_loc_id = ++m_next_id;
33061da546Spatrick   BreakpointLocationSP bp_loc_sp(
34061da546Spatrick       new BreakpointLocation(bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID,
35061da546Spatrick                              m_owner.IsHardware(), resolve_indirect_symbols));
36061da546Spatrick   m_locations.push_back(bp_loc_sp);
37061da546Spatrick   m_address_to_location[addr] = bp_loc_sp;
38061da546Spatrick   return bp_loc_sp;
39061da546Spatrick }
40061da546Spatrick 
ShouldStop(StoppointCallbackContext * context,lldb::break_id_t break_id)41061da546Spatrick bool BreakpointLocationList::ShouldStop(StoppointCallbackContext *context,
42061da546Spatrick                                         lldb::break_id_t break_id) {
43061da546Spatrick   BreakpointLocationSP bp = FindByID(break_id);
44061da546Spatrick   if (bp) {
45061da546Spatrick     // Let the BreakpointLocation decide if it should stop here (could not have
46061da546Spatrick     // reached it's target hit count yet, or it could have a callback that
47061da546Spatrick     // decided it shouldn't stop (shared library loads/unloads).
48061da546Spatrick     return bp->ShouldStop(context);
49061da546Spatrick   }
50061da546Spatrick   // We should stop here since this BreakpointLocation isn't valid anymore or
51061da546Spatrick   // it doesn't exist.
52061da546Spatrick   return true;
53061da546Spatrick }
54061da546Spatrick 
FindIDByAddress(const Address & addr)55061da546Spatrick lldb::break_id_t BreakpointLocationList::FindIDByAddress(const Address &addr) {
56061da546Spatrick   BreakpointLocationSP bp_loc_sp = FindByAddress(addr);
57061da546Spatrick   if (bp_loc_sp) {
58061da546Spatrick     return bp_loc_sp->GetID();
59061da546Spatrick   }
60061da546Spatrick   return LLDB_INVALID_BREAK_ID;
61061da546Spatrick }
62061da546Spatrick 
Compare(BreakpointLocationSP lhs,lldb::break_id_t val)63061da546Spatrick static bool Compare(BreakpointLocationSP lhs, lldb::break_id_t val) {
64061da546Spatrick   return lhs->GetID() < val;
65061da546Spatrick }
66061da546Spatrick 
67061da546Spatrick BreakpointLocationSP
FindByID(lldb::break_id_t break_id) const68061da546Spatrick BreakpointLocationList::FindByID(lldb::break_id_t break_id) const {
69061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
70061da546Spatrick   collection::const_iterator end = m_locations.end();
71061da546Spatrick   collection::const_iterator pos =
72*f6aab3d8Srobert       llvm::lower_bound(m_locations, break_id, Compare);
73061da546Spatrick   if (pos != end && (*pos)->GetID() == break_id)
74061da546Spatrick     return *(pos);
75061da546Spatrick   else
76061da546Spatrick     return BreakpointLocationSP();
77061da546Spatrick }
78061da546Spatrick 
FindInModule(Module * module,BreakpointLocationCollection & bp_loc_list)79061da546Spatrick size_t BreakpointLocationList::FindInModule(
80061da546Spatrick     Module *module, BreakpointLocationCollection &bp_loc_list) {
81061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
82061da546Spatrick   const size_t orig_size = bp_loc_list.GetSize();
83061da546Spatrick   collection::iterator pos, end = m_locations.end();
84061da546Spatrick 
85061da546Spatrick   for (pos = m_locations.begin(); pos != end; ++pos) {
86061da546Spatrick     BreakpointLocationSP break_loc = (*pos);
87061da546Spatrick     SectionSP section_sp(break_loc->GetAddress().GetSection());
88061da546Spatrick     if (section_sp && section_sp->GetModule().get() == module) {
89061da546Spatrick       bp_loc_list.Add(break_loc);
90061da546Spatrick     }
91061da546Spatrick   }
92061da546Spatrick   return bp_loc_list.GetSize() - orig_size;
93061da546Spatrick }
94061da546Spatrick 
95061da546Spatrick const BreakpointLocationSP
FindByAddress(const Address & addr) const96061da546Spatrick BreakpointLocationList::FindByAddress(const Address &addr) const {
97061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
98061da546Spatrick   BreakpointLocationSP bp_loc_sp;
99061da546Spatrick   if (!m_locations.empty()) {
100061da546Spatrick     Address so_addr;
101061da546Spatrick 
102061da546Spatrick     if (addr.IsSectionOffset()) {
103061da546Spatrick       so_addr = addr;
104061da546Spatrick     } else {
105061da546Spatrick       // Try and resolve as a load address if possible.
106061da546Spatrick       m_owner.GetTarget().GetSectionLoadList().ResolveLoadAddress(
107061da546Spatrick           addr.GetOffset(), so_addr);
108061da546Spatrick       if (!so_addr.IsValid()) {
109061da546Spatrick         // The address didn't resolve, so just set to passed in addr.
110061da546Spatrick         so_addr = addr;
111061da546Spatrick       }
112061da546Spatrick     }
113061da546Spatrick 
114061da546Spatrick     addr_map::const_iterator pos = m_address_to_location.find(so_addr);
115061da546Spatrick     if (pos != m_address_to_location.end())
116061da546Spatrick       bp_loc_sp = pos->second;
117061da546Spatrick   }
118061da546Spatrick 
119061da546Spatrick   return bp_loc_sp;
120061da546Spatrick }
121061da546Spatrick 
Dump(Stream * s) const122061da546Spatrick void BreakpointLocationList::Dump(Stream *s) const {
123061da546Spatrick   s->Printf("%p: ", static_cast<const void *>(this));
124061da546Spatrick   // s->Indent();
125061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
126061da546Spatrick   s->Printf("BreakpointLocationList with %" PRIu64 " BreakpointLocations:\n",
127061da546Spatrick             (uint64_t)m_locations.size());
128061da546Spatrick   s->IndentMore();
129061da546Spatrick   collection::const_iterator pos, end = m_locations.end();
130061da546Spatrick   for (pos = m_locations.begin(); pos != end; ++pos)
131061da546Spatrick     (*pos)->Dump(s);
132061da546Spatrick   s->IndentLess();
133061da546Spatrick }
134061da546Spatrick 
GetByIndex(size_t i)135061da546Spatrick BreakpointLocationSP BreakpointLocationList::GetByIndex(size_t i) {
136061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
137061da546Spatrick   BreakpointLocationSP bp_loc_sp;
138061da546Spatrick   if (i < m_locations.size())
139061da546Spatrick     bp_loc_sp = m_locations[i];
140061da546Spatrick 
141061da546Spatrick   return bp_loc_sp;
142061da546Spatrick }
143061da546Spatrick 
GetByIndex(size_t i) const144061da546Spatrick const BreakpointLocationSP BreakpointLocationList::GetByIndex(size_t i) const {
145061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
146061da546Spatrick   BreakpointLocationSP bp_loc_sp;
147061da546Spatrick   if (i < m_locations.size())
148061da546Spatrick     bp_loc_sp = m_locations[i];
149061da546Spatrick 
150061da546Spatrick   return bp_loc_sp;
151061da546Spatrick }
152061da546Spatrick 
ClearAllBreakpointSites()153061da546Spatrick void BreakpointLocationList::ClearAllBreakpointSites() {
154061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
155061da546Spatrick   collection::iterator pos, end = m_locations.end();
156061da546Spatrick   for (pos = m_locations.begin(); pos != end; ++pos)
157061da546Spatrick     (*pos)->ClearBreakpointSite();
158061da546Spatrick }
159061da546Spatrick 
ResolveAllBreakpointSites()160061da546Spatrick void BreakpointLocationList::ResolveAllBreakpointSites() {
161061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
162061da546Spatrick   collection::iterator pos, end = m_locations.end();
163061da546Spatrick 
164061da546Spatrick   for (pos = m_locations.begin(); pos != end; ++pos) {
165061da546Spatrick     if ((*pos)->IsEnabled())
166061da546Spatrick       (*pos)->ResolveBreakpointSite();
167061da546Spatrick   }
168061da546Spatrick }
169061da546Spatrick 
GetHitCount() const170061da546Spatrick uint32_t BreakpointLocationList::GetHitCount() const {
171061da546Spatrick   uint32_t hit_count = 0;
172061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
173061da546Spatrick   collection::const_iterator pos, end = m_locations.end();
174061da546Spatrick   for (pos = m_locations.begin(); pos != end; ++pos)
175061da546Spatrick     hit_count += (*pos)->GetHitCount();
176061da546Spatrick   return hit_count;
177061da546Spatrick }
178061da546Spatrick 
ResetHitCount()179*f6aab3d8Srobert void BreakpointLocationList::ResetHitCount() {
180*f6aab3d8Srobert   std::lock_guard<std::recursive_mutex> guard(m_mutex);
181*f6aab3d8Srobert   for (auto &loc : m_locations)
182*f6aab3d8Srobert     loc->ResetHitCount();
183*f6aab3d8Srobert }
184*f6aab3d8Srobert 
GetNumResolvedLocations() const185061da546Spatrick size_t BreakpointLocationList::GetNumResolvedLocations() const {
186061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
187061da546Spatrick   size_t resolve_count = 0;
188061da546Spatrick   collection::const_iterator pos, end = m_locations.end();
189061da546Spatrick   for (pos = m_locations.begin(); pos != end; ++pos) {
190061da546Spatrick     if ((*pos)->IsResolved())
191061da546Spatrick       ++resolve_count;
192061da546Spatrick   }
193061da546Spatrick   return resolve_count;
194061da546Spatrick }
195061da546Spatrick 
GetDescription(Stream * s,lldb::DescriptionLevel level)196061da546Spatrick void BreakpointLocationList::GetDescription(Stream *s,
197061da546Spatrick                                             lldb::DescriptionLevel level) {
198061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
199061da546Spatrick   collection::iterator pos, end = m_locations.end();
200061da546Spatrick 
201061da546Spatrick   for (pos = m_locations.begin(); pos != end; ++pos) {
202061da546Spatrick     s->Printf(" ");
203061da546Spatrick     (*pos)->GetDescription(s, level);
204061da546Spatrick   }
205061da546Spatrick }
206061da546Spatrick 
AddLocation(const Address & addr,bool resolve_indirect_symbols,bool * new_location)207061da546Spatrick BreakpointLocationSP BreakpointLocationList::AddLocation(
208061da546Spatrick     const Address &addr, bool resolve_indirect_symbols, bool *new_location) {
209061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
210061da546Spatrick 
211061da546Spatrick   if (new_location)
212061da546Spatrick     *new_location = false;
213061da546Spatrick   BreakpointLocationSP bp_loc_sp(FindByAddress(addr));
214061da546Spatrick   if (!bp_loc_sp) {
215061da546Spatrick     bp_loc_sp = Create(addr, resolve_indirect_symbols);
216061da546Spatrick     if (bp_loc_sp) {
217061da546Spatrick       bp_loc_sp->ResolveBreakpointSite();
218061da546Spatrick 
219061da546Spatrick       if (new_location)
220061da546Spatrick         *new_location = true;
221061da546Spatrick       if (m_new_location_recorder) {
222061da546Spatrick         m_new_location_recorder->Add(bp_loc_sp);
223061da546Spatrick       }
224061da546Spatrick     }
225061da546Spatrick   }
226061da546Spatrick   return bp_loc_sp;
227061da546Spatrick }
228061da546Spatrick 
SwapLocation(BreakpointLocationSP to_location_sp,BreakpointLocationSP from_location_sp)229061da546Spatrick void BreakpointLocationList::SwapLocation(
230061da546Spatrick     BreakpointLocationSP to_location_sp,
231061da546Spatrick     BreakpointLocationSP from_location_sp) {
232061da546Spatrick   if (!from_location_sp || !to_location_sp)
233061da546Spatrick     return;
234061da546Spatrick 
235061da546Spatrick   m_address_to_location.erase(to_location_sp->GetAddress());
236061da546Spatrick   to_location_sp->SwapLocation(from_location_sp);
237061da546Spatrick   RemoveLocation(from_location_sp);
238061da546Spatrick   m_address_to_location[to_location_sp->GetAddress()] = to_location_sp;
239061da546Spatrick   to_location_sp->ResolveBreakpointSite();
240061da546Spatrick }
241061da546Spatrick 
RemoveLocation(const lldb::BreakpointLocationSP & bp_loc_sp)242061da546Spatrick bool BreakpointLocationList::RemoveLocation(
243061da546Spatrick     const lldb::BreakpointLocationSP &bp_loc_sp) {
244061da546Spatrick   if (bp_loc_sp) {
245061da546Spatrick     std::lock_guard<std::recursive_mutex> guard(m_mutex);
246061da546Spatrick 
247061da546Spatrick     m_address_to_location.erase(bp_loc_sp->GetAddress());
248061da546Spatrick 
249061da546Spatrick     size_t num_locations = m_locations.size();
250061da546Spatrick     for (size_t idx = 0; idx < num_locations; idx++) {
251061da546Spatrick       if (m_locations[idx].get() == bp_loc_sp.get()) {
252061da546Spatrick         RemoveLocationByIndex(idx);
253061da546Spatrick         return true;
254061da546Spatrick       }
255061da546Spatrick     }
256061da546Spatrick   }
257061da546Spatrick   return false;
258061da546Spatrick }
259061da546Spatrick 
RemoveLocationByIndex(size_t idx)260061da546Spatrick void BreakpointLocationList::RemoveLocationByIndex(size_t idx) {
261061da546Spatrick   assert (idx < m_locations.size());
262061da546Spatrick   m_address_to_location.erase(m_locations[idx]->GetAddress());
263061da546Spatrick   m_locations.erase(m_locations.begin() + idx);
264061da546Spatrick }
265061da546Spatrick 
RemoveInvalidLocations(const ArchSpec & arch)266061da546Spatrick void BreakpointLocationList::RemoveInvalidLocations(const ArchSpec &arch) {
267061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
268061da546Spatrick   size_t idx = 0;
269061da546Spatrick   // Don't cache m_location.size() as it will change since we might remove
270061da546Spatrick   // locations from our vector...
271061da546Spatrick   while (idx < m_locations.size()) {
272061da546Spatrick     BreakpointLocation *bp_loc = m_locations[idx].get();
273061da546Spatrick     if (bp_loc->GetAddress().SectionWasDeleted()) {
274061da546Spatrick       // Section was deleted which means this breakpoint comes from a module
275061da546Spatrick       // that is no longer valid, so we should remove it.
276061da546Spatrick       RemoveLocationByIndex(idx);
277061da546Spatrick       continue;
278061da546Spatrick     }
279061da546Spatrick     if (arch.IsValid()) {
280061da546Spatrick       ModuleSP module_sp(bp_loc->GetAddress().GetModule());
281061da546Spatrick       if (module_sp) {
282061da546Spatrick         if (!arch.IsCompatibleMatch(module_sp->GetArchitecture())) {
283061da546Spatrick           // The breakpoint was in a module whose architecture is no longer
284061da546Spatrick           // compatible with "arch", so we need to remove it
285061da546Spatrick           RemoveLocationByIndex(idx);
286061da546Spatrick           continue;
287061da546Spatrick         }
288061da546Spatrick       }
289061da546Spatrick     }
290061da546Spatrick     // Only increment the index if we didn't remove the locations at index
291061da546Spatrick     // "idx"
292061da546Spatrick     ++idx;
293061da546Spatrick   }
294061da546Spatrick }
295061da546Spatrick 
StartRecordingNewLocations(BreakpointLocationCollection & new_locations)296061da546Spatrick void BreakpointLocationList::StartRecordingNewLocations(
297061da546Spatrick     BreakpointLocationCollection &new_locations) {
298061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
299061da546Spatrick   assert(m_new_location_recorder == nullptr);
300061da546Spatrick   m_new_location_recorder = &new_locations;
301061da546Spatrick }
302061da546Spatrick 
StopRecordingNewLocations()303061da546Spatrick void BreakpointLocationList::StopRecordingNewLocations() {
304061da546Spatrick   std::lock_guard<std::recursive_mutex> guard(m_mutex);
305061da546Spatrick   m_new_location_recorder = nullptr;
306061da546Spatrick }
307061da546Spatrick 
Compact()308061da546Spatrick void BreakpointLocationList::Compact() {
309061da546Spatrick   lldb::break_id_t highest_id = 0;
310061da546Spatrick 
311061da546Spatrick   for (BreakpointLocationSP loc_sp : m_locations) {
312061da546Spatrick     lldb::break_id_t cur_id = loc_sp->GetID();
313061da546Spatrick     if (cur_id > highest_id)
314061da546Spatrick       highest_id = cur_id;
315061da546Spatrick   }
316061da546Spatrick   m_next_id = highest_id;
317061da546Spatrick }
318