1dda28197Spatrick //===-- WatchpointList.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/WatchpointList.h"
10061da546Spatrick #include "lldb/Breakpoint/Watchpoint.h"
11061da546Spatrick
12061da546Spatrick using namespace lldb;
13061da546Spatrick using namespace lldb_private;
14061da546Spatrick
15*f6aab3d8Srobert WatchpointList::WatchpointList() = default;
16061da546Spatrick
17be691f3bSpatrick WatchpointList::~WatchpointList() = default;
18061da546Spatrick
19061da546Spatrick // Add a watchpoint to the list.
Add(const WatchpointSP & wp_sp,bool notify)20061da546Spatrick lldb::watch_id_t WatchpointList::Add(const WatchpointSP &wp_sp, bool notify) {
21061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_mutex);
22061da546Spatrick wp_sp->SetID(++m_next_wp_id);
23061da546Spatrick m_watchpoints.push_back(wp_sp);
24061da546Spatrick if (notify) {
25061da546Spatrick if (wp_sp->GetTarget().EventTypeHasListeners(
26061da546Spatrick Target::eBroadcastBitWatchpointChanged))
27061da546Spatrick wp_sp->GetTarget().BroadcastEvent(Target::eBroadcastBitWatchpointChanged,
28061da546Spatrick new Watchpoint::WatchpointEventData(
29061da546Spatrick eWatchpointEventTypeAdded, wp_sp));
30061da546Spatrick }
31061da546Spatrick return wp_sp->GetID();
32061da546Spatrick }
33061da546Spatrick
Dump(Stream * s) const34061da546Spatrick void WatchpointList::Dump(Stream *s) const {
35061da546Spatrick DumpWithLevel(s, lldb::eDescriptionLevelBrief);
36061da546Spatrick }
37061da546Spatrick
DumpWithLevel(Stream * s,lldb::DescriptionLevel description_level) const38061da546Spatrick void WatchpointList::DumpWithLevel(
39061da546Spatrick Stream *s, lldb::DescriptionLevel description_level) const {
40061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_mutex);
41061da546Spatrick s->Printf("%p: ", static_cast<const void *>(this));
42061da546Spatrick // s->Indent();
43061da546Spatrick s->Printf("WatchpointList with %" PRIu64 " Watchpoints:\n",
44061da546Spatrick (uint64_t)m_watchpoints.size());
45061da546Spatrick s->IndentMore();
46061da546Spatrick wp_collection::const_iterator pos, end = m_watchpoints.end();
47061da546Spatrick for (pos = m_watchpoints.begin(); pos != end; ++pos)
48061da546Spatrick (*pos)->DumpWithLevel(s, description_level);
49061da546Spatrick s->IndentLess();
50061da546Spatrick }
51061da546Spatrick
FindByAddress(lldb::addr_t addr) const52061da546Spatrick const WatchpointSP WatchpointList::FindByAddress(lldb::addr_t addr) const {
53061da546Spatrick WatchpointSP wp_sp;
54061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_mutex);
55061da546Spatrick if (!m_watchpoints.empty()) {
56061da546Spatrick wp_collection::const_iterator pos, end = m_watchpoints.end();
57061da546Spatrick for (pos = m_watchpoints.begin(); pos != end; ++pos) {
58061da546Spatrick lldb::addr_t wp_addr = (*pos)->GetLoadAddress();
59061da546Spatrick uint32_t wp_bytesize = (*pos)->GetByteSize();
60061da546Spatrick if ((wp_addr <= addr) && ((wp_addr + wp_bytesize) > addr)) {
61061da546Spatrick wp_sp = *pos;
62061da546Spatrick break;
63061da546Spatrick }
64061da546Spatrick }
65061da546Spatrick }
66061da546Spatrick
67061da546Spatrick return wp_sp;
68061da546Spatrick }
69061da546Spatrick
FindBySpec(std::string spec) const70061da546Spatrick const WatchpointSP WatchpointList::FindBySpec(std::string spec) const {
71061da546Spatrick WatchpointSP wp_sp;
72061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_mutex);
73061da546Spatrick if (!m_watchpoints.empty()) {
74061da546Spatrick wp_collection::const_iterator pos, end = m_watchpoints.end();
75061da546Spatrick for (pos = m_watchpoints.begin(); pos != end; ++pos)
76061da546Spatrick if ((*pos)->GetWatchSpec() == spec) {
77061da546Spatrick wp_sp = *pos;
78061da546Spatrick break;
79061da546Spatrick }
80061da546Spatrick }
81061da546Spatrick
82061da546Spatrick return wp_sp;
83061da546Spatrick }
84061da546Spatrick
85061da546Spatrick class WatchpointIDMatches {
86061da546Spatrick public:
WatchpointIDMatches(lldb::watch_id_t watch_id)87061da546Spatrick WatchpointIDMatches(lldb::watch_id_t watch_id) : m_watch_id(watch_id) {}
88061da546Spatrick
operator ()(const WatchpointSP & wp) const89061da546Spatrick bool operator()(const WatchpointSP &wp) const {
90061da546Spatrick return m_watch_id == wp->GetID();
91061da546Spatrick }
92061da546Spatrick
93061da546Spatrick private:
94061da546Spatrick const lldb::watch_id_t m_watch_id;
95061da546Spatrick };
96061da546Spatrick
97061da546Spatrick WatchpointList::wp_collection::iterator
GetIDIterator(lldb::watch_id_t watch_id)98061da546Spatrick WatchpointList::GetIDIterator(lldb::watch_id_t watch_id) {
99061da546Spatrick return std::find_if(m_watchpoints.begin(),
100061da546Spatrick m_watchpoints.end(), // Search full range
101061da546Spatrick WatchpointIDMatches(watch_id)); // Predicate
102061da546Spatrick }
103061da546Spatrick
104061da546Spatrick WatchpointList::wp_collection::const_iterator
GetIDConstIterator(lldb::watch_id_t watch_id) const105061da546Spatrick WatchpointList::GetIDConstIterator(lldb::watch_id_t watch_id) const {
106061da546Spatrick return std::find_if(m_watchpoints.begin(),
107061da546Spatrick m_watchpoints.end(), // Search full range
108061da546Spatrick WatchpointIDMatches(watch_id)); // Predicate
109061da546Spatrick }
110061da546Spatrick
FindByID(lldb::watch_id_t watch_id) const111061da546Spatrick WatchpointSP WatchpointList::FindByID(lldb::watch_id_t watch_id) const {
112061da546Spatrick WatchpointSP wp_sp;
113061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_mutex);
114061da546Spatrick wp_collection::const_iterator pos = GetIDConstIterator(watch_id);
115061da546Spatrick if (pos != m_watchpoints.end())
116061da546Spatrick wp_sp = *pos;
117061da546Spatrick
118061da546Spatrick return wp_sp;
119061da546Spatrick }
120061da546Spatrick
FindIDByAddress(lldb::addr_t addr)121061da546Spatrick lldb::watch_id_t WatchpointList::FindIDByAddress(lldb::addr_t addr) {
122061da546Spatrick WatchpointSP wp_sp = FindByAddress(addr);
123061da546Spatrick if (wp_sp) {
124061da546Spatrick return wp_sp->GetID();
125061da546Spatrick }
126061da546Spatrick return LLDB_INVALID_WATCH_ID;
127061da546Spatrick }
128061da546Spatrick
FindIDBySpec(std::string spec)129061da546Spatrick lldb::watch_id_t WatchpointList::FindIDBySpec(std::string spec) {
130061da546Spatrick WatchpointSP wp_sp = FindBySpec(spec);
131061da546Spatrick if (wp_sp) {
132061da546Spatrick return wp_sp->GetID();
133061da546Spatrick }
134061da546Spatrick return LLDB_INVALID_WATCH_ID;
135061da546Spatrick }
136061da546Spatrick
GetByIndex(uint32_t i)137061da546Spatrick WatchpointSP WatchpointList::GetByIndex(uint32_t i) {
138061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_mutex);
139061da546Spatrick WatchpointSP wp_sp;
140061da546Spatrick if (i < m_watchpoints.size()) {
141061da546Spatrick wp_collection::const_iterator pos = m_watchpoints.begin();
142061da546Spatrick std::advance(pos, i);
143061da546Spatrick wp_sp = *pos;
144061da546Spatrick }
145061da546Spatrick return wp_sp;
146061da546Spatrick }
147061da546Spatrick
GetByIndex(uint32_t i) const148061da546Spatrick const WatchpointSP WatchpointList::GetByIndex(uint32_t i) const {
149061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_mutex);
150061da546Spatrick WatchpointSP wp_sp;
151061da546Spatrick if (i < m_watchpoints.size()) {
152061da546Spatrick wp_collection::const_iterator pos = m_watchpoints.begin();
153061da546Spatrick std::advance(pos, i);
154061da546Spatrick wp_sp = *pos;
155061da546Spatrick }
156061da546Spatrick return wp_sp;
157061da546Spatrick }
158061da546Spatrick
GetWatchpointIDs() const159061da546Spatrick std::vector<lldb::watch_id_t> WatchpointList::GetWatchpointIDs() const {
160061da546Spatrick std::vector<lldb::watch_id_t> IDs;
161061da546Spatrick wp_collection::const_iterator pos, end = m_watchpoints.end();
162061da546Spatrick for (pos = m_watchpoints.begin(); pos != end; ++pos)
163061da546Spatrick IDs.push_back((*pos)->GetID());
164061da546Spatrick return IDs;
165061da546Spatrick }
166061da546Spatrick
Remove(lldb::watch_id_t watch_id,bool notify)167061da546Spatrick bool WatchpointList::Remove(lldb::watch_id_t watch_id, bool notify) {
168061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_mutex);
169061da546Spatrick wp_collection::iterator pos = GetIDIterator(watch_id);
170061da546Spatrick if (pos != m_watchpoints.end()) {
171061da546Spatrick WatchpointSP wp_sp = *pos;
172061da546Spatrick if (notify) {
173061da546Spatrick if (wp_sp->GetTarget().EventTypeHasListeners(
174061da546Spatrick Target::eBroadcastBitWatchpointChanged))
175061da546Spatrick wp_sp->GetTarget().BroadcastEvent(
176061da546Spatrick Target::eBroadcastBitWatchpointChanged,
177061da546Spatrick new Watchpoint::WatchpointEventData(eWatchpointEventTypeRemoved,
178061da546Spatrick wp_sp));
179061da546Spatrick }
180061da546Spatrick m_watchpoints.erase(pos);
181061da546Spatrick return true;
182061da546Spatrick }
183061da546Spatrick return false;
184061da546Spatrick }
185061da546Spatrick
GetHitCount() const186061da546Spatrick uint32_t WatchpointList::GetHitCount() const {
187061da546Spatrick uint32_t hit_count = 0;
188061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_mutex);
189061da546Spatrick wp_collection::const_iterator pos, end = m_watchpoints.end();
190061da546Spatrick for (pos = m_watchpoints.begin(); pos != end; ++pos)
191061da546Spatrick hit_count += (*pos)->GetHitCount();
192061da546Spatrick return hit_count;
193061da546Spatrick }
194061da546Spatrick
ShouldStop(StoppointCallbackContext * context,lldb::watch_id_t watch_id)195061da546Spatrick bool WatchpointList::ShouldStop(StoppointCallbackContext *context,
196061da546Spatrick lldb::watch_id_t watch_id) {
197061da546Spatrick
198061da546Spatrick WatchpointSP wp_sp = FindByID(watch_id);
199061da546Spatrick if (wp_sp) {
200061da546Spatrick // Let the Watchpoint decide if it should stop here (could not have reached
201061da546Spatrick // it's target hit count yet, or it could have a callback that decided it
202061da546Spatrick // shouldn't stop.
203061da546Spatrick return wp_sp->ShouldStop(context);
204061da546Spatrick }
205061da546Spatrick // We should stop here since this Watchpoint isn't valid anymore or it
206061da546Spatrick // doesn't exist.
207061da546Spatrick return true;
208061da546Spatrick }
209061da546Spatrick
GetDescription(Stream * s,lldb::DescriptionLevel level)210061da546Spatrick void WatchpointList::GetDescription(Stream *s, lldb::DescriptionLevel level) {
211061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_mutex);
212061da546Spatrick wp_collection::iterator pos, end = m_watchpoints.end();
213061da546Spatrick
214061da546Spatrick for (pos = m_watchpoints.begin(); pos != end; ++pos) {
215061da546Spatrick s->Printf(" ");
216061da546Spatrick (*pos)->Dump(s);
217061da546Spatrick }
218061da546Spatrick }
219061da546Spatrick
SetEnabledAll(bool enabled)220061da546Spatrick void WatchpointList::SetEnabledAll(bool enabled) {
221061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_mutex);
222061da546Spatrick
223061da546Spatrick wp_collection::iterator pos, end = m_watchpoints.end();
224061da546Spatrick for (pos = m_watchpoints.begin(); pos != end; ++pos)
225061da546Spatrick (*pos)->SetEnabled(enabled);
226061da546Spatrick }
227061da546Spatrick
RemoveAll(bool notify)228061da546Spatrick void WatchpointList::RemoveAll(bool notify) {
229061da546Spatrick std::lock_guard<std::recursive_mutex> guard(m_mutex);
230061da546Spatrick if (notify) {
231061da546Spatrick
232061da546Spatrick {
233061da546Spatrick wp_collection::iterator pos, end = m_watchpoints.end();
234061da546Spatrick for (pos = m_watchpoints.begin(); pos != end; ++pos) {
235061da546Spatrick if ((*pos)->GetTarget().EventTypeHasListeners(
236061da546Spatrick Target::eBroadcastBitBreakpointChanged)) {
237061da546Spatrick (*pos)->GetTarget().BroadcastEvent(
238061da546Spatrick Target::eBroadcastBitWatchpointChanged,
239061da546Spatrick new Watchpoint::WatchpointEventData(eWatchpointEventTypeRemoved,
240061da546Spatrick *pos));
241061da546Spatrick }
242061da546Spatrick }
243061da546Spatrick }
244061da546Spatrick }
245061da546Spatrick m_watchpoints.clear();
246061da546Spatrick }
247061da546Spatrick
GetListMutex(std::unique_lock<std::recursive_mutex> & lock)248061da546Spatrick void WatchpointList::GetListMutex(
249061da546Spatrick std::unique_lock<std::recursive_mutex> &lock) {
250061da546Spatrick lock = std::unique_lock<std::recursive_mutex>(m_mutex);
251061da546Spatrick }
252