1 //===-- SBWatchpoint.cpp --------------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "lldb/API/SBWatchpoint.h"
10 #include "lldb/API/SBAddress.h"
11 #include "lldb/API/SBDebugger.h"
12 #include "lldb/API/SBDefines.h"
13 #include "lldb/API/SBEvent.h"
14 #include "lldb/API/SBStream.h"
15 #include "lldb/Utility/Instrumentation.h"
16 
17 #include "lldb/Breakpoint/Watchpoint.h"
18 #include "lldb/Breakpoint/WatchpointList.h"
19 #include "lldb/Symbol/CompilerType.h"
20 #include "lldb/Target/Process.h"
21 #include "lldb/Target/Target.h"
22 #include "lldb/Utility/Stream.h"
23 #include "lldb/lldb-defines.h"
24 #include "lldb/lldb-types.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
SBWatchpoint()29 SBWatchpoint::SBWatchpoint() { LLDB_INSTRUMENT_VA(this); }
30 
SBWatchpoint(const lldb::WatchpointSP & wp_sp)31 SBWatchpoint::SBWatchpoint(const lldb::WatchpointSP &wp_sp)
32     : m_opaque_wp(wp_sp) {
33   LLDB_INSTRUMENT_VA(this, wp_sp);
34 }
35 
SBWatchpoint(const SBWatchpoint & rhs)36 SBWatchpoint::SBWatchpoint(const SBWatchpoint &rhs)
37     : m_opaque_wp(rhs.m_opaque_wp) {
38   LLDB_INSTRUMENT_VA(this, rhs);
39 }
40 
operator =(const SBWatchpoint & rhs)41 const SBWatchpoint &SBWatchpoint::operator=(const SBWatchpoint &rhs) {
42   LLDB_INSTRUMENT_VA(this, rhs);
43 
44   m_opaque_wp = rhs.m_opaque_wp;
45   return *this;
46 }
47 
48 SBWatchpoint::~SBWatchpoint() = default;
49 
GetID()50 watch_id_t SBWatchpoint::GetID() {
51   LLDB_INSTRUMENT_VA(this);
52 
53   watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
54   lldb::WatchpointSP watchpoint_sp(GetSP());
55   if (watchpoint_sp)
56     watch_id = watchpoint_sp->GetID();
57 
58   return watch_id;
59 }
60 
IsValid() const61 bool SBWatchpoint::IsValid() const {
62   LLDB_INSTRUMENT_VA(this);
63   return this->operator bool();
64 }
operator bool() const65 SBWatchpoint::operator bool() const {
66   LLDB_INSTRUMENT_VA(this);
67 
68   return bool(m_opaque_wp.lock());
69 }
70 
operator ==(const SBWatchpoint & rhs) const71 bool SBWatchpoint::operator==(const SBWatchpoint &rhs) const {
72   LLDB_INSTRUMENT_VA(this, rhs);
73 
74   return GetSP() == rhs.GetSP();
75 }
76 
operator !=(const SBWatchpoint & rhs) const77 bool SBWatchpoint::operator!=(const SBWatchpoint &rhs) const {
78   LLDB_INSTRUMENT_VA(this, rhs);
79 
80   return !(*this == rhs);
81 }
82 
GetError()83 SBError SBWatchpoint::GetError() {
84   LLDB_INSTRUMENT_VA(this);
85 
86   SBError sb_error;
87   lldb::WatchpointSP watchpoint_sp(GetSP());
88   if (watchpoint_sp) {
89     sb_error.SetError(watchpoint_sp->GetError());
90   }
91   return sb_error;
92 }
93 
GetHardwareIndex()94 int32_t SBWatchpoint::GetHardwareIndex() {
95   LLDB_INSTRUMENT_VA(this);
96 
97   // For processes using gdb remote protocol,
98   // we cannot determine the hardware breakpoint
99   // index reliably; providing possibly correct
100   // guesses is not useful to anyone.
101   return -1;
102 }
103 
GetWatchAddress()104 addr_t SBWatchpoint::GetWatchAddress() {
105   LLDB_INSTRUMENT_VA(this);
106 
107   addr_t ret_addr = LLDB_INVALID_ADDRESS;
108 
109   lldb::WatchpointSP watchpoint_sp(GetSP());
110   if (watchpoint_sp) {
111     std::lock_guard<std::recursive_mutex> guard(
112         watchpoint_sp->GetTarget().GetAPIMutex());
113     ret_addr = watchpoint_sp->GetLoadAddress();
114   }
115 
116   return ret_addr;
117 }
118 
GetWatchSize()119 size_t SBWatchpoint::GetWatchSize() {
120   LLDB_INSTRUMENT_VA(this);
121 
122   size_t watch_size = 0;
123 
124   lldb::WatchpointSP watchpoint_sp(GetSP());
125   if (watchpoint_sp) {
126     std::lock_guard<std::recursive_mutex> guard(
127         watchpoint_sp->GetTarget().GetAPIMutex());
128     watch_size = watchpoint_sp->GetByteSize();
129   }
130 
131   return watch_size;
132 }
133 
SetEnabled(bool enabled)134 void SBWatchpoint::SetEnabled(bool enabled) {
135   LLDB_INSTRUMENT_VA(this, enabled);
136 
137   lldb::WatchpointSP watchpoint_sp(GetSP());
138   if (watchpoint_sp) {
139     Target &target = watchpoint_sp->GetTarget();
140     std::lock_guard<std::recursive_mutex> guard(target.GetAPIMutex());
141     ProcessSP process_sp = target.GetProcessSP();
142     const bool notify = true;
143     if (process_sp) {
144       if (enabled)
145         process_sp->EnableWatchpoint(watchpoint_sp, notify);
146       else
147         process_sp->DisableWatchpoint(watchpoint_sp, notify);
148     } else {
149       watchpoint_sp->SetEnabled(enabled, notify);
150     }
151   }
152 }
153 
IsEnabled()154 bool SBWatchpoint::IsEnabled() {
155   LLDB_INSTRUMENT_VA(this);
156 
157   lldb::WatchpointSP watchpoint_sp(GetSP());
158   if (watchpoint_sp) {
159     std::lock_guard<std::recursive_mutex> guard(
160         watchpoint_sp->GetTarget().GetAPIMutex());
161     return watchpoint_sp->IsEnabled();
162   } else
163     return false;
164 }
165 
GetHitCount()166 uint32_t SBWatchpoint::GetHitCount() {
167   LLDB_INSTRUMENT_VA(this);
168 
169   uint32_t count = 0;
170   lldb::WatchpointSP watchpoint_sp(GetSP());
171   if (watchpoint_sp) {
172     std::lock_guard<std::recursive_mutex> guard(
173         watchpoint_sp->GetTarget().GetAPIMutex());
174     count = watchpoint_sp->GetHitCount();
175   }
176 
177   return count;
178 }
179 
GetIgnoreCount()180 uint32_t SBWatchpoint::GetIgnoreCount() {
181   LLDB_INSTRUMENT_VA(this);
182 
183   lldb::WatchpointSP watchpoint_sp(GetSP());
184   if (watchpoint_sp) {
185     std::lock_guard<std::recursive_mutex> guard(
186         watchpoint_sp->GetTarget().GetAPIMutex());
187     return watchpoint_sp->GetIgnoreCount();
188   } else
189     return 0;
190 }
191 
SetIgnoreCount(uint32_t n)192 void SBWatchpoint::SetIgnoreCount(uint32_t n) {
193   LLDB_INSTRUMENT_VA(this, n);
194 
195   lldb::WatchpointSP watchpoint_sp(GetSP());
196   if (watchpoint_sp) {
197     std::lock_guard<std::recursive_mutex> guard(
198         watchpoint_sp->GetTarget().GetAPIMutex());
199     watchpoint_sp->SetIgnoreCount(n);
200   }
201 }
202 
GetCondition()203 const char *SBWatchpoint::GetCondition() {
204   LLDB_INSTRUMENT_VA(this);
205 
206   lldb::WatchpointSP watchpoint_sp(GetSP());
207   if (!watchpoint_sp)
208     return nullptr;
209 
210   std::lock_guard<std::recursive_mutex> guard(
211       watchpoint_sp->GetTarget().GetAPIMutex());
212   return ConstString(watchpoint_sp->GetConditionText()).GetCString();
213 }
214 
SetCondition(const char * condition)215 void SBWatchpoint::SetCondition(const char *condition) {
216   LLDB_INSTRUMENT_VA(this, condition);
217 
218   lldb::WatchpointSP watchpoint_sp(GetSP());
219   if (watchpoint_sp) {
220     std::lock_guard<std::recursive_mutex> guard(
221         watchpoint_sp->GetTarget().GetAPIMutex());
222     watchpoint_sp->SetCondition(condition);
223   }
224 }
225 
GetDescription(SBStream & description,DescriptionLevel level)226 bool SBWatchpoint::GetDescription(SBStream &description,
227                                   DescriptionLevel level) {
228   LLDB_INSTRUMENT_VA(this, description, level);
229 
230   Stream &strm = description.ref();
231 
232   lldb::WatchpointSP watchpoint_sp(GetSP());
233   if (watchpoint_sp) {
234     std::lock_guard<std::recursive_mutex> guard(
235         watchpoint_sp->GetTarget().GetAPIMutex());
236     watchpoint_sp->GetDescription(&strm, level);
237     strm.EOL();
238   } else
239     strm.PutCString("No value");
240 
241   return true;
242 }
243 
Clear()244 void SBWatchpoint::Clear() {
245   LLDB_INSTRUMENT_VA(this);
246 
247   m_opaque_wp.reset();
248 }
249 
GetSP() const250 lldb::WatchpointSP SBWatchpoint::GetSP() const {
251   LLDB_INSTRUMENT_VA(this);
252 
253   return m_opaque_wp.lock();
254 }
255 
SetSP(const lldb::WatchpointSP & sp)256 void SBWatchpoint::SetSP(const lldb::WatchpointSP &sp) {
257   LLDB_INSTRUMENT_VA(this, sp);
258 
259   m_opaque_wp = sp;
260 }
261 
EventIsWatchpointEvent(const lldb::SBEvent & event)262 bool SBWatchpoint::EventIsWatchpointEvent(const lldb::SBEvent &event) {
263   LLDB_INSTRUMENT_VA(event);
264 
265   return Watchpoint::WatchpointEventData::GetEventDataFromEvent(event.get()) !=
266          nullptr;
267 }
268 
269 WatchpointEventType
GetWatchpointEventTypeFromEvent(const SBEvent & event)270 SBWatchpoint::GetWatchpointEventTypeFromEvent(const SBEvent &event) {
271   LLDB_INSTRUMENT_VA(event);
272 
273   if (event.IsValid())
274     return Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent(
275         event.GetSP());
276   return eWatchpointEventTypeInvalidType;
277 }
278 
GetWatchpointFromEvent(const lldb::SBEvent & event)279 SBWatchpoint SBWatchpoint::GetWatchpointFromEvent(const lldb::SBEvent &event) {
280   LLDB_INSTRUMENT_VA(event);
281 
282   SBWatchpoint sb_watchpoint;
283   if (event.IsValid())
284     sb_watchpoint =
285         Watchpoint::WatchpointEventData::GetWatchpointFromEvent(event.GetSP());
286   return sb_watchpoint;
287 }
288 
GetType()289 lldb::SBType SBWatchpoint::GetType() {
290   LLDB_INSTRUMENT_VA(this);
291 
292   lldb::WatchpointSP watchpoint_sp(GetSP());
293   if (watchpoint_sp) {
294     std::lock_guard<std::recursive_mutex> guard(
295         watchpoint_sp->GetTarget().GetAPIMutex());
296     const CompilerType &type = watchpoint_sp->GetCompilerType();
297     return lldb::SBType(type);
298   }
299   return lldb::SBType();
300 }
301 
GetWatchValueKind()302 WatchpointValueKind SBWatchpoint::GetWatchValueKind() {
303   LLDB_INSTRUMENT_VA(this);
304 
305   lldb::WatchpointSP watchpoint_sp(GetSP());
306   if (watchpoint_sp) {
307     std::lock_guard<std::recursive_mutex> guard(
308         watchpoint_sp->GetTarget().GetAPIMutex());
309     if (watchpoint_sp->IsWatchVariable())
310       return WatchpointValueKind::eWatchPointValueKindVariable;
311     return WatchpointValueKind::eWatchPointValueKindExpression;
312   }
313   return WatchpointValueKind::eWatchPointValueKindInvalid;
314 }
315 
GetWatchSpec()316 const char *SBWatchpoint::GetWatchSpec() {
317   LLDB_INSTRUMENT_VA(this);
318 
319   lldb::WatchpointSP watchpoint_sp(GetSP());
320   if (!watchpoint_sp)
321     return nullptr;
322 
323   std::lock_guard<std::recursive_mutex> guard(
324       watchpoint_sp->GetTarget().GetAPIMutex());
325   // Store the result of `GetWatchSpec()` as a ConstString
326   // so that the C string we return has a sufficiently long
327   // lifetime. Note this a memory leak but should be fairly
328   // low impact.
329   return ConstString(watchpoint_sp->GetWatchSpec()).AsCString();
330 }
331 
IsWatchingReads()332 bool SBWatchpoint::IsWatchingReads() {
333   LLDB_INSTRUMENT_VA(this);
334   lldb::WatchpointSP watchpoint_sp(GetSP());
335   if (watchpoint_sp) {
336     std::lock_guard<std::recursive_mutex> guard(
337         watchpoint_sp->GetTarget().GetAPIMutex());
338 
339     return watchpoint_sp->WatchpointRead();
340   }
341 
342   return false;
343 }
344 
IsWatchingWrites()345 bool SBWatchpoint::IsWatchingWrites() {
346   LLDB_INSTRUMENT_VA(this);
347   lldb::WatchpointSP watchpoint_sp(GetSP());
348   if (watchpoint_sp) {
349     std::lock_guard<std::recursive_mutex> guard(
350         watchpoint_sp->GetTarget().GetAPIMutex());
351 
352     return watchpoint_sp->WatchpointWrite() ||
353            watchpoint_sp->WatchpointModify();
354   }
355 
356   return false;
357 }
358