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