1 | //===-- SBBreakpoint.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/SBBreakpoint.h" |
10 | #include "lldb/API/SBBreakpointLocation.h" |
11 | #include "lldb/API/SBDebugger.h" |
12 | #include "lldb/API/SBEvent.h" |
13 | #include "lldb/API/SBProcess.h" |
14 | #include "lldb/API/SBStream.h" |
15 | #include "lldb/API/SBStringList.h" |
16 | #include "lldb/API/SBStructuredData.h" |
17 | #include "lldb/API/SBThread.h" |
18 | #include "lldb/Utility/Instrumentation.h" |
19 | |
20 | #include "lldb/Breakpoint/Breakpoint.h" |
21 | #include "lldb/Breakpoint/BreakpointIDList.h" |
22 | #include "lldb/Breakpoint/BreakpointLocation.h" |
23 | #include "lldb/Breakpoint/BreakpointResolver.h" |
24 | #include "lldb/Breakpoint/BreakpointResolverScripted.h" |
25 | #include "lldb/Breakpoint/StoppointCallbackContext.h" |
26 | #include "lldb/Core/Address.h" |
27 | #include "lldb/Core/Debugger.h" |
28 | #include "lldb/Core/StructuredDataImpl.h" |
29 | #include "lldb/Interpreter/CommandInterpreter.h" |
30 | #include "lldb/Interpreter/ScriptInterpreter.h" |
31 | #include "lldb/Target/Process.h" |
32 | #include "lldb/Target/SectionLoadList.h" |
33 | #include "lldb/Target/Target.h" |
34 | #include "lldb/Target/Thread.h" |
35 | #include "lldb/Target/ThreadSpec.h" |
36 | #include "lldb/Utility/Stream.h" |
37 | |
38 | #include "SBBreakpointOptionCommon.h" |
39 | |
40 | #include "lldb/lldb-enumerations.h" |
41 | |
42 | #include "llvm/ADT/STLExtras.h" |
43 | |
44 | using namespace lldb; |
45 | using namespace lldb_private; |
46 | |
47 | SBBreakpoint::SBBreakpoint() { LLDB_INSTRUMENT_VA(this); } |
48 | |
49 | SBBreakpoint::SBBreakpoint(const SBBreakpoint &rhs) |
50 | : m_opaque_wp(rhs.m_opaque_wp) { |
51 | LLDB_INSTRUMENT_VA(this, rhs); |
52 | } |
53 | |
54 | SBBreakpoint::SBBreakpoint(const lldb::BreakpointSP &bp_sp) |
55 | : m_opaque_wp(bp_sp) { |
56 | LLDB_INSTRUMENT_VA(this, bp_sp); |
57 | } |
58 | |
59 | SBBreakpoint::~SBBreakpoint() = default; |
60 | |
61 | const SBBreakpoint &SBBreakpoint::operator=(const SBBreakpoint &rhs) { |
62 | LLDB_INSTRUMENT_VA(this, rhs); |
63 | |
64 | m_opaque_wp = rhs.m_opaque_wp; |
65 | return *this; |
66 | } |
67 | |
68 | bool SBBreakpoint::operator==(const lldb::SBBreakpoint &rhs) { |
69 | LLDB_INSTRUMENT_VA(this, rhs); |
70 | |
71 | return m_opaque_wp.lock() == rhs.m_opaque_wp.lock(); |
72 | } |
73 | |
74 | bool SBBreakpoint::operator!=(const lldb::SBBreakpoint &rhs) { |
75 | LLDB_INSTRUMENT_VA(this, rhs); |
76 | |
77 | return m_opaque_wp.lock() != rhs.m_opaque_wp.lock(); |
78 | } |
79 | |
80 | SBTarget SBBreakpoint::GetTarget() const { |
81 | LLDB_INSTRUMENT_VA(this); |
82 | |
83 | BreakpointSP bkpt_sp = GetSP(); |
84 | if (bkpt_sp) |
85 | return SBTarget(bkpt_sp->GetTargetSP()); |
86 | |
87 | return SBTarget(); |
88 | } |
89 | |
90 | break_id_t SBBreakpoint::GetID() const { |
91 | LLDB_INSTRUMENT_VA(this); |
92 | |
93 | break_id_t break_id = LLDB_INVALID_BREAK_ID; |
94 | BreakpointSP bkpt_sp = GetSP(); |
95 | if (bkpt_sp) |
96 | break_id = bkpt_sp->GetID(); |
97 | |
98 | return break_id; |
99 | } |
100 | |
101 | bool SBBreakpoint::IsValid() const { |
102 | LLDB_INSTRUMENT_VA(this); |
103 | return this->operator bool(); |
104 | } |
105 | SBBreakpoint::operator bool() const { |
106 | LLDB_INSTRUMENT_VA(this); |
107 | |
108 | BreakpointSP bkpt_sp = GetSP(); |
109 | if (!bkpt_sp) |
110 | return false; |
111 | else if (bkpt_sp->GetTarget().GetBreakpointByID(break_id: bkpt_sp->GetID())) |
112 | return true; |
113 | else |
114 | return false; |
115 | } |
116 | |
117 | void SBBreakpoint::ClearAllBreakpointSites() { |
118 | LLDB_INSTRUMENT_VA(this); |
119 | |
120 | BreakpointSP bkpt_sp = GetSP(); |
121 | if (bkpt_sp) { |
122 | std::lock_guard<std::recursive_mutex> guard( |
123 | bkpt_sp->GetTarget().GetAPIMutex()); |
124 | bkpt_sp->ClearAllBreakpointSites(); |
125 | } |
126 | } |
127 | |
128 | SBBreakpointLocation SBBreakpoint::FindLocationByAddress(addr_t vm_addr) { |
129 | LLDB_INSTRUMENT_VA(this, vm_addr); |
130 | |
131 | SBBreakpointLocation sb_bp_location; |
132 | |
133 | BreakpointSP bkpt_sp = GetSP(); |
134 | if (bkpt_sp) { |
135 | if (vm_addr != LLDB_INVALID_ADDRESS) { |
136 | std::lock_guard<std::recursive_mutex> guard( |
137 | bkpt_sp->GetTarget().GetAPIMutex()); |
138 | Address address; |
139 | Target &target = bkpt_sp->GetTarget(); |
140 | if (!target.GetSectionLoadList().ResolveLoadAddress(load_addr: vm_addr, so_addr&: address)) { |
141 | address.SetRawAddress(vm_addr); |
142 | } |
143 | sb_bp_location.SetLocation(bkpt_sp->FindLocationByAddress(addr: address)); |
144 | } |
145 | } |
146 | return sb_bp_location; |
147 | } |
148 | |
149 | break_id_t SBBreakpoint::FindLocationIDByAddress(addr_t vm_addr) { |
150 | LLDB_INSTRUMENT_VA(this, vm_addr); |
151 | |
152 | break_id_t break_id = LLDB_INVALID_BREAK_ID; |
153 | BreakpointSP bkpt_sp = GetSP(); |
154 | |
155 | if (bkpt_sp && vm_addr != LLDB_INVALID_ADDRESS) { |
156 | std::lock_guard<std::recursive_mutex> guard( |
157 | bkpt_sp->GetTarget().GetAPIMutex()); |
158 | Address address; |
159 | Target &target = bkpt_sp->GetTarget(); |
160 | if (!target.GetSectionLoadList().ResolveLoadAddress(load_addr: vm_addr, so_addr&: address)) { |
161 | address.SetRawAddress(vm_addr); |
162 | } |
163 | break_id = bkpt_sp->FindLocationIDByAddress(addr: address); |
164 | } |
165 | |
166 | return break_id; |
167 | } |
168 | |
169 | SBBreakpointLocation SBBreakpoint::FindLocationByID(break_id_t bp_loc_id) { |
170 | LLDB_INSTRUMENT_VA(this, bp_loc_id); |
171 | |
172 | SBBreakpointLocation sb_bp_location; |
173 | BreakpointSP bkpt_sp = GetSP(); |
174 | |
175 | if (bkpt_sp) { |
176 | std::lock_guard<std::recursive_mutex> guard( |
177 | bkpt_sp->GetTarget().GetAPIMutex()); |
178 | sb_bp_location.SetLocation(bkpt_sp->FindLocationByID(bp_loc_id)); |
179 | } |
180 | |
181 | return sb_bp_location; |
182 | } |
183 | |
184 | SBBreakpointLocation SBBreakpoint::GetLocationAtIndex(uint32_t index) { |
185 | LLDB_INSTRUMENT_VA(this, index); |
186 | |
187 | SBBreakpointLocation sb_bp_location; |
188 | BreakpointSP bkpt_sp = GetSP(); |
189 | |
190 | if (bkpt_sp) { |
191 | std::lock_guard<std::recursive_mutex> guard( |
192 | bkpt_sp->GetTarget().GetAPIMutex()); |
193 | sb_bp_location.SetLocation(bkpt_sp->GetLocationAtIndex(index)); |
194 | } |
195 | |
196 | return sb_bp_location; |
197 | } |
198 | |
199 | void SBBreakpoint::SetEnabled(bool enable) { |
200 | LLDB_INSTRUMENT_VA(this, enable); |
201 | |
202 | BreakpointSP bkpt_sp = GetSP(); |
203 | |
204 | if (bkpt_sp) { |
205 | std::lock_guard<std::recursive_mutex> guard( |
206 | bkpt_sp->GetTarget().GetAPIMutex()); |
207 | bkpt_sp->SetEnabled(enable); |
208 | } |
209 | } |
210 | |
211 | bool SBBreakpoint::IsEnabled() { |
212 | LLDB_INSTRUMENT_VA(this); |
213 | |
214 | BreakpointSP bkpt_sp = GetSP(); |
215 | if (bkpt_sp) { |
216 | std::lock_guard<std::recursive_mutex> guard( |
217 | bkpt_sp->GetTarget().GetAPIMutex()); |
218 | return bkpt_sp->IsEnabled(); |
219 | } else |
220 | return false; |
221 | } |
222 | |
223 | void SBBreakpoint::SetOneShot(bool one_shot) { |
224 | LLDB_INSTRUMENT_VA(this, one_shot); |
225 | |
226 | BreakpointSP bkpt_sp = GetSP(); |
227 | |
228 | if (bkpt_sp) { |
229 | std::lock_guard<std::recursive_mutex> guard( |
230 | bkpt_sp->GetTarget().GetAPIMutex()); |
231 | bkpt_sp->SetOneShot(one_shot); |
232 | } |
233 | } |
234 | |
235 | bool SBBreakpoint::IsOneShot() const { |
236 | LLDB_INSTRUMENT_VA(this); |
237 | |
238 | BreakpointSP bkpt_sp = GetSP(); |
239 | if (bkpt_sp) { |
240 | std::lock_guard<std::recursive_mutex> guard( |
241 | bkpt_sp->GetTarget().GetAPIMutex()); |
242 | return bkpt_sp->IsOneShot(); |
243 | } else |
244 | return false; |
245 | } |
246 | |
247 | bool SBBreakpoint::IsInternal() { |
248 | LLDB_INSTRUMENT_VA(this); |
249 | |
250 | BreakpointSP bkpt_sp = GetSP(); |
251 | if (bkpt_sp) { |
252 | std::lock_guard<std::recursive_mutex> guard( |
253 | bkpt_sp->GetTarget().GetAPIMutex()); |
254 | return bkpt_sp->IsInternal(); |
255 | } else |
256 | return false; |
257 | } |
258 | |
259 | void SBBreakpoint::SetIgnoreCount(uint32_t count) { |
260 | LLDB_INSTRUMENT_VA(this, count); |
261 | |
262 | BreakpointSP bkpt_sp = GetSP(); |
263 | |
264 | if (bkpt_sp) { |
265 | std::lock_guard<std::recursive_mutex> guard( |
266 | bkpt_sp->GetTarget().GetAPIMutex()); |
267 | bkpt_sp->SetIgnoreCount(count); |
268 | } |
269 | } |
270 | |
271 | void SBBreakpoint::SetCondition(const char *condition) { |
272 | LLDB_INSTRUMENT_VA(this, condition); |
273 | |
274 | BreakpointSP bkpt_sp = GetSP(); |
275 | if (bkpt_sp) { |
276 | std::lock_guard<std::recursive_mutex> guard( |
277 | bkpt_sp->GetTarget().GetAPIMutex()); |
278 | bkpt_sp->SetCondition(condition); |
279 | } |
280 | } |
281 | |
282 | const char *SBBreakpoint::GetCondition() { |
283 | LLDB_INSTRUMENT_VA(this); |
284 | |
285 | BreakpointSP bkpt_sp = GetSP(); |
286 | if (!bkpt_sp) |
287 | return nullptr; |
288 | |
289 | std::lock_guard<std::recursive_mutex> guard( |
290 | bkpt_sp->GetTarget().GetAPIMutex()); |
291 | return ConstString(bkpt_sp->GetConditionText()).GetCString(); |
292 | } |
293 | |
294 | void SBBreakpoint::SetAutoContinue(bool auto_continue) { |
295 | LLDB_INSTRUMENT_VA(this, auto_continue); |
296 | |
297 | BreakpointSP bkpt_sp = GetSP(); |
298 | if (bkpt_sp) { |
299 | std::lock_guard<std::recursive_mutex> guard( |
300 | bkpt_sp->GetTarget().GetAPIMutex()); |
301 | bkpt_sp->SetAutoContinue(auto_continue); |
302 | } |
303 | } |
304 | |
305 | bool SBBreakpoint::GetAutoContinue() { |
306 | LLDB_INSTRUMENT_VA(this); |
307 | |
308 | BreakpointSP bkpt_sp = GetSP(); |
309 | if (bkpt_sp) { |
310 | std::lock_guard<std::recursive_mutex> guard( |
311 | bkpt_sp->GetTarget().GetAPIMutex()); |
312 | return bkpt_sp->IsAutoContinue(); |
313 | } |
314 | return false; |
315 | } |
316 | |
317 | uint32_t SBBreakpoint::GetHitCount() const { |
318 | LLDB_INSTRUMENT_VA(this); |
319 | |
320 | uint32_t count = 0; |
321 | BreakpointSP bkpt_sp = GetSP(); |
322 | if (bkpt_sp) { |
323 | std::lock_guard<std::recursive_mutex> guard( |
324 | bkpt_sp->GetTarget().GetAPIMutex()); |
325 | count = bkpt_sp->GetHitCount(); |
326 | } |
327 | |
328 | return count; |
329 | } |
330 | |
331 | uint32_t SBBreakpoint::GetIgnoreCount() const { |
332 | LLDB_INSTRUMENT_VA(this); |
333 | |
334 | uint32_t count = 0; |
335 | BreakpointSP bkpt_sp = GetSP(); |
336 | if (bkpt_sp) { |
337 | std::lock_guard<std::recursive_mutex> guard( |
338 | bkpt_sp->GetTarget().GetAPIMutex()); |
339 | count = bkpt_sp->GetIgnoreCount(); |
340 | } |
341 | |
342 | return count; |
343 | } |
344 | |
345 | void SBBreakpoint::SetThreadID(tid_t tid) { |
346 | LLDB_INSTRUMENT_VA(this, tid); |
347 | |
348 | BreakpointSP bkpt_sp = GetSP(); |
349 | if (bkpt_sp) { |
350 | std::lock_guard<std::recursive_mutex> guard( |
351 | bkpt_sp->GetTarget().GetAPIMutex()); |
352 | bkpt_sp->SetThreadID(tid); |
353 | } |
354 | } |
355 | |
356 | tid_t SBBreakpoint::GetThreadID() { |
357 | LLDB_INSTRUMENT_VA(this); |
358 | |
359 | tid_t tid = LLDB_INVALID_THREAD_ID; |
360 | BreakpointSP bkpt_sp = GetSP(); |
361 | if (bkpt_sp) { |
362 | std::lock_guard<std::recursive_mutex> guard( |
363 | bkpt_sp->GetTarget().GetAPIMutex()); |
364 | tid = bkpt_sp->GetThreadID(); |
365 | } |
366 | |
367 | return tid; |
368 | } |
369 | |
370 | void SBBreakpoint::SetThreadIndex(uint32_t index) { |
371 | LLDB_INSTRUMENT_VA(this, index); |
372 | |
373 | BreakpointSP bkpt_sp = GetSP(); |
374 | if (bkpt_sp) { |
375 | std::lock_guard<std::recursive_mutex> guard( |
376 | bkpt_sp->GetTarget().GetAPIMutex()); |
377 | bkpt_sp->GetOptions().GetThreadSpec()->SetIndex(index); |
378 | } |
379 | } |
380 | |
381 | uint32_t SBBreakpoint::GetThreadIndex() const { |
382 | LLDB_INSTRUMENT_VA(this); |
383 | |
384 | uint32_t thread_idx = UINT32_MAX; |
385 | BreakpointSP bkpt_sp = GetSP(); |
386 | if (bkpt_sp) { |
387 | std::lock_guard<std::recursive_mutex> guard( |
388 | bkpt_sp->GetTarget().GetAPIMutex()); |
389 | const ThreadSpec *thread_spec = |
390 | bkpt_sp->GetOptions().GetThreadSpecNoCreate(); |
391 | if (thread_spec != nullptr) |
392 | thread_idx = thread_spec->GetIndex(); |
393 | } |
394 | |
395 | return thread_idx; |
396 | } |
397 | |
398 | void SBBreakpoint::SetThreadName(const char *thread_name) { |
399 | LLDB_INSTRUMENT_VA(this, thread_name); |
400 | |
401 | BreakpointSP bkpt_sp = GetSP(); |
402 | |
403 | if (bkpt_sp) { |
404 | std::lock_guard<std::recursive_mutex> guard( |
405 | bkpt_sp->GetTarget().GetAPIMutex()); |
406 | bkpt_sp->GetOptions().GetThreadSpec()->SetName(thread_name); |
407 | } |
408 | } |
409 | |
410 | const char *SBBreakpoint::GetThreadName() const { |
411 | LLDB_INSTRUMENT_VA(this); |
412 | |
413 | BreakpointSP bkpt_sp = GetSP(); |
414 | if (!bkpt_sp) |
415 | return nullptr; |
416 | |
417 | std::lock_guard<std::recursive_mutex> guard( |
418 | bkpt_sp->GetTarget().GetAPIMutex()); |
419 | if (const ThreadSpec *thread_spec = |
420 | bkpt_sp->GetOptions().GetThreadSpecNoCreate()) |
421 | return ConstString(thread_spec->GetName()).GetCString(); |
422 | |
423 | return nullptr; |
424 | } |
425 | |
426 | void SBBreakpoint::SetQueueName(const char *queue_name) { |
427 | LLDB_INSTRUMENT_VA(this, queue_name); |
428 | |
429 | BreakpointSP bkpt_sp = GetSP(); |
430 | if (bkpt_sp) { |
431 | std::lock_guard<std::recursive_mutex> guard( |
432 | bkpt_sp->GetTarget().GetAPIMutex()); |
433 | bkpt_sp->GetOptions().GetThreadSpec()->SetQueueName(queue_name); |
434 | } |
435 | } |
436 | |
437 | const char *SBBreakpoint::GetQueueName() const { |
438 | LLDB_INSTRUMENT_VA(this); |
439 | |
440 | BreakpointSP bkpt_sp = GetSP(); |
441 | if (!bkpt_sp) |
442 | return nullptr; |
443 | |
444 | std::lock_guard<std::recursive_mutex> guard( |
445 | bkpt_sp->GetTarget().GetAPIMutex()); |
446 | if (const ThreadSpec *thread_spec = |
447 | bkpt_sp->GetOptions().GetThreadSpecNoCreate()) |
448 | return ConstString(thread_spec->GetQueueName()).GetCString(); |
449 | |
450 | return nullptr; |
451 | } |
452 | |
453 | size_t SBBreakpoint::GetNumResolvedLocations() const { |
454 | LLDB_INSTRUMENT_VA(this); |
455 | |
456 | size_t num_resolved = 0; |
457 | BreakpointSP bkpt_sp = GetSP(); |
458 | if (bkpt_sp) { |
459 | std::lock_guard<std::recursive_mutex> guard( |
460 | bkpt_sp->GetTarget().GetAPIMutex()); |
461 | num_resolved = bkpt_sp->GetNumResolvedLocations(); |
462 | } |
463 | return num_resolved; |
464 | } |
465 | |
466 | size_t SBBreakpoint::GetNumLocations() const { |
467 | LLDB_INSTRUMENT_VA(this); |
468 | |
469 | BreakpointSP bkpt_sp = GetSP(); |
470 | size_t num_locs = 0; |
471 | if (bkpt_sp) { |
472 | std::lock_guard<std::recursive_mutex> guard( |
473 | bkpt_sp->GetTarget().GetAPIMutex()); |
474 | num_locs = bkpt_sp->GetNumLocations(); |
475 | } |
476 | return num_locs; |
477 | } |
478 | |
479 | void SBBreakpoint::SetCommandLineCommands(SBStringList &commands) { |
480 | LLDB_INSTRUMENT_VA(this, commands); |
481 | |
482 | BreakpointSP bkpt_sp = GetSP(); |
483 | if (!bkpt_sp) |
484 | return; |
485 | if (commands.GetSize() == 0) |
486 | return; |
487 | |
488 | std::lock_guard<std::recursive_mutex> guard( |
489 | bkpt_sp->GetTarget().GetAPIMutex()); |
490 | std::unique_ptr<BreakpointOptions::CommandData> cmd_data_up( |
491 | new BreakpointOptions::CommandData(*commands, eScriptLanguageNone)); |
492 | |
493 | bkpt_sp->GetOptions().SetCommandDataCallback(cmd_data_up); |
494 | } |
495 | |
496 | bool SBBreakpoint::GetCommandLineCommands(SBStringList &commands) { |
497 | LLDB_INSTRUMENT_VA(this, commands); |
498 | |
499 | BreakpointSP bkpt_sp = GetSP(); |
500 | if (!bkpt_sp) |
501 | return false; |
502 | StringList command_list; |
503 | bool has_commands = |
504 | bkpt_sp->GetOptions().GetCommandLineCallbacks(command_list); |
505 | if (has_commands) |
506 | commands.AppendList(strings: command_list); |
507 | return has_commands; |
508 | } |
509 | |
510 | bool SBBreakpoint::GetDescription(SBStream &s) { |
511 | LLDB_INSTRUMENT_VA(this, s); |
512 | |
513 | return GetDescription(description&: s, include_locations: true); |
514 | } |
515 | |
516 | bool SBBreakpoint::GetDescription(SBStream &s, bool include_locations) { |
517 | LLDB_INSTRUMENT_VA(this, s, include_locations); |
518 | |
519 | BreakpointSP bkpt_sp = GetSP(); |
520 | if (bkpt_sp) { |
521 | std::lock_guard<std::recursive_mutex> guard( |
522 | bkpt_sp->GetTarget().GetAPIMutex()); |
523 | s.Printf(format: "SBBreakpoint: id = %i, " , bkpt_sp->GetID()); |
524 | bkpt_sp->GetResolverDescription(s: s.get()); |
525 | bkpt_sp->GetFilterDescription(s: s.get()); |
526 | if (include_locations) { |
527 | const size_t num_locations = bkpt_sp->GetNumLocations(); |
528 | s.Printf(format: ", locations = %" PRIu64, (uint64_t)num_locations); |
529 | } |
530 | return true; |
531 | } |
532 | s.Printf(format: "No value" ); |
533 | return false; |
534 | } |
535 | |
536 | SBError SBBreakpoint::AddLocation(SBAddress &address) { |
537 | LLDB_INSTRUMENT_VA(this, address); |
538 | |
539 | BreakpointSP bkpt_sp = GetSP(); |
540 | SBError error; |
541 | |
542 | if (!address.IsValid()) { |
543 | error.SetErrorString("Can't add an invalid address." ); |
544 | return error; |
545 | } |
546 | |
547 | if (!bkpt_sp) { |
548 | error.SetErrorString("No breakpoint to add a location to." ); |
549 | return error; |
550 | } |
551 | |
552 | if (!llvm::isa<BreakpointResolverScripted>(Val: bkpt_sp->GetResolver().get())) { |
553 | error.SetErrorString("Only a scripted resolver can add locations." ); |
554 | return error; |
555 | } |
556 | |
557 | if (bkpt_sp->GetSearchFilter()->AddressPasses(addr&: address.ref())) |
558 | bkpt_sp->AddLocation(addr: address.ref()); |
559 | else { |
560 | StreamString s; |
561 | address.get()->Dump(s: &s, exe_scope: &bkpt_sp->GetTarget(), |
562 | style: Address::DumpStyleModuleWithFileAddress); |
563 | error.SetErrorStringWithFormat("Address: %s didn't pass the filter." , |
564 | s.GetData()); |
565 | } |
566 | return error; |
567 | } |
568 | |
569 | SBStructuredData SBBreakpoint::SerializeToStructuredData() { |
570 | LLDB_INSTRUMENT_VA(this); |
571 | |
572 | SBStructuredData data; |
573 | BreakpointSP bkpt_sp = GetSP(); |
574 | |
575 | if (!bkpt_sp) |
576 | return data; |
577 | |
578 | StructuredData::ObjectSP bkpt_dict = bkpt_sp->SerializeToStructuredData(); |
579 | data.m_impl_up->SetObjectSP(bkpt_dict); |
580 | return data; |
581 | } |
582 | |
583 | void SBBreakpoint::SetCallback(SBBreakpointHitCallback callback, void *baton) { |
584 | LLDB_INSTRUMENT_VA(this, callback, baton); |
585 | |
586 | BreakpointSP bkpt_sp = GetSP(); |
587 | |
588 | if (bkpt_sp) { |
589 | std::lock_guard<std::recursive_mutex> guard( |
590 | bkpt_sp->GetTarget().GetAPIMutex()); |
591 | BatonSP baton_sp(new SBBreakpointCallbackBaton(callback, baton)); |
592 | bkpt_sp->SetCallback(callback: SBBreakpointCallbackBaton |
593 | ::PrivateBreakpointHitCallback, callback_baton_sp: baton_sp, |
594 | is_synchronous: false); |
595 | } |
596 | } |
597 | |
598 | void SBBreakpoint::SetScriptCallbackFunction( |
599 | const char *callback_function_name) { |
600 | LLDB_INSTRUMENT_VA(this, callback_function_name); |
601 | SBStructuredData empty_args; |
602 | SetScriptCallbackFunction(callback_function_name, extra_args&: empty_args); |
603 | } |
604 | |
605 | SBError SBBreakpoint::SetScriptCallbackFunction( |
606 | const char *callback_function_name, |
607 | SBStructuredData &) { |
608 | LLDB_INSTRUMENT_VA(this, callback_function_name, extra_args); |
609 | SBError sb_error; |
610 | BreakpointSP bkpt_sp = GetSP(); |
611 | |
612 | if (bkpt_sp) { |
613 | Status error; |
614 | std::lock_guard<std::recursive_mutex> guard( |
615 | bkpt_sp->GetTarget().GetAPIMutex()); |
616 | BreakpointOptions &bp_options = bkpt_sp->GetOptions(); |
617 | error = bkpt_sp->GetTarget() |
618 | .GetDebugger() |
619 | .GetScriptInterpreter() |
620 | ->SetBreakpointCommandCallbackFunction(bp_options, |
621 | function_name: callback_function_name, |
622 | extra_args_sp: extra_args.m_impl_up |
623 | ->GetObjectSP()); |
624 | sb_error.SetError(error); |
625 | } else |
626 | sb_error.SetErrorString("invalid breakpoint" ); |
627 | |
628 | return sb_error; |
629 | } |
630 | |
631 | SBError SBBreakpoint::SetScriptCallbackBody(const char *callback_body_text) { |
632 | LLDB_INSTRUMENT_VA(this, callback_body_text); |
633 | |
634 | BreakpointSP bkpt_sp = GetSP(); |
635 | |
636 | SBError sb_error; |
637 | if (bkpt_sp) { |
638 | std::lock_guard<std::recursive_mutex> guard( |
639 | bkpt_sp->GetTarget().GetAPIMutex()); |
640 | BreakpointOptions &bp_options = bkpt_sp->GetOptions(); |
641 | Status error = |
642 | bkpt_sp->GetTarget() |
643 | .GetDebugger() |
644 | .GetScriptInterpreter() |
645 | ->SetBreakpointCommandCallback(bp_options, callback_text: callback_body_text, |
646 | /*is_callback=*/false); |
647 | sb_error.SetError(error); |
648 | } else |
649 | sb_error.SetErrorString("invalid breakpoint" ); |
650 | |
651 | return sb_error; |
652 | } |
653 | |
654 | bool SBBreakpoint::AddName(const char *new_name) { |
655 | LLDB_INSTRUMENT_VA(this, new_name); |
656 | |
657 | SBError status = AddNameWithErrorHandling(new_name); |
658 | return status.Success(); |
659 | } |
660 | |
661 | SBError SBBreakpoint::AddNameWithErrorHandling(const char *new_name) { |
662 | LLDB_INSTRUMENT_VA(this, new_name); |
663 | |
664 | BreakpointSP bkpt_sp = GetSP(); |
665 | |
666 | SBError status; |
667 | if (bkpt_sp) { |
668 | std::lock_guard<std::recursive_mutex> guard( |
669 | bkpt_sp->GetTarget().GetAPIMutex()); |
670 | Status error; |
671 | bkpt_sp->GetTarget().AddNameToBreakpoint(bp_sp&: bkpt_sp, name: new_name, error); |
672 | status.SetError(error); |
673 | } else { |
674 | status.SetErrorString("invalid breakpoint" ); |
675 | } |
676 | |
677 | return status; |
678 | } |
679 | |
680 | void SBBreakpoint::RemoveName(const char *name_to_remove) { |
681 | LLDB_INSTRUMENT_VA(this, name_to_remove); |
682 | |
683 | BreakpointSP bkpt_sp = GetSP(); |
684 | |
685 | if (bkpt_sp) { |
686 | std::lock_guard<std::recursive_mutex> guard( |
687 | bkpt_sp->GetTarget().GetAPIMutex()); |
688 | bkpt_sp->GetTarget().RemoveNameFromBreakpoint(bp_sp&: bkpt_sp, |
689 | name: ConstString(name_to_remove)); |
690 | } |
691 | } |
692 | |
693 | bool SBBreakpoint::MatchesName(const char *name) { |
694 | LLDB_INSTRUMENT_VA(this, name); |
695 | |
696 | BreakpointSP bkpt_sp = GetSP(); |
697 | |
698 | if (bkpt_sp) { |
699 | std::lock_guard<std::recursive_mutex> guard( |
700 | bkpt_sp->GetTarget().GetAPIMutex()); |
701 | return bkpt_sp->MatchesName(name); |
702 | } |
703 | |
704 | return false; |
705 | } |
706 | |
707 | void SBBreakpoint::GetNames(SBStringList &names) { |
708 | LLDB_INSTRUMENT_VA(this, names); |
709 | |
710 | BreakpointSP bkpt_sp = GetSP(); |
711 | |
712 | if (bkpt_sp) { |
713 | std::lock_guard<std::recursive_mutex> guard( |
714 | bkpt_sp->GetTarget().GetAPIMutex()); |
715 | std::vector<std::string> names_vec; |
716 | bkpt_sp->GetNames(names&: names_vec); |
717 | for (std::string name : names_vec) { |
718 | names.AppendString(str: name.c_str()); |
719 | } |
720 | } |
721 | } |
722 | |
723 | bool SBBreakpoint::EventIsBreakpointEvent(const lldb::SBEvent &event) { |
724 | LLDB_INSTRUMENT_VA(event); |
725 | |
726 | return Breakpoint::BreakpointEventData::GetEventDataFromEvent(event_sp: event.get()) != |
727 | nullptr; |
728 | } |
729 | |
730 | BreakpointEventType |
731 | SBBreakpoint::GetBreakpointEventTypeFromEvent(const SBEvent &event) { |
732 | LLDB_INSTRUMENT_VA(event); |
733 | |
734 | if (event.IsValid()) |
735 | return Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent( |
736 | event_sp: event.GetSP()); |
737 | return eBreakpointEventTypeInvalidType; |
738 | } |
739 | |
740 | SBBreakpoint SBBreakpoint::GetBreakpointFromEvent(const lldb::SBEvent &event) { |
741 | LLDB_INSTRUMENT_VA(event); |
742 | |
743 | if (event.IsValid()) |
744 | return SBBreakpoint( |
745 | Breakpoint::BreakpointEventData::GetBreakpointFromEvent(event_sp: event.GetSP())); |
746 | return SBBreakpoint(); |
747 | } |
748 | |
749 | SBBreakpointLocation |
750 | SBBreakpoint::GetBreakpointLocationAtIndexFromEvent(const lldb::SBEvent &event, |
751 | uint32_t loc_idx) { |
752 | LLDB_INSTRUMENT_VA(event, loc_idx); |
753 | |
754 | SBBreakpointLocation sb_breakpoint_loc; |
755 | if (event.IsValid()) |
756 | sb_breakpoint_loc.SetLocation( |
757 | Breakpoint::BreakpointEventData::GetBreakpointLocationAtIndexFromEvent( |
758 | event_sp: event.GetSP(), loc_idx)); |
759 | return sb_breakpoint_loc; |
760 | } |
761 | |
762 | uint32_t |
763 | SBBreakpoint::GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event) { |
764 | LLDB_INSTRUMENT_VA(event); |
765 | |
766 | uint32_t num_locations = 0; |
767 | if (event.IsValid()) |
768 | num_locations = |
769 | (Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent( |
770 | event_sp: event.GetSP())); |
771 | return num_locations; |
772 | } |
773 | |
774 | bool SBBreakpoint::IsHardware() const { |
775 | LLDB_INSTRUMENT_VA(this); |
776 | |
777 | BreakpointSP bkpt_sp = GetSP(); |
778 | if (bkpt_sp) |
779 | return bkpt_sp->IsHardware(); |
780 | return false; |
781 | } |
782 | |
783 | BreakpointSP SBBreakpoint::GetSP() const { return m_opaque_wp.lock(); } |
784 | |
785 | // This is simple collection of breakpoint id's and their target. |
786 | class SBBreakpointListImpl { |
787 | public: |
788 | SBBreakpointListImpl(lldb::TargetSP target_sp) { |
789 | if (target_sp && target_sp->IsValid()) |
790 | m_target_wp = target_sp; |
791 | } |
792 | |
793 | ~SBBreakpointListImpl() = default; |
794 | |
795 | size_t GetSize() { return m_break_ids.size(); } |
796 | |
797 | BreakpointSP GetBreakpointAtIndex(size_t idx) { |
798 | if (idx >= m_break_ids.size()) |
799 | return BreakpointSP(); |
800 | TargetSP target_sp = m_target_wp.lock(); |
801 | if (!target_sp) |
802 | return BreakpointSP(); |
803 | lldb::break_id_t bp_id = m_break_ids[idx]; |
804 | return target_sp->GetBreakpointList().FindBreakpointByID(breakID: bp_id); |
805 | } |
806 | |
807 | BreakpointSP FindBreakpointByID(lldb::break_id_t desired_id) { |
808 | TargetSP target_sp = m_target_wp.lock(); |
809 | if (!target_sp) |
810 | return BreakpointSP(); |
811 | |
812 | for (lldb::break_id_t &break_id : m_break_ids) { |
813 | if (break_id == desired_id) |
814 | return target_sp->GetBreakpointList().FindBreakpointByID(breakID: break_id); |
815 | } |
816 | return BreakpointSP(); |
817 | } |
818 | |
819 | bool Append(BreakpointSP bkpt) { |
820 | TargetSP target_sp = m_target_wp.lock(); |
821 | if (!target_sp || !bkpt) |
822 | return false; |
823 | if (bkpt->GetTargetSP() != target_sp) |
824 | return false; |
825 | m_break_ids.push_back(x: bkpt->GetID()); |
826 | return true; |
827 | } |
828 | |
829 | bool AppendIfUnique(BreakpointSP bkpt) { |
830 | TargetSP target_sp = m_target_wp.lock(); |
831 | if (!target_sp || !bkpt) |
832 | return false; |
833 | if (bkpt->GetTargetSP() != target_sp) |
834 | return false; |
835 | lldb::break_id_t bp_id = bkpt->GetID(); |
836 | if (!llvm::is_contained(Range&: m_break_ids, Element: bp_id)) |
837 | return false; |
838 | |
839 | m_break_ids.push_back(x: bkpt->GetID()); |
840 | return true; |
841 | } |
842 | |
843 | bool AppendByID(lldb::break_id_t id) { |
844 | TargetSP target_sp = m_target_wp.lock(); |
845 | if (!target_sp) |
846 | return false; |
847 | if (id == LLDB_INVALID_BREAK_ID) |
848 | return false; |
849 | m_break_ids.push_back(x: id); |
850 | return true; |
851 | } |
852 | |
853 | void Clear() { m_break_ids.clear(); } |
854 | |
855 | void CopyToBreakpointIDList(lldb_private::BreakpointIDList &bp_list) { |
856 | for (lldb::break_id_t id : m_break_ids) { |
857 | bp_list.AddBreakpointID(bp_id: BreakpointID(id)); |
858 | } |
859 | } |
860 | |
861 | TargetSP GetTarget() { return m_target_wp.lock(); } |
862 | |
863 | private: |
864 | std::vector<lldb::break_id_t> m_break_ids; |
865 | TargetWP m_target_wp; |
866 | }; |
867 | |
868 | SBBreakpointList::SBBreakpointList(SBTarget &target) |
869 | : m_opaque_sp(new SBBreakpointListImpl(target.GetSP())) { |
870 | LLDB_INSTRUMENT_VA(this, target); |
871 | } |
872 | |
873 | SBBreakpointList::~SBBreakpointList() = default; |
874 | |
875 | size_t SBBreakpointList::GetSize() const { |
876 | LLDB_INSTRUMENT_VA(this); |
877 | |
878 | if (!m_opaque_sp) |
879 | return 0; |
880 | else |
881 | return m_opaque_sp->GetSize(); |
882 | } |
883 | |
884 | SBBreakpoint SBBreakpointList::GetBreakpointAtIndex(size_t idx) { |
885 | LLDB_INSTRUMENT_VA(this, idx); |
886 | |
887 | if (!m_opaque_sp) |
888 | return SBBreakpoint(); |
889 | |
890 | BreakpointSP bkpt_sp = m_opaque_sp->GetBreakpointAtIndex(idx); |
891 | return SBBreakpoint(bkpt_sp); |
892 | } |
893 | |
894 | SBBreakpoint SBBreakpointList::FindBreakpointByID(lldb::break_id_t id) { |
895 | LLDB_INSTRUMENT_VA(this, id); |
896 | |
897 | if (!m_opaque_sp) |
898 | return SBBreakpoint(); |
899 | BreakpointSP bkpt_sp = m_opaque_sp->FindBreakpointByID(desired_id: id); |
900 | return SBBreakpoint(bkpt_sp); |
901 | } |
902 | |
903 | void SBBreakpointList::Append(const SBBreakpoint &sb_bkpt) { |
904 | LLDB_INSTRUMENT_VA(this, sb_bkpt); |
905 | |
906 | if (!sb_bkpt.IsValid()) |
907 | return; |
908 | if (!m_opaque_sp) |
909 | return; |
910 | m_opaque_sp->Append(bkpt: sb_bkpt.m_opaque_wp.lock()); |
911 | } |
912 | |
913 | void SBBreakpointList::AppendByID(lldb::break_id_t id) { |
914 | LLDB_INSTRUMENT_VA(this, id); |
915 | |
916 | if (!m_opaque_sp) |
917 | return; |
918 | m_opaque_sp->AppendByID(id); |
919 | } |
920 | |
921 | bool SBBreakpointList::AppendIfUnique(const SBBreakpoint &sb_bkpt) { |
922 | LLDB_INSTRUMENT_VA(this, sb_bkpt); |
923 | |
924 | if (!sb_bkpt.IsValid()) |
925 | return false; |
926 | if (!m_opaque_sp) |
927 | return false; |
928 | return m_opaque_sp->AppendIfUnique(bkpt: sb_bkpt.GetSP()); |
929 | } |
930 | |
931 | void SBBreakpointList::Clear() { |
932 | LLDB_INSTRUMENT_VA(this); |
933 | |
934 | if (m_opaque_sp) |
935 | m_opaque_sp->Clear(); |
936 | } |
937 | |
938 | void SBBreakpointList::CopyToBreakpointIDList( |
939 | lldb_private::BreakpointIDList &bp_id_list) { |
940 | if (m_opaque_sp) |
941 | m_opaque_sp->CopyToBreakpointIDList(bp_list&: bp_id_list); |
942 | } |
943 | |