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 | |
29 | SBWatchpoint::SBWatchpoint() { LLDB_INSTRUMENT_VA(this); } |
30 | |
31 | SBWatchpoint::SBWatchpoint(const lldb::WatchpointSP &wp_sp) |
32 | : m_opaque_wp(wp_sp) { |
33 | LLDB_INSTRUMENT_VA(this, wp_sp); |
34 | } |
35 | |
36 | SBWatchpoint::SBWatchpoint(const SBWatchpoint &rhs) |
37 | : m_opaque_wp(rhs.m_opaque_wp) { |
38 | LLDB_INSTRUMENT_VA(this, rhs); |
39 | } |
40 | |
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 | |
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 | |
61 | bool SBWatchpoint::IsValid() const { |
62 | LLDB_INSTRUMENT_VA(this); |
63 | return this->operator bool(); |
64 | } |
65 | SBWatchpoint::operator bool() const { |
66 | LLDB_INSTRUMENT_VA(this); |
67 | |
68 | return bool(m_opaque_wp.lock()); |
69 | } |
70 | |
71 | bool SBWatchpoint::operator==(const SBWatchpoint &rhs) const { |
72 | LLDB_INSTRUMENT_VA(this, rhs); |
73 | |
74 | return GetSP() == rhs.GetSP(); |
75 | } |
76 | |
77 | bool SBWatchpoint::operator!=(const SBWatchpoint &rhs) const { |
78 | LLDB_INSTRUMENT_VA(this, rhs); |
79 | |
80 | return !(*this == rhs); |
81 | } |
82 | |
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 | |
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 | |
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 | |
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 | |
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(wp_sp: watchpoint_sp, notify); |
146 | else |
147 | process_sp->DisableWatchpoint(wp_sp: watchpoint_sp, notify); |
148 | } else { |
149 | watchpoint_sp->SetEnabled(enabled, notify); |
150 | } |
151 | } |
152 | } |
153 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 | |
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(s: &strm, level); |
237 | strm.EOL(); |
238 | } else |
239 | strm.PutCString(cstr: "No value" ); |
240 | |
241 | return true; |
242 | } |
243 | |
244 | void SBWatchpoint::Clear() { |
245 | LLDB_INSTRUMENT_VA(this); |
246 | |
247 | m_opaque_wp.reset(); |
248 | } |
249 | |
250 | lldb::WatchpointSP SBWatchpoint::GetSP() const { |
251 | LLDB_INSTRUMENT_VA(this); |
252 | |
253 | return m_opaque_wp.lock(); |
254 | } |
255 | |
256 | void SBWatchpoint::SetSP(const lldb::WatchpointSP &sp) { |
257 | LLDB_INSTRUMENT_VA(this, sp); |
258 | |
259 | m_opaque_wp = sp; |
260 | } |
261 | |
262 | bool SBWatchpoint::EventIsWatchpointEvent(const lldb::SBEvent &event) { |
263 | LLDB_INSTRUMENT_VA(event); |
264 | |
265 | return Watchpoint::WatchpointEventData::GetEventDataFromEvent(event_sp: event.get()) != |
266 | nullptr; |
267 | } |
268 | |
269 | WatchpointEventType |
270 | SBWatchpoint::GetWatchpointEventTypeFromEvent(const SBEvent &event) { |
271 | LLDB_INSTRUMENT_VA(event); |
272 | |
273 | if (event.IsValid()) |
274 | return Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent( |
275 | event_sp: event.GetSP()); |
276 | return eWatchpointEventTypeInvalidType; |
277 | } |
278 | |
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_sp: event.GetSP()); |
286 | return sb_watchpoint; |
287 | } |
288 | |
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 | |
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 | |
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 | |
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 | |
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 | |