1 //===-- WatchpointList.cpp --------------------------------------*- C++ -*-===//
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()
16 : m_watchpoints(), m_mutex(), m_next_wp_id(0) {}
18 WatchpointList::~WatchpointList() {}
20 // Add a watchpoint to the list.
21 lldb::watch_id_t
WatchpointList::Add(const WatchpointSP
&wp_sp
, bool notify
) {
22 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
23 wp_sp
->SetID(++m_next_wp_id
);
24 m_watchpoints
.push_back(wp_sp
);
26 if (wp_sp
->GetTarget().EventTypeHasListeners(
27 Target::eBroadcastBitWatchpointChanged
))
28 wp_sp
->GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged
,
29 new Watchpoint::WatchpointEventData(
30 eWatchpointEventTypeAdded
, wp_sp
));
32 return wp_sp
->GetID();
35 void WatchpointList::Dump(Stream
*s
) const {
36 DumpWithLevel(s
, lldb::eDescriptionLevelBrief
);
39 void WatchpointList::DumpWithLevel(
40 Stream
*s
, lldb::DescriptionLevel description_level
) const {
41 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
42 s
->Printf("%p: ", static_cast<const void *>(this));
44 s
->Printf("WatchpointList with %" PRIu64
" Watchpoints:\n",
45 (uint64_t)m_watchpoints
.size());
47 wp_collection::const_iterator pos
, end
= m_watchpoints
.end();
48 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
)
49 (*pos
)->DumpWithLevel(s
, description_level
);
53 const WatchpointSP
WatchpointList::FindByAddress(lldb::addr_t addr
) const {
55 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
56 if (!m_watchpoints
.empty()) {
57 wp_collection::const_iterator pos
, end
= m_watchpoints
.end();
58 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
) {
59 lldb::addr_t wp_addr
= (*pos
)->GetLoadAddress();
60 uint32_t wp_bytesize
= (*pos
)->GetByteSize();
61 if ((wp_addr
<= addr
) && ((wp_addr
+ wp_bytesize
) > addr
)) {
71 const WatchpointSP
WatchpointList::FindBySpec(std::string spec
) const {
73 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
74 if (!m_watchpoints
.empty()) {
75 wp_collection::const_iterator pos
, end
= m_watchpoints
.end();
76 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
)
77 if ((*pos
)->GetWatchSpec() == spec
) {
86 class WatchpointIDMatches
{
88 WatchpointIDMatches(lldb::watch_id_t watch_id
) : m_watch_id(watch_id
) {}
90 bool operator()(const WatchpointSP
&wp
) const {
91 return m_watch_id
== wp
->GetID();
95 const lldb::watch_id_t m_watch_id
;
98 WatchpointList::wp_collection::iterator
99 WatchpointList::GetIDIterator(lldb::watch_id_t watch_id
) {
100 return std::find_if(m_watchpoints
.begin(),
101 m_watchpoints
.end(), // Search full range
102 WatchpointIDMatches(watch_id
)); // Predicate
105 WatchpointList::wp_collection::const_iterator
106 WatchpointList::GetIDConstIterator(lldb::watch_id_t watch_id
) const {
107 return std::find_if(m_watchpoints
.begin(),
108 m_watchpoints
.end(), // Search full range
109 WatchpointIDMatches(watch_id
)); // Predicate
112 WatchpointSP
WatchpointList::FindByID(lldb::watch_id_t watch_id
) const {
114 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
115 wp_collection::const_iterator pos
= GetIDConstIterator(watch_id
);
116 if (pos
!= m_watchpoints
.end())
122 lldb::watch_id_t
WatchpointList::FindIDByAddress(lldb::addr_t addr
) {
123 WatchpointSP wp_sp
= FindByAddress(addr
);
125 return wp_sp
->GetID();
127 return LLDB_INVALID_WATCH_ID
;
130 lldb::watch_id_t
WatchpointList::FindIDBySpec(std::string spec
) {
131 WatchpointSP wp_sp
= FindBySpec(spec
);
133 return wp_sp
->GetID();
135 return LLDB_INVALID_WATCH_ID
;
138 WatchpointSP
WatchpointList::GetByIndex(uint32_t i
) {
139 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
141 if (i
< m_watchpoints
.size()) {
142 wp_collection::const_iterator pos
= m_watchpoints
.begin();
143 std::advance(pos
, i
);
149 const WatchpointSP
WatchpointList::GetByIndex(uint32_t i
) const {
150 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
152 if (i
< m_watchpoints
.size()) {
153 wp_collection::const_iterator pos
= m_watchpoints
.begin();
154 std::advance(pos
, i
);
160 std::vector
<lldb::watch_id_t
> WatchpointList::GetWatchpointIDs() const {
161 std::vector
<lldb::watch_id_t
> IDs
;
162 wp_collection::const_iterator pos
, end
= m_watchpoints
.end();
163 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
)
164 IDs
.push_back((*pos
)->GetID());
168 bool WatchpointList::Remove(lldb::watch_id_t watch_id
, bool notify
) {
169 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
170 wp_collection::iterator pos
= GetIDIterator(watch_id
);
171 if (pos
!= m_watchpoints
.end()) {
172 WatchpointSP wp_sp
= *pos
;
174 if (wp_sp
->GetTarget().EventTypeHasListeners(
175 Target::eBroadcastBitWatchpointChanged
))
176 wp_sp
->GetTarget().BroadcastEvent(
177 Target::eBroadcastBitWatchpointChanged
,
178 new Watchpoint::WatchpointEventData(eWatchpointEventTypeRemoved
,
181 m_watchpoints
.erase(pos
);
187 uint32_t WatchpointList::GetHitCount() const {
188 uint32_t hit_count
= 0;
189 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
190 wp_collection::const_iterator pos
, end
= m_watchpoints
.end();
191 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
)
192 hit_count
+= (*pos
)->GetHitCount();
196 bool WatchpointList::ShouldStop(StoppointCallbackContext
*context
,
197 lldb::watch_id_t watch_id
) {
199 WatchpointSP wp_sp
= FindByID(watch_id
);
201 // Let the Watchpoint decide if it should stop here (could not have reached
202 // it's target hit count yet, or it could have a callback that decided it
204 return wp_sp
->ShouldStop(context
);
206 // We should stop here since this Watchpoint isn't valid anymore or it
211 void WatchpointList::GetDescription(Stream
*s
, lldb::DescriptionLevel level
) {
212 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
213 wp_collection::iterator pos
, end
= m_watchpoints
.end();
215 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
) {
221 void WatchpointList::SetEnabledAll(bool enabled
) {
222 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
224 wp_collection::iterator pos
, end
= m_watchpoints
.end();
225 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
)
226 (*pos
)->SetEnabled(enabled
);
229 void WatchpointList::RemoveAll(bool notify
) {
230 std::lock_guard
<std::recursive_mutex
> guard(m_mutex
);
234 wp_collection::iterator pos
, end
= m_watchpoints
.end();
235 for (pos
= m_watchpoints
.begin(); pos
!= end
; ++pos
) {
236 if ((*pos
)->GetTarget().EventTypeHasListeners(
237 Target::eBroadcastBitBreakpointChanged
)) {
238 (*pos
)->GetTarget().BroadcastEvent(
239 Target::eBroadcastBitWatchpointChanged
,
240 new Watchpoint::WatchpointEventData(eWatchpointEventTypeRemoved
,
246 m_watchpoints
.clear();
249 void WatchpointList::GetListMutex(
250 std::unique_lock
<std::recursive_mutex
> &lock
) {
251 lock
= std::unique_lock
<std::recursive_mutex
>(m_mutex
);