1 //===-- BreakpointLocationList.cpp ----------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Breakpoint/BreakpointLocationList.h"
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"
20 using namespace lldb_private
;
22 BreakpointLocationList::BreakpointLocationList(Breakpoint
&owner
)
23 : m_owner(owner
), m_next_id(0), m_new_location_recorder(nullptr) {}
25 BreakpointLocationList::~BreakpointLocationList() = default;
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
;
41 bool BreakpointLocationList::ShouldStop(StoppointCallbackContext
*context
,
42 lldb::break_id_t break_id
) {
43 BreakpointLocationSP bp
= FindByID(break_id
);
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
);
50 // We should stop here since this BreakpointLocation isn't valid anymore or
55 lldb::break_id_t
BreakpointLocationList::FindIDByAddress(const Address
&addr
) {
56 BreakpointLocationSP bp_loc_sp
= FindByAddress(addr
);
58 return bp_loc_sp
->GetID();
60 return LLDB_INVALID_BREAK_ID
;
63 static bool Compare(BreakpointLocationSP lhs
, lldb::break_id_t val
) {
64 return lhs
->GetID() < val
;
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
)
76 return BreakpointLocationSP();
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();
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
);
92 return bp_loc_list
.GetSize() - orig_size
;
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()) {
102 if (addr
.IsSectionOffset()) {
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.
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
;
122 void BreakpointLocationList::Dump(Stream
*s
) const {
123 s
->Printf("%p: ", static_cast<const void *>(this));
125 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
126 s
->Printf("BreakpointLocationList with %" PRIu64
" BreakpointLocations:\n",
127 (uint64_t)m_locations
.size());
129 collection::const_iterator pos
, end
= m_locations
.end();
130 for (pos
= m_locations
.begin(); pos
!= end
; ++pos
)
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
];
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
];
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();
160 void BreakpointLocationList::ResolveAllBreakpointSites() {
161 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
162 collection::iterator pos
, end
= m_locations
.end();
164 for (pos
= m_locations
.begin(); pos
!= end
; ++pos
) {
165 if ((*pos
)->IsEnabled())
166 (*pos
)->ResolveBreakpointSite();
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();
179 void BreakpointLocationList::ResetHitCount() {
180 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
181 for (auto &loc
: m_locations
)
182 loc
->ResetHitCount();
185 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())
193 return resolve_count
;
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();
201 for (pos
= m_locations
.begin(); pos
!= end
; ++pos
) {
203 (*pos
)->GetDescription(s
, level
);
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
);
212 *new_location
= false;
213 BreakpointLocationSP
bp_loc_sp(FindByAddress(addr
));
215 bp_loc_sp
= Create(addr
, resolve_indirect_symbols
);
217 bp_loc_sp
->ResolveBreakpointSite();
220 *new_location
= true;
221 if (m_new_location_recorder
) {
222 m_new_location_recorder
->Add(bp_loc_sp
);
229 void BreakpointLocationList::SwapLocation(
230 BreakpointLocationSP to_location_sp
,
231 BreakpointLocationSP from_location_sp
) {
232 if (!from_location_sp
|| !to_location_sp
)
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();
242 bool BreakpointLocationList::RemoveLocation(
243 const lldb::BreakpointLocationSP
&bp_loc_sp
) {
245 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
247 m_address_to_location
.erase(bp_loc_sp
->GetAddress());
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
);
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
);
266 void BreakpointLocationList::RemoveInvalidLocations(const ArchSpec
&arch
) {
267 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
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
);
279 if (arch
.IsValid()) {
280 ModuleSP
module_sp(bp_loc
->GetAddress().GetModule());
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
);
290 // Only increment the index if we didn't remove the locations at index
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
;
303 void BreakpointLocationList::StopRecordingNewLocations() {
304 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
305 m_new_location_recorder
= nullptr;
308 void BreakpointLocationList::Compact() {
309 lldb::break_id_t highest_id
= 0;
311 for (BreakpointLocationSP loc_sp
: m_locations
) {
312 lldb::break_id_t cur_id
= loc_sp
->GetID();
313 if (cur_id
> highest_id
)
316 m_next_id
= highest_id
;