xref: /openbsd-src/gnu/llvm/lldb/source/Breakpoint/WatchpointList.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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