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