1 //===-- BreakpointLocation.cpp ----------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 // C Includes 11 // C++ Includes 12 // Other libraries and framework includes 13 // Project includes 14 #include "lldb/Breakpoint/BreakpointLocation.h" 15 #include "lldb/Breakpoint/BreakpointID.h" 16 #include "lldb/Breakpoint/StoppointCallbackContext.h" 17 #include "lldb/Core/Debugger.h" 18 #include "lldb/Core/Log.h" 19 #include "lldb/Core/Module.h" 20 #include "lldb/Core/StreamString.h" 21 #include "lldb/Core/ValueObject.h" 22 #include "lldb/Expression/DiagnosticManager.h" 23 #include "lldb/Expression/ExpressionVariable.h" 24 #include "lldb/Expression/UserExpression.h" 25 #include "lldb/Symbol/CompileUnit.h" 26 #include "lldb/Symbol/Symbol.h" 27 #include "lldb/Symbol/TypeSystem.h" 28 #include "lldb/Target/Target.h" 29 #include "lldb/Target/Process.h" 30 #include "lldb/Target/Thread.h" 31 #include "lldb/Target/ThreadSpec.h" 32 33 using namespace lldb; 34 using namespace lldb_private; 35 36 BreakpointLocation::BreakpointLocation(break_id_t loc_id, Breakpoint &owner, const Address &addr, lldb::tid_t tid, 37 bool hardware, bool check_for_resolver) 38 : StoppointLocation(loc_id, addr.GetOpcodeLoadAddress(&owner.GetTarget()), hardware), 39 m_being_created(true), 40 m_should_resolve_indirect_functions(false), 41 m_is_reexported(false), 42 m_is_indirect(false), 43 m_address(addr), 44 m_owner(owner), 45 m_options_ap(), 46 m_bp_site_sp(), 47 m_condition_mutex() 48 { 49 if (check_for_resolver) 50 { 51 Symbol *symbol = m_address.CalculateSymbolContextSymbol(); 52 if (symbol && symbol->IsIndirect()) 53 { 54 SetShouldResolveIndirectFunctions(true); 55 } 56 } 57 58 SetThreadID(tid); 59 m_being_created = false; 60 } 61 62 BreakpointLocation::~BreakpointLocation() 63 { 64 ClearBreakpointSite(); 65 } 66 67 lldb::addr_t 68 BreakpointLocation::GetLoadAddress () const 69 { 70 return m_address.GetOpcodeLoadAddress (&m_owner.GetTarget()); 71 } 72 73 Address & 74 BreakpointLocation::GetAddress () 75 { 76 return m_address; 77 } 78 79 Breakpoint & 80 BreakpointLocation::GetBreakpoint () 81 { 82 return m_owner; 83 } 84 85 Target & 86 BreakpointLocation::GetTarget() 87 { 88 return m_owner.GetTarget(); 89 } 90 91 bool 92 BreakpointLocation::IsEnabled () const 93 { 94 if (!m_owner.IsEnabled()) 95 return false; 96 else if (m_options_ap.get() != nullptr) 97 return m_options_ap->IsEnabled(); 98 else 99 return true; 100 } 101 102 void 103 BreakpointLocation::SetEnabled (bool enabled) 104 { 105 GetLocationOptions()->SetEnabled(enabled); 106 if (enabled) 107 { 108 ResolveBreakpointSite(); 109 } 110 else 111 { 112 ClearBreakpointSite(); 113 } 114 SendBreakpointLocationChangedEvent (enabled ? eBreakpointEventTypeEnabled : eBreakpointEventTypeDisabled); 115 } 116 117 void 118 BreakpointLocation::SetThreadID (lldb::tid_t thread_id) 119 { 120 if (thread_id != LLDB_INVALID_THREAD_ID) 121 GetLocationOptions()->SetThreadID(thread_id); 122 else 123 { 124 // If we're resetting this to an invalid thread id, then 125 // don't make an options pointer just to do that. 126 if (m_options_ap.get() != nullptr) 127 m_options_ap->SetThreadID (thread_id); 128 } 129 SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged); 130 } 131 132 lldb::tid_t 133 BreakpointLocation::GetThreadID () 134 { 135 if (GetOptionsNoCreate()->GetThreadSpecNoCreate()) 136 return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetTID(); 137 else 138 return LLDB_INVALID_THREAD_ID; 139 } 140 141 void 142 BreakpointLocation::SetThreadIndex (uint32_t index) 143 { 144 if (index != 0) 145 GetLocationOptions()->GetThreadSpec()->SetIndex(index); 146 else 147 { 148 // If we're resetting this to an invalid thread id, then 149 // don't make an options pointer just to do that. 150 if (m_options_ap.get() != nullptr) 151 m_options_ap->GetThreadSpec()->SetIndex(index); 152 } 153 SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged); 154 } 155 156 uint32_t 157 BreakpointLocation::GetThreadIndex() const 158 { 159 if (GetOptionsNoCreate()->GetThreadSpecNoCreate()) 160 return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetIndex(); 161 else 162 return 0; 163 } 164 165 void 166 BreakpointLocation::SetThreadName (const char *thread_name) 167 { 168 if (thread_name != nullptr) 169 GetLocationOptions()->GetThreadSpec()->SetName(thread_name); 170 else 171 { 172 // If we're resetting this to an invalid thread id, then 173 // don't make an options pointer just to do that. 174 if (m_options_ap.get() != nullptr) 175 m_options_ap->GetThreadSpec()->SetName(thread_name); 176 } 177 SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged); 178 } 179 180 const char * 181 BreakpointLocation::GetThreadName () const 182 { 183 if (GetOptionsNoCreate()->GetThreadSpecNoCreate()) 184 return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetName(); 185 else 186 return nullptr; 187 } 188 189 void 190 BreakpointLocation::SetQueueName (const char *queue_name) 191 { 192 if (queue_name != nullptr) 193 GetLocationOptions()->GetThreadSpec()->SetQueueName(queue_name); 194 else 195 { 196 // If we're resetting this to an invalid thread id, then 197 // don't make an options pointer just to do that. 198 if (m_options_ap.get() != nullptr) 199 m_options_ap->GetThreadSpec()->SetQueueName(queue_name); 200 } 201 SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged); 202 } 203 204 const char * 205 BreakpointLocation::GetQueueName () const 206 { 207 if (GetOptionsNoCreate()->GetThreadSpecNoCreate()) 208 return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetQueueName(); 209 else 210 return nullptr; 211 } 212 213 bool 214 BreakpointLocation::InvokeCallback (StoppointCallbackContext *context) 215 { 216 if (m_options_ap.get() != nullptr && m_options_ap->HasCallback()) 217 return m_options_ap->InvokeCallback (context, m_owner.GetID(), GetID()); 218 else 219 return m_owner.InvokeCallback (context, GetID()); 220 } 221 222 void 223 BreakpointLocation::SetCallback (BreakpointHitCallback callback, void *baton, 224 bool is_synchronous) 225 { 226 // The default "Baton" class will keep a copy of "baton" and won't free 227 // or delete it when it goes goes out of scope. 228 GetLocationOptions()->SetCallback(callback, BatonSP (new Baton(baton)), is_synchronous); 229 SendBreakpointLocationChangedEvent (eBreakpointEventTypeCommandChanged); 230 } 231 232 void 233 BreakpointLocation::SetCallback (BreakpointHitCallback callback, const BatonSP &baton_sp, 234 bool is_synchronous) 235 { 236 GetLocationOptions()->SetCallback (callback, baton_sp, is_synchronous); 237 SendBreakpointLocationChangedEvent (eBreakpointEventTypeCommandChanged); 238 } 239 240 void 241 BreakpointLocation::ClearCallback () 242 { 243 GetLocationOptions()->ClearCallback(); 244 } 245 246 void 247 BreakpointLocation::SetCondition (const char *condition) 248 { 249 GetLocationOptions()->SetCondition (condition); 250 SendBreakpointLocationChangedEvent (eBreakpointEventTypeConditionChanged); 251 } 252 253 const char * 254 BreakpointLocation::GetConditionText (size_t *hash) const 255 { 256 return GetOptionsNoCreate()->GetConditionText(hash); 257 } 258 259 bool 260 BreakpointLocation::ConditionSaysStop (ExecutionContext &exe_ctx, Error &error) 261 { 262 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS); 263 264 std::lock_guard<std::mutex> guard(m_condition_mutex); 265 266 size_t condition_hash; 267 const char *condition_text = GetConditionText(&condition_hash); 268 269 if (!condition_text) 270 { 271 m_user_expression_sp.reset(); 272 return false; 273 } 274 275 error.Clear(); 276 277 DiagnosticManager diagnostics; 278 279 if (condition_hash != m_condition_hash || !m_user_expression_sp || !m_user_expression_sp->MatchesContext(exe_ctx)) 280 { 281 LanguageType language = eLanguageTypeUnknown; 282 // See if we can figure out the language from the frame, otherwise use the default language: 283 CompileUnit *comp_unit = m_address.CalculateSymbolContextCompileUnit(); 284 if (comp_unit) 285 language = comp_unit->GetLanguage(); 286 287 m_user_expression_sp.reset(GetTarget().GetUserExpressionForLanguage(condition_text, 288 nullptr, 289 language, 290 Expression::eResultTypeAny, 291 EvaluateExpressionOptions(), 292 error)); 293 if (error.Fail()) 294 { 295 if (log) 296 log->Printf("Error getting condition expression: %s.", error.AsCString()); 297 m_user_expression_sp.reset(); 298 return true; 299 } 300 301 if (!m_user_expression_sp->Parse(diagnostics, exe_ctx, eExecutionPolicyOnlyWhenNeeded, true, false)) 302 { 303 error.SetErrorStringWithFormat("Couldn't parse conditional expression:\n%s", 304 diagnostics.GetString().c_str()); 305 m_user_expression_sp.reset(); 306 return true; 307 } 308 309 m_condition_hash = condition_hash; 310 } 311 312 // We need to make sure the user sees any parse errors in their condition, so we'll hook the 313 // constructor errors up to the debugger's Async I/O. 314 315 ValueObjectSP result_value_sp; 316 317 EvaluateExpressionOptions options; 318 options.SetUnwindOnError(true); 319 options.SetIgnoreBreakpoints(true); 320 options.SetTryAllThreads(true); 321 options.SetResultIsInternal(true); // Don't generate a user variable for condition expressions. 322 323 Error expr_error; 324 325 diagnostics.Clear(); 326 327 ExpressionVariableSP result_variable_sp; 328 329 ExpressionResults result_code = 330 m_user_expression_sp->Execute(diagnostics, exe_ctx, options, m_user_expression_sp, result_variable_sp); 331 332 bool ret; 333 334 if (result_code == eExpressionCompleted) 335 { 336 if (!result_variable_sp) 337 { 338 error.SetErrorString("Expression did not return a result"); 339 return false; 340 } 341 342 result_value_sp = result_variable_sp->GetValueObject(); 343 344 if (result_value_sp) 345 { 346 ret = result_value_sp->IsLogicalTrue(error); 347 if (log) 348 { 349 if (error.Success()) 350 { 351 log->Printf("Condition successfully evaluated, result is %s.\n", 352 ret ? "true" : "false"); 353 } 354 else 355 { 356 error.SetErrorString("Failed to get an integer result from the expression"); 357 ret = false; 358 } 359 360 } 361 } 362 else 363 { 364 ret = false; 365 error.SetErrorString("Failed to get any result from the expression"); 366 } 367 } 368 else 369 { 370 ret = false; 371 error.SetErrorStringWithFormat("Couldn't execute expression:\n%s", diagnostics.GetString().c_str()); 372 } 373 374 return ret; 375 } 376 377 uint32_t 378 BreakpointLocation::GetIgnoreCount () 379 { 380 return GetOptionsNoCreate()->GetIgnoreCount(); 381 } 382 383 void 384 BreakpointLocation::SetIgnoreCount (uint32_t n) 385 { 386 GetLocationOptions()->SetIgnoreCount(n); 387 SendBreakpointLocationChangedEvent (eBreakpointEventTypeIgnoreChanged); 388 } 389 390 void 391 BreakpointLocation::DecrementIgnoreCount() 392 { 393 if (m_options_ap.get() != nullptr) 394 { 395 uint32_t loc_ignore = m_options_ap->GetIgnoreCount(); 396 if (loc_ignore != 0) 397 m_options_ap->SetIgnoreCount(loc_ignore - 1); 398 } 399 } 400 401 bool 402 BreakpointLocation::IgnoreCountShouldStop() 403 { 404 if (m_options_ap.get() != nullptr) 405 { 406 uint32_t loc_ignore = m_options_ap->GetIgnoreCount(); 407 if (loc_ignore != 0) 408 { 409 m_owner.DecrementIgnoreCount(); 410 DecrementIgnoreCount(); // Have to decrement our owners' ignore count, since it won't get a 411 // chance to. 412 return false; 413 } 414 } 415 return true; 416 } 417 418 const BreakpointOptions * 419 BreakpointLocation::GetOptionsNoCreate () const 420 { 421 if (m_options_ap.get() != nullptr) 422 return m_options_ap.get(); 423 else 424 return m_owner.GetOptions (); 425 } 426 427 BreakpointOptions * 428 BreakpointLocation::GetLocationOptions () 429 { 430 // If we make the copy we don't copy the callbacks because that is potentially 431 // expensive and we don't want to do that for the simple case where someone is 432 // just disabling the location. 433 if (m_options_ap.get() == nullptr) 434 m_options_ap.reset(BreakpointOptions::CopyOptionsNoCallback(*m_owner.GetOptions ())); 435 436 return m_options_ap.get(); 437 } 438 439 bool 440 BreakpointLocation::ValidForThisThread (Thread *thread) 441 { 442 return thread->MatchesSpec(GetOptionsNoCreate()->GetThreadSpecNoCreate()); 443 } 444 445 // RETURNS - true if we should stop at this breakpoint, false if we 446 // should continue. Note, we don't check the thread spec for the breakpoint 447 // here, since if the breakpoint is not for this thread, then the event won't 448 // even get reported, so the check is redundant. 449 450 bool 451 BreakpointLocation::ShouldStop (StoppointCallbackContext *context) 452 { 453 bool should_stop = true; 454 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS); 455 456 // Do this first, if a location is disabled, it shouldn't increment its hit count. 457 if (!IsEnabled()) 458 return false; 459 460 if (!IgnoreCountShouldStop()) 461 return false; 462 463 if (!m_owner.IgnoreCountShouldStop()) 464 return false; 465 466 // We only run synchronous callbacks in ShouldStop: 467 context->is_synchronous = true; 468 should_stop = InvokeCallback (context); 469 470 if (log) 471 { 472 StreamString s; 473 GetDescription (&s, lldb::eDescriptionLevelVerbose); 474 log->Printf ("Hit breakpoint location: %s, %s.\n", s.GetData(), should_stop ? "stopping" : "continuing"); 475 } 476 477 return should_stop; 478 } 479 480 void 481 BreakpointLocation::BumpHitCount() 482 { 483 if (IsEnabled()) 484 { 485 // Step our hit count, and also step the hit count of the owner. 486 IncrementHitCount(); 487 m_owner.IncrementHitCount(); 488 } 489 } 490 491 void 492 BreakpointLocation::UndoBumpHitCount() 493 { 494 if (IsEnabled()) 495 { 496 // Step our hit count, and also step the hit count of the owner. 497 DecrementHitCount(); 498 m_owner.DecrementHitCount(); 499 } 500 } 501 502 bool 503 BreakpointLocation::IsResolved () const 504 { 505 return m_bp_site_sp.get() != nullptr; 506 } 507 508 lldb::BreakpointSiteSP 509 BreakpointLocation::GetBreakpointSite() const 510 { 511 return m_bp_site_sp; 512 } 513 514 bool 515 BreakpointLocation::ResolveBreakpointSite () 516 { 517 if (m_bp_site_sp) 518 return true; 519 520 Process *process = m_owner.GetTarget().GetProcessSP().get(); 521 if (process == nullptr) 522 return false; 523 524 lldb::break_id_t new_id = process->CreateBreakpointSite (shared_from_this(), m_owner.IsHardware()); 525 526 if (new_id == LLDB_INVALID_BREAK_ID) 527 { 528 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS); 529 if (log) 530 log->Warning ("Tried to add breakpoint site at 0x%" PRIx64 " but it was already present.\n", 531 m_address.GetOpcodeLoadAddress (&m_owner.GetTarget())); 532 return false; 533 } 534 535 return true; 536 } 537 538 bool 539 BreakpointLocation::SetBreakpointSite (BreakpointSiteSP& bp_site_sp) 540 { 541 m_bp_site_sp = bp_site_sp; 542 SendBreakpointLocationChangedEvent (eBreakpointEventTypeLocationsResolved); 543 return true; 544 } 545 546 bool 547 BreakpointLocation::ClearBreakpointSite () 548 { 549 if (m_bp_site_sp.get()) 550 { 551 ProcessSP process_sp(m_owner.GetTarget().GetProcessSP()); 552 // If the process exists, get it to remove the owner, it will remove the physical implementation 553 // of the breakpoint as well if there are no more owners. Otherwise just remove this owner. 554 if (process_sp) 555 process_sp->RemoveOwnerFromBreakpointSite (GetBreakpoint().GetID(), 556 GetID(), m_bp_site_sp); 557 else 558 m_bp_site_sp->RemoveOwner(GetBreakpoint().GetID(), GetID()); 559 560 m_bp_site_sp.reset(); 561 return true; 562 } 563 return false; 564 } 565 566 void 567 BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level) 568 { 569 SymbolContext sc; 570 571 // If the description level is "initial" then the breakpoint is printing out our initial state, 572 // and we should let it decide how it wants to print our label. 573 if (level != eDescriptionLevelInitial) 574 { 575 s->Indent(); 576 BreakpointID::GetCanonicalReference(s, m_owner.GetID(), GetID()); 577 } 578 579 if (level == lldb::eDescriptionLevelBrief) 580 return; 581 582 if (level != eDescriptionLevelInitial) 583 s->PutCString(": "); 584 585 if (level == lldb::eDescriptionLevelVerbose) 586 s->IndentMore(); 587 588 if (m_address.IsSectionOffset()) 589 { 590 m_address.CalculateSymbolContext(&sc); 591 592 if (level == lldb::eDescriptionLevelFull || level == eDescriptionLevelInitial) 593 { 594 if (IsReExported()) 595 s->PutCString ("re-exported target = "); 596 else 597 s->PutCString("where = "); 598 sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false, true, true); 599 } 600 else 601 { 602 if (sc.module_sp) 603 { 604 s->EOL(); 605 s->Indent("module = "); 606 sc.module_sp->GetFileSpec().Dump (s); 607 } 608 609 if (sc.comp_unit != nullptr) 610 { 611 s->EOL(); 612 s->Indent("compile unit = "); 613 static_cast<FileSpec*>(sc.comp_unit)->GetFilename().Dump (s); 614 615 if (sc.function != nullptr) 616 { 617 s->EOL(); 618 s->Indent("function = "); 619 s->PutCString (sc.function->GetName().AsCString("<unknown>")); 620 } 621 622 if (sc.line_entry.line > 0) 623 { 624 s->EOL(); 625 s->Indent("location = "); 626 sc.line_entry.DumpStopContext (s, true); 627 } 628 629 } 630 else 631 { 632 // If we don't have a comp unit, see if we have a symbol we can print. 633 if (sc.symbol) 634 { 635 s->EOL(); 636 if (IsReExported()) 637 s->Indent ("re-exported target = "); 638 else 639 s->Indent("symbol = "); 640 s->PutCString(sc.symbol->GetName().AsCString("<unknown>")); 641 } 642 } 643 } 644 } 645 646 if (level == lldb::eDescriptionLevelVerbose) 647 { 648 s->EOL(); 649 s->Indent(); 650 } 651 652 if (m_address.IsSectionOffset() && (level == eDescriptionLevelFull || level == eDescriptionLevelInitial)) 653 s->Printf (", "); 654 s->Printf ("address = "); 655 656 ExecutionContextScope *exe_scope = nullptr; 657 Target *target = &m_owner.GetTarget(); 658 if (target) 659 exe_scope = target->GetProcessSP().get(); 660 if (exe_scope == nullptr) 661 exe_scope = target; 662 663 if (level == eDescriptionLevelInitial) 664 m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress); 665 else 666 m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress); 667 668 if (IsIndirect() && m_bp_site_sp) 669 { 670 Address resolved_address; 671 resolved_address.SetLoadAddress(m_bp_site_sp->GetLoadAddress(), target); 672 Symbol *resolved_symbol = resolved_address.CalculateSymbolContextSymbol(); 673 if (resolved_symbol) 674 { 675 if (level == eDescriptionLevelFull || level == eDescriptionLevelInitial) 676 s->Printf (", "); 677 else if (level == lldb::eDescriptionLevelVerbose) 678 { 679 s->EOL(); 680 s->Indent(); 681 } 682 s->Printf ("indirect target = %s", resolved_symbol->GetName().GetCString()); 683 } 684 } 685 686 if (level == lldb::eDescriptionLevelVerbose) 687 { 688 s->EOL(); 689 s->Indent(); 690 s->Printf("resolved = %s\n", IsResolved() ? "true" : "false"); 691 692 s->Indent(); 693 s->Printf ("hit count = %-4u\n", GetHitCount()); 694 695 if (m_options_ap.get()) 696 { 697 s->Indent(); 698 m_options_ap->GetDescription (s, level); 699 s->EOL(); 700 } 701 s->IndentLess(); 702 } 703 else if (level != eDescriptionLevelInitial) 704 { 705 s->Printf(", %sresolved, hit count = %u ", 706 (IsResolved() ? "" : "un"), 707 GetHitCount()); 708 if (m_options_ap.get()) 709 { 710 m_options_ap->GetDescription (s, level); 711 } 712 } 713 } 714 715 void 716 BreakpointLocation::Dump(Stream *s) const 717 { 718 if (s == nullptr) 719 return; 720 721 s->Printf("BreakpointLocation %u: tid = %4.4" PRIx64 " load addr = 0x%8.8" PRIx64 " state = %s type = %s breakpoint " 722 "hw_index = %i hit_count = %-4u ignore_count = %-4u", 723 GetID(), 724 GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetTID(), 725 (uint64_t) m_address.GetOpcodeLoadAddress (&m_owner.GetTarget()), 726 (m_options_ap.get() ? m_options_ap->IsEnabled() : m_owner.IsEnabled()) ? "enabled " : "disabled", 727 IsHardware() ? "hardware" : "software", 728 GetHardwareIndex(), 729 GetHitCount(), 730 GetOptionsNoCreate()->GetIgnoreCount()); 731 } 732 733 void 734 BreakpointLocation::SendBreakpointLocationChangedEvent (lldb::BreakpointEventType eventKind) 735 { 736 if (!m_being_created 737 && !m_owner.IsInternal() 738 && m_owner.GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged)) 739 { 740 Breakpoint::BreakpointEventData *data = new Breakpoint::BreakpointEventData (eventKind, 741 m_owner.shared_from_this()); 742 data->GetBreakpointLocationCollection().Add (shared_from_this()); 743 m_owner.GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged, data); 744 } 745 } 746 747 void 748 BreakpointLocation::SwapLocation (BreakpointLocationSP swap_from) 749 { 750 m_address = swap_from->m_address; 751 m_should_resolve_indirect_functions = swap_from->m_should_resolve_indirect_functions; 752 m_is_reexported = swap_from->m_is_reexported; 753 m_is_indirect = swap_from->m_is_indirect; 754 m_user_expression_sp.reset(); 755 } 756