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