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