1 //===-- WatchpointList.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/WatchpointList.h"
10 #include "lldb/Breakpoint/Watchpoint.h"
13 using namespace lldb_private
;
15 WatchpointList::WatchpointList() = default;
17 WatchpointList::~WatchpointList() = default;
19 // Add a watchpoint to the list.
20 lldb::watch_id_t
WatchpointList::Add(const WatchpointSP
&wp_sp
, bool notify
) {
21 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
22 wp_sp
->SetID(++m_next_wp_id
);
23 m_watchpoints
.push_back(wp_sp
);
25 if (wp_sp
->GetTarget().EventTypeHasListeners(
26 Target::eBroadcastBitWatchpointChanged
))
27 wp_sp
->GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged
,
28 new Watchpoint::WatchpointEventData(
29 eWatchpointEventTypeAdded
, wp_sp
));
31 return wp_sp
->GetID();
34 void WatchpointList::Dump(Stream
*s
) const {
35 DumpWithLevel(s
, lldb::eDescriptionLevelBrief
);
38 void WatchpointList::DumpWithLevel(
39 Stream
*s
, lldb::DescriptionLevel description_level
) const {
40 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
41 s
->Printf("%p: ", static_cast<const void *>(this));
43 s
->Printf("WatchpointList with %" PRIu64
" Watchpoints:\n",
44 (uint64_t)m_watchpoints
.size());
46 wp_collection::const_iterator pos
, end
= m_watchpoints
.end();
47 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
)
48 (*pos
)->DumpWithLevel(s
, description_level
);
52 const WatchpointSP
WatchpointList::FindByAddress(lldb::addr_t addr
) const {
54 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
55 if (!m_watchpoints
.empty()) {
56 wp_collection::const_iterator pos
, end
= m_watchpoints
.end();
57 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
) {
58 lldb::addr_t wp_addr
= (*pos
)->GetLoadAddress();
59 uint32_t wp_bytesize
= (*pos
)->GetByteSize();
60 if ((wp_addr
<= addr
) && ((wp_addr
+ wp_bytesize
) > addr
)) {
70 const WatchpointSP
WatchpointList::FindBySpec(std::string spec
) const {
72 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
73 if (!m_watchpoints
.empty()) {
74 wp_collection::const_iterator pos
, end
= m_watchpoints
.end();
75 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
)
76 if ((*pos
)->GetWatchSpec() == spec
) {
85 class WatchpointIDMatches
{
87 WatchpointIDMatches(lldb::watch_id_t watch_id
) : m_watch_id(watch_id
) {}
89 bool operator()(const WatchpointSP
&wp
) const {
90 return m_watch_id
== wp
->GetID();
94 const lldb::watch_id_t m_watch_id
;
97 WatchpointList::wp_collection::iterator
98 WatchpointList::GetIDIterator(lldb::watch_id_t watch_id
) {
99 return std::find_if(m_watchpoints
.begin(),
100 m_watchpoints
.end(), // Search full range
101 WatchpointIDMatches(watch_id
)); // Predicate
104 WatchpointList::wp_collection::const_iterator
105 WatchpointList::GetIDConstIterator(lldb::watch_id_t watch_id
) const {
106 return std::find_if(m_watchpoints
.begin(),
107 m_watchpoints
.end(), // Search full range
108 WatchpointIDMatches(watch_id
)); // Predicate
111 WatchpointSP
WatchpointList::FindByID(lldb::watch_id_t watch_id
) const {
113 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
114 wp_collection::const_iterator pos
= GetIDConstIterator(watch_id
);
115 if (pos
!= m_watchpoints
.end())
121 lldb::watch_id_t
WatchpointList::FindIDByAddress(lldb::addr_t addr
) {
122 WatchpointSP wp_sp
= FindByAddress(addr
);
124 return wp_sp
->GetID();
126 return LLDB_INVALID_WATCH_ID
;
129 lldb::watch_id_t
WatchpointList::FindIDBySpec(std::string spec
) {
130 WatchpointSP wp_sp
= FindBySpec(spec
);
132 return wp_sp
->GetID();
134 return LLDB_INVALID_WATCH_ID
;
137 WatchpointSP
WatchpointList::GetByIndex(uint32_t i
) {
138 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
140 if (i
< m_watchpoints
.size()) {
141 wp_collection::const_iterator pos
= m_watchpoints
.begin();
142 std::advance(pos
, i
);
148 const WatchpointSP
WatchpointList::GetByIndex(uint32_t i
) const {
149 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
151 if (i
< m_watchpoints
.size()) {
152 wp_collection::const_iterator pos
= m_watchpoints
.begin();
153 std::advance(pos
, i
);
159 std::vector
<lldb::watch_id_t
> WatchpointList::GetWatchpointIDs() const {
160 std::vector
<lldb::watch_id_t
> IDs
;
161 wp_collection::const_iterator pos
, end
= m_watchpoints
.end();
162 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
)
163 IDs
.push_back((*pos
)->GetID());
167 bool WatchpointList::Remove(lldb::watch_id_t watch_id
, bool notify
) {
168 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
169 wp_collection::iterator pos
= GetIDIterator(watch_id
);
170 if (pos
!= m_watchpoints
.end()) {
171 WatchpointSP wp_sp
= *pos
;
173 if (wp_sp
->GetTarget().EventTypeHasListeners(
174 Target::eBroadcastBitWatchpointChanged
))
175 wp_sp
->GetTarget().BroadcastEvent(
176 Target::eBroadcastBitWatchpointChanged
,
177 new Watchpoint::WatchpointEventData(eWatchpointEventTypeRemoved
,
180 m_watchpoints
.erase(pos
);
186 uint32_t WatchpointList::GetHitCount() const {
187 uint32_t hit_count
= 0;
188 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
189 wp_collection::const_iterator pos
, end
= m_watchpoints
.end();
190 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
)
191 hit_count
+= (*pos
)->GetHitCount();
195 bool WatchpointList::ShouldStop(StoppointCallbackContext
*context
,
196 lldb::watch_id_t watch_id
) {
198 WatchpointSP wp_sp
= FindByID(watch_id
);
200 // Let the Watchpoint decide if it should stop here (could not have reached
201 // it's target hit count yet, or it could have a callback that decided it
203 return wp_sp
->ShouldStop(context
);
205 // We should stop here since this Watchpoint isn't valid anymore or it
210 void WatchpointList::GetDescription(Stream
*s
, lldb::DescriptionLevel level
) {
211 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
212 wp_collection::iterator pos
, end
= m_watchpoints
.end();
214 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
) {
220 void WatchpointList::SetEnabledAll(bool enabled
) {
221 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
223 wp_collection::iterator pos
, end
= m_watchpoints
.end();
224 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
)
225 (*pos
)->SetEnabled(enabled
);
228 void WatchpointList::RemoveAll(bool notify
) {
229 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
233 wp_collection::iterator pos
, end
= m_watchpoints
.end();
234 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
) {
235 if ((*pos
)->GetTarget().EventTypeHasListeners(
236 Target::eBroadcastBitBreakpointChanged
)) {
237 (*pos
)->GetTarget().BroadcastEvent(
238 Target::eBroadcastBitWatchpointChanged
,
239 new Watchpoint::WatchpointEventData(eWatchpointEventTypeRemoved
,
245 m_watchpoints
.clear();
248 void WatchpointList::GetListMutex(
249 std::unique_lock
<std::recursive_mutex
> &lock
) {
250 lock
= std::unique_lock
<std::recursive_mutex
>(m_mutex
);