1 //===-- Breakpoint.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 
11 // C Includes
12 // C++ Includes
13 // Other libraries and framework includes
14 // Project includes
15 
16 #include "lldb/Core/Address.h"
17 #include "lldb/Breakpoint/Breakpoint.h"
18 #include "lldb/Breakpoint/BreakpointLocation.h"
19 #include "lldb/Breakpoint/BreakpointLocationCollection.h"
20 #include "lldb/Breakpoint/BreakpointResolver.h"
21 #include "lldb/Breakpoint/BreakpointResolverFileLine.h"
22 #include "lldb/Core/Log.h"
23 #include "lldb/Core/ModuleList.h"
24 #include "lldb/Core/SearchFilter.h"
25 #include "lldb/Core/Section.h"
26 #include "lldb/Core/Stream.h"
27 #include "lldb/Core/StreamString.h"
28 #include "lldb/Symbol/SymbolContext.h"
29 #include "lldb/Target/Target.h"
30 #include "lldb/Target/ThreadSpec.h"
31 #include "lldb/lldb-private-log.h"
32 #include "llvm/Support/Casting.h"
33 
34 using namespace lldb;
35 using namespace lldb_private;
36 using namespace llvm;
37 
38 const ConstString &
39 Breakpoint::GetEventIdentifier ()
40 {
41     static ConstString g_identifier("event-identifier.breakpoint.changed");
42     return g_identifier;
43 }
44 
45 //----------------------------------------------------------------------
46 // Breakpoint constructor
47 //----------------------------------------------------------------------
48 Breakpoint::Breakpoint(Target &target, SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool hardware) :
49     m_being_created(true),
50     m_hardware(hardware),
51     m_target (target),
52     m_filter_sp (filter_sp),
53     m_resolver_sp (resolver_sp),
54     m_options (),
55     m_locations (*this)
56 {
57     m_being_created = false;
58 }
59 
60 //----------------------------------------------------------------------
61 // Destructor
62 //----------------------------------------------------------------------
63 Breakpoint::~Breakpoint()
64 {
65 }
66 
67 bool
68 Breakpoint::IsInternal () const
69 {
70     return LLDB_BREAK_ID_IS_INTERNAL(m_bid);
71 }
72 
73 
74 
75 Target&
76 Breakpoint::GetTarget ()
77 {
78     return m_target;
79 }
80 
81 const Target&
82 Breakpoint::GetTarget () const
83 {
84     return m_target;
85 }
86 
87 BreakpointLocationSP
88 Breakpoint::AddLocation (const Address &addr, bool *new_location)
89 {
90     return m_locations.AddLocation (addr, new_location);
91 }
92 
93 BreakpointLocationSP
94 Breakpoint::FindLocationByAddress (const Address &addr)
95 {
96     return m_locations.FindByAddress(addr);
97 }
98 
99 break_id_t
100 Breakpoint::FindLocationIDByAddress (const Address &addr)
101 {
102     return m_locations.FindIDByAddress(addr);
103 }
104 
105 BreakpointLocationSP
106 Breakpoint::FindLocationByID (break_id_t bp_loc_id)
107 {
108     return m_locations.FindByID(bp_loc_id);
109 }
110 
111 BreakpointLocationSP
112 Breakpoint::GetLocationAtIndex (size_t index)
113 {
114     return m_locations.GetByIndex(index);
115 }
116 
117 void
118 Breakpoint::RemoveInvalidLocations (const ArchSpec &arch)
119 {
120     m_locations.RemoveInvalidLocations(arch);
121 }
122 
123 // For each of the overall options we need to decide how they propagate to
124 // the location options.  This will determine the precedence of options on
125 // the breakpoint vs. its locations.
126 
127 // Disable at the breakpoint level should override the location settings.
128 // That way you can conveniently turn off a whole breakpoint without messing
129 // up the individual settings.
130 
131 void
132 Breakpoint::SetEnabled (bool enable)
133 {
134     if (enable == m_options.IsEnabled())
135         return;
136 
137     m_options.SetEnabled(enable);
138     if (enable)
139         m_locations.ResolveAllBreakpointSites();
140     else
141         m_locations.ClearAllBreakpointSites();
142 
143     SendBreakpointChangedEvent (enable ? eBreakpointEventTypeEnabled : eBreakpointEventTypeDisabled);
144 
145 }
146 
147 bool
148 Breakpoint::IsEnabled ()
149 {
150     return m_options.IsEnabled();
151 }
152 
153 void
154 Breakpoint::SetIgnoreCount (uint32_t n)
155 {
156     if (m_options.GetIgnoreCount() == n)
157         return;
158 
159     m_options.SetIgnoreCount(n);
160     SendBreakpointChangedEvent (eBreakpointEventTypeIgnoreChanged);
161 }
162 
163 void
164 Breakpoint::DecrementIgnoreCount ()
165 {
166     uint32_t ignore = m_options.GetIgnoreCount();
167     if (ignore != 0)
168         m_options.SetIgnoreCount(ignore - 1);
169 }
170 
171 uint32_t
172 Breakpoint::GetIgnoreCount () const
173 {
174     return m_options.GetIgnoreCount();
175 }
176 
177 bool
178 Breakpoint::IgnoreCountShouldStop ()
179 {
180     uint32_t ignore = GetIgnoreCount();
181     if (ignore != 0)
182     {
183         // When we get here we know the location that caused the stop doesn't have an ignore count,
184         // since by contract we call it first...  So we don't have to find & decrement it, we only have
185         // to decrement our own ignore count.
186         DecrementIgnoreCount();
187         return false;
188     }
189     else
190         return true;
191 }
192 
193 uint32_t
194 Breakpoint::GetHitCount () const
195 {
196     return m_locations.GetHitCount();
197 }
198 
199 bool
200 Breakpoint::IsOneShot () const
201 {
202     return m_options.IsOneShot();
203 }
204 
205 void
206 Breakpoint::SetOneShot (bool one_shot)
207 {
208     m_options.SetOneShot (one_shot);
209 }
210 
211 void
212 Breakpoint::SetThreadID (lldb::tid_t thread_id)
213 {
214     if (m_options.GetThreadSpec()->GetTID() == thread_id)
215         return;
216 
217     m_options.GetThreadSpec()->SetTID(thread_id);
218     SendBreakpointChangedEvent (eBreakpointEventTypeThreadChanged);
219 }
220 
221 lldb::tid_t
222 Breakpoint::GetThreadID () const
223 {
224     if (m_options.GetThreadSpecNoCreate() == NULL)
225         return LLDB_INVALID_THREAD_ID;
226     else
227         return m_options.GetThreadSpecNoCreate()->GetTID();
228 }
229 
230 void
231 Breakpoint::SetThreadIndex (uint32_t index)
232 {
233     if (m_options.GetThreadSpec()->GetIndex() == index)
234         return;
235 
236     m_options.GetThreadSpec()->SetIndex(index);
237     SendBreakpointChangedEvent (eBreakpointEventTypeThreadChanged);
238 }
239 
240 uint32_t
241 Breakpoint::GetThreadIndex() const
242 {
243     if (m_options.GetThreadSpecNoCreate() == NULL)
244         return 0;
245     else
246         return m_options.GetThreadSpecNoCreate()->GetIndex();
247 }
248 
249 void
250 Breakpoint::SetThreadName (const char *thread_name)
251 {
252     if (m_options.GetThreadSpec()->GetName() != NULL
253         && ::strcmp (m_options.GetThreadSpec()->GetName(), thread_name) == 0)
254         return;
255 
256     m_options.GetThreadSpec()->SetName (thread_name);
257     SendBreakpointChangedEvent (eBreakpointEventTypeThreadChanged);
258 }
259 
260 const char *
261 Breakpoint::GetThreadName () const
262 {
263     if (m_options.GetThreadSpecNoCreate() == NULL)
264         return NULL;
265     else
266         return m_options.GetThreadSpecNoCreate()->GetName();
267 }
268 
269 void
270 Breakpoint::SetQueueName (const char *queue_name)
271 {
272     if (m_options.GetThreadSpec()->GetQueueName() != NULL
273         && ::strcmp (m_options.GetThreadSpec()->GetQueueName(), queue_name) == 0)
274         return;
275 
276     m_options.GetThreadSpec()->SetQueueName (queue_name);
277     SendBreakpointChangedEvent (eBreakpointEventTypeThreadChanged);
278 }
279 
280 const char *
281 Breakpoint::GetQueueName () const
282 {
283     if (m_options.GetThreadSpecNoCreate() == NULL)
284         return NULL;
285     else
286         return m_options.GetThreadSpecNoCreate()->GetQueueName();
287 }
288 
289 void
290 Breakpoint::SetCondition (const char *condition)
291 {
292     m_options.SetCondition (condition);
293     SendBreakpointChangedEvent (eBreakpointEventTypeConditionChanged);
294 }
295 
296 const char *
297 Breakpoint::GetConditionText () const
298 {
299     return m_options.GetConditionText();
300 }
301 
302 // This function is used when "baton" doesn't need to be freed
303 void
304 Breakpoint::SetCallback (BreakpointHitCallback callback, void *baton, bool is_synchronous)
305 {
306     // The default "Baton" class will keep a copy of "baton" and won't free
307     // or delete it when it goes goes out of scope.
308     m_options.SetCallback(callback, BatonSP (new Baton(baton)), is_synchronous);
309 
310     SendBreakpointChangedEvent (eBreakpointEventTypeCommandChanged);
311 }
312 
313 // This function is used when a baton needs to be freed and therefore is
314 // contained in a "Baton" subclass.
315 void
316 Breakpoint::SetCallback (BreakpointHitCallback callback, const BatonSP &callback_baton_sp, bool is_synchronous)
317 {
318     m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
319 }
320 
321 void
322 Breakpoint::ClearCallback ()
323 {
324     m_options.ClearCallback ();
325 }
326 
327 bool
328 Breakpoint::InvokeCallback (StoppointCallbackContext *context, break_id_t bp_loc_id)
329 {
330     return m_options.InvokeCallback (context, GetID(), bp_loc_id);
331 }
332 
333 BreakpointOptions *
334 Breakpoint::GetOptions ()
335 {
336     return &m_options;
337 }
338 
339 void
340 Breakpoint::ResolveBreakpoint ()
341 {
342     if (m_resolver_sp)
343         m_resolver_sp->ResolveBreakpoint(*m_filter_sp);
344 }
345 
346 void
347 Breakpoint::ResolveBreakpointInModules (ModuleList &module_list)
348 {
349     if (m_resolver_sp)
350         m_resolver_sp->ResolveBreakpointInModules(*m_filter_sp, module_list);
351 }
352 
353 void
354 Breakpoint::ClearAllBreakpointSites ()
355 {
356     m_locations.ClearAllBreakpointSites();
357 }
358 
359 //----------------------------------------------------------------------
360 // ModulesChanged: Pass in a list of new modules, and
361 //----------------------------------------------------------------------
362 
363 void
364 Breakpoint::ModulesChanged (ModuleList &module_list, bool load, bool delete_locations)
365 {
366     Mutex::Locker modules_mutex(module_list.GetMutex());
367     if (load)
368     {
369         // The logic for handling new modules is:
370         // 1) If the filter rejects this module, then skip it.
371         // 2) Run through the current location list and if there are any locations
372         //    for that module, we mark the module as "seen" and we don't try to re-resolve
373         //    breakpoint locations for that module.
374         //    However, we do add breakpoint sites to these locations if needed.
375         // 3) If we don't see this module in our breakpoint location list, call ResolveInModules.
376 
377         ModuleList new_modules;  // We'll stuff the "unseen" modules in this list, and then resolve
378                                  // them after the locations pass.  Have to do it this way because
379                                  // resolving breakpoints will add new locations potentially.
380 
381         const size_t num_locs = m_locations.GetSize();
382         size_t num_modules = module_list.GetSize();
383         for (size_t i = 0; i < num_modules; i++)
384         {
385             bool seen = false;
386             ModuleSP module_sp (module_list.GetModuleAtIndexUnlocked (i));
387             if (!m_filter_sp->ModulePasses (module_sp))
388                 continue;
389 
390             for (size_t loc_idx = 0; loc_idx < num_locs; loc_idx++)
391             {
392                 BreakpointLocationSP break_loc = m_locations.GetByIndex(loc_idx);
393                 if (!break_loc->IsEnabled())
394                     continue;
395                 SectionSP section_sp (break_loc->GetAddress().GetSection());
396                 if (!section_sp || section_sp->GetModule() == module_sp)
397                 {
398                     if (!seen)
399                         seen = true;
400 
401                     if (!break_loc->ResolveBreakpointSite())
402                     {
403                         Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
404                         if (log)
405                             log->Printf ("Warning: could not set breakpoint site for breakpoint location %d of breakpoint %d.\n",
406                                          break_loc->GetID(), GetID());
407                     }
408                 }
409             }
410 
411             if (!seen)
412                 new_modules.AppendIfNeeded (module_sp);
413 
414         }
415 
416         if (new_modules.GetSize() > 0)
417         {
418             // If this is not an internal breakpoint, set up to record the new locations, then dispatch
419             // an event with the new locations.
420             if (!IsInternal())
421             {
422                 BreakpointEventData *new_locations_event = new BreakpointEventData (eBreakpointEventTypeLocationsAdded,
423                                                                                     shared_from_this());
424 
425                 m_locations.StartRecordingNewLocations(new_locations_event->GetBreakpointLocationCollection());
426 
427                 ResolveBreakpointInModules(new_modules);
428 
429                 m_locations.StopRecordingNewLocations();
430                 if (new_locations_event->GetBreakpointLocationCollection().GetSize() != 0)
431                 {
432                     SendBreakpointChangedEvent (new_locations_event);
433                 }
434                 else
435                     delete new_locations_event;
436             }
437             else
438                 ResolveBreakpointInModules(new_modules);
439 
440         }
441     }
442     else
443     {
444         // Go through the currently set locations and if any have breakpoints in
445         // the module list, then remove their breakpoint sites, and their locations if asked to.
446 
447         BreakpointEventData *removed_locations_event;
448         if (!IsInternal())
449             removed_locations_event = new BreakpointEventData (eBreakpointEventTypeLocationsRemoved,
450                                                                shared_from_this());
451         else
452             removed_locations_event = NULL;
453 
454         size_t num_modules = module_list.GetSize();
455         for (size_t i = 0; i < num_modules; i++)
456         {
457             ModuleSP module_sp (module_list.GetModuleAtIndexUnlocked (i));
458             if (m_filter_sp->ModulePasses (module_sp))
459             {
460                 size_t loc_idx = 0;
461                 size_t num_locations = m_locations.GetSize();
462                 BreakpointLocationCollection locations_to_remove;
463                 for (loc_idx = 0; loc_idx < num_locations; loc_idx++)
464                 {
465                     BreakpointLocationSP break_loc_sp (m_locations.GetByIndex(loc_idx));
466                     SectionSP section_sp (break_loc_sp->GetAddress().GetSection());
467                     if (section_sp && section_sp->GetModule() == module_sp)
468                     {
469                         // Remove this breakpoint since the shared library is
470                         // unloaded, but keep the breakpoint location around
471                         // so we always get complete hit count and breakpoint
472                         // lifetime info
473                         break_loc_sp->ClearBreakpointSite();
474                         if (removed_locations_event)
475                         {
476                             removed_locations_event->GetBreakpointLocationCollection().Add(break_loc_sp);
477                         }
478                         if (delete_locations)
479                             locations_to_remove.Add (break_loc_sp);
480 
481                     }
482                 }
483 
484                 if (delete_locations)
485                 {
486                     size_t num_locations_to_remove = locations_to_remove.GetSize();
487                     for (loc_idx = 0; loc_idx < num_locations_to_remove; loc_idx++)
488                         m_locations.RemoveLocation  (locations_to_remove.GetByIndex(loc_idx));
489                 }
490             }
491         }
492         SendBreakpointChangedEvent (removed_locations_event);
493     }
494 }
495 
496 void
497 Breakpoint::ModuleReplaced (ModuleSP old_module_sp, ModuleSP new_module_sp)
498 {
499     ModuleList temp_list;
500     temp_list.Append (new_module_sp);
501     ModulesChanged (temp_list, true);
502 
503     // TO DO: For now I'm just adding locations for the new module and removing the
504     // breakpoint locations that were in the old module.
505     // We should really go find the ones that are in the new module & if we can determine that they are "equivalent"
506     // carry over the options from the old location to the new.
507 
508     temp_list.Clear();
509     temp_list.Append (old_module_sp);
510     ModulesChanged (temp_list, false, true);
511 }
512 
513 void
514 Breakpoint::Dump (Stream *)
515 {
516 }
517 
518 size_t
519 Breakpoint::GetNumResolvedLocations() const
520 {
521     // Return the number of breakpoints that are actually resolved and set
522     // down in the inferior process.
523     return m_locations.GetNumResolvedLocations();
524 }
525 
526 size_t
527 Breakpoint::GetNumLocations() const
528 {
529     return m_locations.GetSize();
530 }
531 
532 void
533 Breakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_locations)
534 {
535     assert (s != NULL);
536 
537     if (!m_kind_description.empty())
538     {
539         if (eDescriptionLevelBrief)
540         {
541             s->PutCString (GetBreakpointKind());
542             return;
543         }
544         else
545             s->Printf("Kind: %s\n", GetBreakpointKind ());
546     }
547 
548     const size_t num_locations = GetNumLocations ();
549     const size_t num_resolved_locations = GetNumResolvedLocations ();
550 
551     // They just made the breakpoint, they don't need to be told HOW they made it...
552     // Also, we'll print the breakpoint number differently depending on whether there is 1 or more locations.
553     if (level != eDescriptionLevelInitial)
554     {
555         s->Printf("%i: ", GetID());
556         GetResolverDescription (s);
557         GetFilterDescription (s);
558     }
559 
560     switch (level)
561     {
562     case lldb::eDescriptionLevelBrief:
563     case lldb::eDescriptionLevelFull:
564         if (num_locations > 0)
565         {
566             s->Printf(", locations = %" PRIu64, (uint64_t)num_locations);
567             if (num_resolved_locations > 0)
568                 s->Printf(", resolved = %" PRIu64 ", hit count = %d", (uint64_t)num_resolved_locations, GetHitCount());
569         }
570         else
571         {
572             // Don't print the pending notification for exception resolvers since we don't generally
573             // know how to set them until the target is run.
574             if (m_resolver_sp->getResolverID() != BreakpointResolver::ExceptionResolver)
575                 s->Printf(", locations = 0 (pending)");
576         }
577 
578         GetOptions()->GetDescription(s, level);
579 
580         if (level == lldb::eDescriptionLevelFull)
581         {
582             s->IndentLess();
583             s->EOL();
584         }
585         break;
586 
587     case lldb::eDescriptionLevelInitial:
588         s->Printf ("Breakpoint %i: ", GetID());
589         if (num_locations == 0)
590         {
591             s->Printf ("no locations (pending).");
592         }
593         else if (num_locations == 1)
594         {
595             // If there is one location only, we'll just print that location information.  But don't do this if
596             // show locations is true, then that will be handled below.
597             if (show_locations == false)
598             {
599                 GetLocationAtIndex(0)->GetDescription(s, level);
600             }
601             else
602             {
603                 s->Printf ("%zd locations.", num_locations);
604             }
605         }
606         else
607         {
608             s->Printf ("%zd locations.", num_locations);
609         }
610         s->EOL();
611         break;
612     case lldb::eDescriptionLevelVerbose:
613         // Verbose mode does a debug dump of the breakpoint
614         Dump (s);
615         s->EOL ();
616             //s->Indent();
617         GetOptions()->GetDescription(s, level);
618         break;
619 
620     default:
621         break;
622     }
623 
624     // The brief description is just the location name (1.2 or whatever).  That's pointless to
625     // show in the breakpoint's description, so suppress it.
626     if (show_locations && level != lldb::eDescriptionLevelBrief)
627     {
628         s->IndentMore();
629         for (size_t i = 0; i < num_locations; ++i)
630         {
631             BreakpointLocation *loc = GetLocationAtIndex(i).get();
632             loc->GetDescription(s, level);
633             s->EOL();
634         }
635         s->IndentLess();
636     }
637 }
638 
639 void
640 Breakpoint::GetResolverDescription (Stream *s)
641 {
642     if (m_resolver_sp)
643         m_resolver_sp->GetDescription (s);
644 }
645 
646 
647 bool
648 Breakpoint::GetMatchingFileLine (const ConstString &filename, uint32_t line_number, BreakpointLocationCollection &loc_coll)
649 {
650     // TODO: To be correct, this method needs to fill the breakpoint location collection
651     //       with the location IDs which match the filename and line_number.
652     //
653 
654     if (m_resolver_sp)
655     {
656         BreakpointResolverFileLine *resolverFileLine = dyn_cast<BreakpointResolverFileLine>(m_resolver_sp.get());
657         if (resolverFileLine &&
658             resolverFileLine->m_file_spec.GetFilename() == filename &&
659             resolverFileLine->m_line_number == line_number)
660         {
661             return true;
662         }
663     }
664     return false;
665 }
666 
667 void
668 Breakpoint::GetFilterDescription (Stream *s)
669 {
670     m_filter_sp->GetDescription (s);
671 }
672 
673 void
674 Breakpoint::SendBreakpointChangedEvent (lldb::BreakpointEventType eventKind)
675 {
676     if (!m_being_created
677         && !IsInternal()
678         && GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
679     {
680         BreakpointEventData *data = new Breakpoint::BreakpointEventData (eventKind, shared_from_this());
681 
682         GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged, data);
683     }
684 }
685 
686 void
687 Breakpoint::SendBreakpointChangedEvent (BreakpointEventData *data)
688 {
689 
690     if (data == NULL)
691         return;
692 
693     if (!m_being_created
694         && !IsInternal()
695         && GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
696         GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged, data);
697     else
698         delete data;
699 }
700 
701 Breakpoint::BreakpointEventData::BreakpointEventData (BreakpointEventType sub_type,
702                                                       const BreakpointSP &new_breakpoint_sp) :
703     EventData (),
704     m_breakpoint_event (sub_type),
705     m_new_breakpoint_sp (new_breakpoint_sp)
706 {
707 }
708 
709 Breakpoint::BreakpointEventData::~BreakpointEventData ()
710 {
711 }
712 
713 const ConstString &
714 Breakpoint::BreakpointEventData::GetFlavorString ()
715 {
716     static ConstString g_flavor ("Breakpoint::BreakpointEventData");
717     return g_flavor;
718 }
719 
720 const ConstString &
721 Breakpoint::BreakpointEventData::GetFlavor () const
722 {
723     return BreakpointEventData::GetFlavorString ();
724 }
725 
726 
727 BreakpointSP &
728 Breakpoint::BreakpointEventData::GetBreakpoint ()
729 {
730     return m_new_breakpoint_sp;
731 }
732 
733 BreakpointEventType
734 Breakpoint::BreakpointEventData::GetBreakpointEventType () const
735 {
736     return m_breakpoint_event;
737 }
738 
739 void
740 Breakpoint::BreakpointEventData::Dump (Stream *s) const
741 {
742 }
743 
744 const Breakpoint::BreakpointEventData *
745 Breakpoint::BreakpointEventData::GetEventDataFromEvent (const Event *event)
746 {
747     if (event)
748     {
749         const EventData *event_data = event->GetData();
750         if (event_data && event_data->GetFlavor() == BreakpointEventData::GetFlavorString())
751             return static_cast <const BreakpointEventData *> (event->GetData());
752     }
753     return NULL;
754 }
755 
756 BreakpointEventType
757 Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent (const EventSP &event_sp)
758 {
759     const BreakpointEventData *data = GetEventDataFromEvent (event_sp.get());
760 
761     if (data == NULL)
762         return eBreakpointEventTypeInvalidType;
763     else
764         return data->GetBreakpointEventType();
765 }
766 
767 BreakpointSP
768 Breakpoint::BreakpointEventData::GetBreakpointFromEvent (const EventSP &event_sp)
769 {
770     BreakpointSP bp_sp;
771 
772     const BreakpointEventData *data = GetEventDataFromEvent (event_sp.get());
773     if (data)
774         bp_sp = data->m_new_breakpoint_sp;
775 
776     return bp_sp;
777 }
778 
779 size_t
780 Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent (const EventSP &event_sp)
781 {
782     const BreakpointEventData *data = GetEventDataFromEvent (event_sp.get());
783     if (data)
784         return data->m_locations.GetSize();
785 
786     return 0;
787 }
788 
789 lldb::BreakpointLocationSP
790 Breakpoint::BreakpointEventData::GetBreakpointLocationAtIndexFromEvent (const lldb::EventSP &event_sp, uint32_t bp_loc_idx)
791 {
792     lldb::BreakpointLocationSP bp_loc_sp;
793 
794     const BreakpointEventData *data = GetEventDataFromEvent (event_sp.get());
795     if (data)
796     {
797         bp_loc_sp = data->m_locations.GetByIndex(bp_loc_idx);
798     }
799 
800     return bp_loc_sp;
801 }
802