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