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