1 | //===-- SBBreakpointLocation.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/SBBreakpointLocation.h" |
10 | #include "lldb/API/SBAddress.h" |
11 | #include "lldb/API/SBDebugger.h" |
12 | #include "lldb/API/SBDefines.h" |
13 | #include "lldb/API/SBStream.h" |
14 | #include "lldb/API/SBStringList.h" |
15 | #include "lldb/API/SBStructuredData.h" |
16 | #include "lldb/Utility/Instrumentation.h" |
17 | |
18 | #include "lldb/Breakpoint/Breakpoint.h" |
19 | #include "lldb/Breakpoint/BreakpointLocation.h" |
20 | #include "lldb/Core/Debugger.h" |
21 | #include "lldb/Core/StructuredDataImpl.h" |
22 | #include "lldb/Interpreter/CommandInterpreter.h" |
23 | #include "lldb/Interpreter/ScriptInterpreter.h" |
24 | #include "lldb/Target/Target.h" |
25 | #include "lldb/Target/ThreadSpec.h" |
26 | #include "lldb/Utility/Stream.h" |
27 | #include "lldb/lldb-defines.h" |
28 | #include "lldb/lldb-types.h" |
29 | |
30 | #include "SBBreakpointOptionCommon.h" |
31 | |
32 | using namespace lldb; |
33 | using namespace lldb_private; |
34 | |
35 | SBBreakpointLocation::SBBreakpointLocation() { LLDB_INSTRUMENT_VA(this); } |
36 | |
37 | SBBreakpointLocation::SBBreakpointLocation( |
38 | const lldb::BreakpointLocationSP &break_loc_sp) |
39 | : m_opaque_wp(break_loc_sp) { |
40 | LLDB_INSTRUMENT_VA(this, break_loc_sp); |
41 | } |
42 | |
43 | SBBreakpointLocation::SBBreakpointLocation(const SBBreakpointLocation &rhs) |
44 | : m_opaque_wp(rhs.m_opaque_wp) { |
45 | LLDB_INSTRUMENT_VA(this, rhs); |
46 | } |
47 | |
48 | const SBBreakpointLocation &SBBreakpointLocation:: |
49 | operator=(const SBBreakpointLocation &rhs) { |
50 | LLDB_INSTRUMENT_VA(this, rhs); |
51 | |
52 | m_opaque_wp = rhs.m_opaque_wp; |
53 | return *this; |
54 | } |
55 | |
56 | SBBreakpointLocation::~SBBreakpointLocation() = default; |
57 | |
58 | BreakpointLocationSP SBBreakpointLocation::GetSP() const { |
59 | return m_opaque_wp.lock(); |
60 | } |
61 | |
62 | bool SBBreakpointLocation::IsValid() const { |
63 | LLDB_INSTRUMENT_VA(this); |
64 | return this->operator bool(); |
65 | } |
66 | SBBreakpointLocation::operator bool() const { |
67 | LLDB_INSTRUMENT_VA(this); |
68 | |
69 | return bool(GetSP()); |
70 | } |
71 | |
72 | SBAddress SBBreakpointLocation::GetAddress() { |
73 | LLDB_INSTRUMENT_VA(this); |
74 | |
75 | BreakpointLocationSP loc_sp = GetSP(); |
76 | if (loc_sp) { |
77 | return SBAddress(loc_sp->GetAddress()); |
78 | } |
79 | |
80 | return SBAddress(); |
81 | } |
82 | |
83 | addr_t SBBreakpointLocation::GetLoadAddress() { |
84 | LLDB_INSTRUMENT_VA(this); |
85 | |
86 | addr_t ret_addr = LLDB_INVALID_ADDRESS; |
87 | BreakpointLocationSP loc_sp = GetSP(); |
88 | |
89 | if (loc_sp) { |
90 | std::lock_guard<std::recursive_mutex> guard( |
91 | loc_sp->GetTarget().GetAPIMutex()); |
92 | ret_addr = loc_sp->GetLoadAddress(); |
93 | } |
94 | |
95 | return ret_addr; |
96 | } |
97 | |
98 | void SBBreakpointLocation::SetEnabled(bool enabled) { |
99 | LLDB_INSTRUMENT_VA(this, enabled); |
100 | |
101 | BreakpointLocationSP loc_sp = GetSP(); |
102 | if (loc_sp) { |
103 | std::lock_guard<std::recursive_mutex> guard( |
104 | loc_sp->GetTarget().GetAPIMutex()); |
105 | loc_sp->SetEnabled(enabled); |
106 | } |
107 | } |
108 | |
109 | bool SBBreakpointLocation::IsEnabled() { |
110 | LLDB_INSTRUMENT_VA(this); |
111 | |
112 | BreakpointLocationSP loc_sp = GetSP(); |
113 | if (loc_sp) { |
114 | std::lock_guard<std::recursive_mutex> guard( |
115 | loc_sp->GetTarget().GetAPIMutex()); |
116 | return loc_sp->IsEnabled(); |
117 | } else |
118 | return false; |
119 | } |
120 | |
121 | uint32_t SBBreakpointLocation::GetHitCount() { |
122 | LLDB_INSTRUMENT_VA(this); |
123 | |
124 | BreakpointLocationSP loc_sp = GetSP(); |
125 | if (loc_sp) { |
126 | std::lock_guard<std::recursive_mutex> guard( |
127 | loc_sp->GetTarget().GetAPIMutex()); |
128 | return loc_sp->GetHitCount(); |
129 | } else |
130 | return 0; |
131 | } |
132 | |
133 | uint32_t SBBreakpointLocation::GetIgnoreCount() { |
134 | LLDB_INSTRUMENT_VA(this); |
135 | |
136 | BreakpointLocationSP loc_sp = GetSP(); |
137 | if (loc_sp) { |
138 | std::lock_guard<std::recursive_mutex> guard( |
139 | loc_sp->GetTarget().GetAPIMutex()); |
140 | return loc_sp->GetIgnoreCount(); |
141 | } else |
142 | return 0; |
143 | } |
144 | |
145 | void SBBreakpointLocation::SetIgnoreCount(uint32_t n) { |
146 | LLDB_INSTRUMENT_VA(this, n); |
147 | |
148 | BreakpointLocationSP loc_sp = GetSP(); |
149 | if (loc_sp) { |
150 | std::lock_guard<std::recursive_mutex> guard( |
151 | loc_sp->GetTarget().GetAPIMutex()); |
152 | loc_sp->SetIgnoreCount(n); |
153 | } |
154 | } |
155 | |
156 | void SBBreakpointLocation::SetCondition(const char *condition) { |
157 | LLDB_INSTRUMENT_VA(this, condition); |
158 | |
159 | BreakpointLocationSP loc_sp = GetSP(); |
160 | if (loc_sp) { |
161 | std::lock_guard<std::recursive_mutex> guard( |
162 | loc_sp->GetTarget().GetAPIMutex()); |
163 | loc_sp->SetCondition(condition); |
164 | } |
165 | } |
166 | |
167 | const char *SBBreakpointLocation::GetCondition() { |
168 | LLDB_INSTRUMENT_VA(this); |
169 | |
170 | BreakpointLocationSP loc_sp = GetSP(); |
171 | if (!loc_sp) |
172 | return nullptr; |
173 | |
174 | std::lock_guard<std::recursive_mutex> guard( |
175 | loc_sp->GetTarget().GetAPIMutex()); |
176 | return ConstString(loc_sp->GetConditionText()).GetCString(); |
177 | } |
178 | |
179 | void SBBreakpointLocation::SetAutoContinue(bool auto_continue) { |
180 | LLDB_INSTRUMENT_VA(this, auto_continue); |
181 | |
182 | BreakpointLocationSP loc_sp = GetSP(); |
183 | if (loc_sp) { |
184 | std::lock_guard<std::recursive_mutex> guard( |
185 | loc_sp->GetTarget().GetAPIMutex()); |
186 | loc_sp->SetAutoContinue(auto_continue); |
187 | } |
188 | } |
189 | |
190 | bool SBBreakpointLocation::GetAutoContinue() { |
191 | LLDB_INSTRUMENT_VA(this); |
192 | |
193 | BreakpointLocationSP loc_sp = GetSP(); |
194 | if (loc_sp) { |
195 | std::lock_guard<std::recursive_mutex> guard( |
196 | loc_sp->GetTarget().GetAPIMutex()); |
197 | return loc_sp->IsAutoContinue(); |
198 | } |
199 | return false; |
200 | } |
201 | |
202 | void SBBreakpointLocation::SetCallback(SBBreakpointHitCallback callback, |
203 | void *baton) { |
204 | LLDB_INSTRUMENT_VA(this, callback, baton); |
205 | |
206 | BreakpointLocationSP loc_sp = GetSP(); |
207 | |
208 | if (loc_sp) { |
209 | std::lock_guard<std::recursive_mutex> guard( |
210 | loc_sp->GetTarget().GetAPIMutex()); |
211 | BatonSP baton_sp(new SBBreakpointCallbackBaton(callback, baton)); |
212 | loc_sp->SetCallback(callback: SBBreakpointCallbackBaton::PrivateBreakpointHitCallback, |
213 | callback_baton_sp: baton_sp, is_synchronous: false); |
214 | } |
215 | } |
216 | |
217 | void SBBreakpointLocation::SetScriptCallbackFunction( |
218 | const char *callback_function_name) { |
219 | LLDB_INSTRUMENT_VA(this, callback_function_name); |
220 | } |
221 | |
222 | SBError SBBreakpointLocation::SetScriptCallbackFunction( |
223 | const char *callback_function_name, |
224 | SBStructuredData &) { |
225 | LLDB_INSTRUMENT_VA(this, callback_function_name, extra_args); |
226 | SBError sb_error; |
227 | BreakpointLocationSP loc_sp = GetSP(); |
228 | |
229 | if (loc_sp) { |
230 | Status error; |
231 | std::lock_guard<std::recursive_mutex> guard( |
232 | loc_sp->GetTarget().GetAPIMutex()); |
233 | BreakpointOptions &bp_options = loc_sp->GetLocationOptions(); |
234 | error = loc_sp->GetBreakpoint() |
235 | .GetTarget() |
236 | .GetDebugger() |
237 | .GetScriptInterpreter() |
238 | ->SetBreakpointCommandCallbackFunction(bp_options, |
239 | function_name: callback_function_name, |
240 | extra_args_sp: extra_args.m_impl_up |
241 | ->GetObjectSP()); |
242 | sb_error.SetError(error); |
243 | } else |
244 | sb_error.SetErrorString("invalid breakpoint" ); |
245 | |
246 | return sb_error; |
247 | } |
248 | |
249 | SBError |
250 | SBBreakpointLocation::SetScriptCallbackBody(const char *callback_body_text) { |
251 | LLDB_INSTRUMENT_VA(this, callback_body_text); |
252 | |
253 | BreakpointLocationSP loc_sp = GetSP(); |
254 | |
255 | SBError sb_error; |
256 | if (loc_sp) { |
257 | std::lock_guard<std::recursive_mutex> guard( |
258 | loc_sp->GetTarget().GetAPIMutex()); |
259 | BreakpointOptions &bp_options = loc_sp->GetLocationOptions(); |
260 | Status error = |
261 | loc_sp->GetBreakpoint() |
262 | .GetTarget() |
263 | .GetDebugger() |
264 | .GetScriptInterpreter() |
265 | ->SetBreakpointCommandCallback(bp_options, callback_text: callback_body_text, |
266 | /*is_callback=*/false); |
267 | sb_error.SetError(error); |
268 | } else |
269 | sb_error.SetErrorString("invalid breakpoint" ); |
270 | |
271 | return sb_error; |
272 | } |
273 | |
274 | void SBBreakpointLocation::SetCommandLineCommands(SBStringList &commands) { |
275 | LLDB_INSTRUMENT_VA(this, commands); |
276 | |
277 | BreakpointLocationSP loc_sp = GetSP(); |
278 | if (!loc_sp) |
279 | return; |
280 | if (commands.GetSize() == 0) |
281 | return; |
282 | |
283 | std::lock_guard<std::recursive_mutex> guard( |
284 | loc_sp->GetTarget().GetAPIMutex()); |
285 | std::unique_ptr<BreakpointOptions::CommandData> cmd_data_up( |
286 | new BreakpointOptions::CommandData(*commands, eScriptLanguageNone)); |
287 | |
288 | loc_sp->GetLocationOptions().SetCommandDataCallback(cmd_data_up); |
289 | } |
290 | |
291 | bool SBBreakpointLocation::GetCommandLineCommands(SBStringList &commands) { |
292 | LLDB_INSTRUMENT_VA(this, commands); |
293 | |
294 | BreakpointLocationSP loc_sp = GetSP(); |
295 | if (!loc_sp) |
296 | return false; |
297 | StringList command_list; |
298 | bool has_commands = |
299 | loc_sp->GetLocationOptions().GetCommandLineCallbacks(command_list); |
300 | if (has_commands) |
301 | commands.AppendList(strings: command_list); |
302 | return has_commands; |
303 | } |
304 | |
305 | void SBBreakpointLocation::SetThreadID(tid_t thread_id) { |
306 | LLDB_INSTRUMENT_VA(this, thread_id); |
307 | |
308 | BreakpointLocationSP loc_sp = GetSP(); |
309 | if (loc_sp) { |
310 | std::lock_guard<std::recursive_mutex> guard( |
311 | loc_sp->GetTarget().GetAPIMutex()); |
312 | loc_sp->SetThreadID(thread_id); |
313 | } |
314 | } |
315 | |
316 | tid_t SBBreakpointLocation::GetThreadID() { |
317 | LLDB_INSTRUMENT_VA(this); |
318 | |
319 | tid_t tid = LLDB_INVALID_THREAD_ID; |
320 | BreakpointLocationSP loc_sp = GetSP(); |
321 | if (loc_sp) { |
322 | std::lock_guard<std::recursive_mutex> guard( |
323 | loc_sp->GetTarget().GetAPIMutex()); |
324 | return loc_sp->GetThreadID(); |
325 | } |
326 | return tid; |
327 | } |
328 | |
329 | void SBBreakpointLocation::SetThreadIndex(uint32_t index) { |
330 | LLDB_INSTRUMENT_VA(this, index); |
331 | |
332 | BreakpointLocationSP loc_sp = GetSP(); |
333 | if (loc_sp) { |
334 | std::lock_guard<std::recursive_mutex> guard( |
335 | loc_sp->GetTarget().GetAPIMutex()); |
336 | loc_sp->SetThreadIndex(index); |
337 | } |
338 | } |
339 | |
340 | uint32_t SBBreakpointLocation::GetThreadIndex() const { |
341 | LLDB_INSTRUMENT_VA(this); |
342 | |
343 | uint32_t thread_idx = UINT32_MAX; |
344 | BreakpointLocationSP loc_sp = GetSP(); |
345 | if (loc_sp) { |
346 | std::lock_guard<std::recursive_mutex> guard( |
347 | loc_sp->GetTarget().GetAPIMutex()); |
348 | return loc_sp->GetThreadIndex(); |
349 | } |
350 | return thread_idx; |
351 | } |
352 | |
353 | void SBBreakpointLocation::SetThreadName(const char *thread_name) { |
354 | LLDB_INSTRUMENT_VA(this, thread_name); |
355 | |
356 | BreakpointLocationSP loc_sp = GetSP(); |
357 | if (loc_sp) { |
358 | std::lock_guard<std::recursive_mutex> guard( |
359 | loc_sp->GetTarget().GetAPIMutex()); |
360 | loc_sp->SetThreadName(thread_name); |
361 | } |
362 | } |
363 | |
364 | const char *SBBreakpointLocation::GetThreadName() const { |
365 | LLDB_INSTRUMENT_VA(this); |
366 | |
367 | BreakpointLocationSP loc_sp = GetSP(); |
368 | if (!loc_sp) |
369 | return nullptr; |
370 | |
371 | std::lock_guard<std::recursive_mutex> guard( |
372 | loc_sp->GetTarget().GetAPIMutex()); |
373 | return ConstString(loc_sp->GetThreadName()).GetCString(); |
374 | } |
375 | |
376 | void SBBreakpointLocation::SetQueueName(const char *queue_name) { |
377 | LLDB_INSTRUMENT_VA(this, queue_name); |
378 | |
379 | BreakpointLocationSP loc_sp = GetSP(); |
380 | if (loc_sp) { |
381 | std::lock_guard<std::recursive_mutex> guard( |
382 | loc_sp->GetTarget().GetAPIMutex()); |
383 | loc_sp->SetQueueName(queue_name); |
384 | } |
385 | } |
386 | |
387 | const char *SBBreakpointLocation::GetQueueName() const { |
388 | LLDB_INSTRUMENT_VA(this); |
389 | |
390 | BreakpointLocationSP loc_sp = GetSP(); |
391 | if (!loc_sp) |
392 | return nullptr; |
393 | |
394 | std::lock_guard<std::recursive_mutex> guard( |
395 | loc_sp->GetTarget().GetAPIMutex()); |
396 | return ConstString(loc_sp->GetQueueName()).GetCString(); |
397 | } |
398 | |
399 | bool SBBreakpointLocation::IsResolved() { |
400 | LLDB_INSTRUMENT_VA(this); |
401 | |
402 | BreakpointLocationSP loc_sp = GetSP(); |
403 | if (loc_sp) { |
404 | std::lock_guard<std::recursive_mutex> guard( |
405 | loc_sp->GetTarget().GetAPIMutex()); |
406 | return loc_sp->IsResolved(); |
407 | } |
408 | return false; |
409 | } |
410 | |
411 | void SBBreakpointLocation::SetLocation( |
412 | const lldb::BreakpointLocationSP &break_loc_sp) { |
413 | // Uninstall the callbacks? |
414 | m_opaque_wp = break_loc_sp; |
415 | } |
416 | |
417 | bool SBBreakpointLocation::GetDescription(SBStream &description, |
418 | DescriptionLevel level) { |
419 | LLDB_INSTRUMENT_VA(this, description, level); |
420 | |
421 | Stream &strm = description.ref(); |
422 | BreakpointLocationSP loc_sp = GetSP(); |
423 | |
424 | if (loc_sp) { |
425 | std::lock_guard<std::recursive_mutex> guard( |
426 | loc_sp->GetTarget().GetAPIMutex()); |
427 | loc_sp->GetDescription(s: &strm, level); |
428 | strm.EOL(); |
429 | } else |
430 | strm.PutCString(cstr: "No value" ); |
431 | |
432 | return true; |
433 | } |
434 | |
435 | break_id_t SBBreakpointLocation::GetID() { |
436 | LLDB_INSTRUMENT_VA(this); |
437 | |
438 | BreakpointLocationSP loc_sp = GetSP(); |
439 | if (loc_sp) { |
440 | std::lock_guard<std::recursive_mutex> guard( |
441 | loc_sp->GetTarget().GetAPIMutex()); |
442 | return loc_sp->GetID(); |
443 | } else |
444 | return LLDB_INVALID_BREAK_ID; |
445 | } |
446 | |
447 | SBBreakpoint SBBreakpointLocation::GetBreakpoint() { |
448 | LLDB_INSTRUMENT_VA(this); |
449 | |
450 | BreakpointLocationSP loc_sp = GetSP(); |
451 | |
452 | SBBreakpoint sb_bp; |
453 | if (loc_sp) { |
454 | std::lock_guard<std::recursive_mutex> guard( |
455 | loc_sp->GetTarget().GetAPIMutex()); |
456 | sb_bp = loc_sp->GetBreakpoint().shared_from_this(); |
457 | } |
458 | |
459 | return sb_bp; |
460 | } |
461 | |